java根据图片中绿色像素点的多少进行排序
前言
一个朋友被绿了,看见绿色就会很伤感,作为好兄弟的我当然看不下去,感觉有我必要也必须做一点什么。正好我又在写java程序,那就写一个小程序帮他把电脑里的图片排一下顺序,根据绿色的程度进行排序,最后把排好序的图片偷偷的放到他的电脑里去。为了好兄弟做这么多的事情,正所谓:事了拂衣去,功藏身与名啊!(当然是倒序排的)
一、利用for循环读取图片
相信学过图像处理的小伙伴都知道,一张图片由很多像素组成(当然,矢量图片除外,大家下来可以了解为啥矢量图片不是由像素点组成的)。因此,不管是什么图片我们都看作是一个平面,因为就可以用坐标的方式去读取图片啦!那就废话不多说直接开始!
二、代码的逻辑
1.先给大家看看主方法里面都有一些什么内容
publicstaticvoidmain(String[]args){
HashMapimageMap=newHashMap();//用hashMap将文件和对应的像素点数量装到一起
FilefileDir=newFile("D:\\Download\\TestFile");//将要进行排序的文件目录
File[]listFiles=fileDir.listFiles();
for(FilereadFile:listFiles){
getImagePixel(readFile,imageMap);//获取图片的绿色像素点数量的多少
}
HashMapSortUtilshashMapSortUtils=newHashMapSortUtils(imageMap,1,3,"Mus");
LinkedHashMapsortFileMap=hashMapSortUtils.sortFileMap();//将图片按照像素点的数量进行排序
hashMapSortUtils.renameFiles(sortFileMap);//将排好序的文件重命名(不然离开控制台就看不到文件的排序了>o<)
System.out.println(imageMap);//这里只是用来看具体像素点有多少的,并没有实际的意义
}
是不是很简单呢?跟大象装冰箱一样,只有三个步骤:
1.将文件目录下的所有图片含有的绿色像素点全部读取出来,然后将对应的文件名和像素点个数暂存在HashMap里;
2.将图片根据绿色像素点的多少进行排序;
3.将排好序的图片重命名,然后进行排序输出(Tips:文件会进行重命名的,所有不要直接在源文件上直接玩喔,注意文件的备份);
好了,那我们就直接开始看每个方法具体是怎样实现的吧,按顺序进行讲解!(以下大家就注意看代码中的注释了,不再做重复的解释了)
2.读取图片像素点的方法
privatestaticHashMapgetImagePixel(FilereadFile,HashMap imageMap){ intred=0;//记录像素点的红色 intgreen=0;//记录像素点的绿色 intblue=0;//记录像素点的蓝色 intcounter=0;//程序计数器 BufferedImagebi=null; try{ bi=ImageIO.read(readFile);//通过ImageIO来读取图片,以便获取图片的RGB信息 }catch(IOExceptione){ e.printStackTrace(); } intwidth=bi.getWidth();//获取图片的宽度 intheight=bi.getHeight();//获取图片的高度 intminx=bi.getMinX();//获取图片的坐标起点x轴 intminy=bi.getMinY();//获取图片的坐标起点y轴 for(inti=minx;i >16;//过滤掉图片的绿色和蓝色 green=(pixel&0xff00)>>8;//过滤掉图片的绿色 blue=(pixel&0xff);//最后剩下的就是蓝色啦 if(green-red>30&&green-blue>30){//绿色的范围 counter++; } } } imageMap.put(readFile,counter);//将文件和像素点的个数记录到HashMap中 returnimageMap; }
3.将图片按照像素点的数量进行排序
由于排序不光在这里可以使用,在其他情况下也可能会使用到(比如说根据文件的创建时间进行排序,都可以用到排序的)。所以我将排序写成了一个抽象类,其他情况下只需要继承这个抽象类,然后具体实现自己想要实现的方法就行了!具体的现如下:
抽象类:
packagereadcolor;
importjava.io.File;
importjava.util.HashMap;
importjava.util.LinkedHashMap;
publicabstractclassHashMapSortUtil{
privateHashMapsortMap;//全局变量Map,就是主方法需要传过来进行排序的Map
privateStringprefix;//前缀,用来命名自己的文件==>Mus
publicabstractLinkedHashMapsortFileMap();//进行排序的方法
publicabstractvoidrenameFiles(LinkedHashMaplinkedTimeMap);//重命名的方法
publicHashMapgetSortMap(){
returnsortMap;
}
publicvoidsetSortMap(HashMapsortMap){
this.sortMap=sortMap;
}
publicStringgetPrefix(){
returnprefix;
}
publicvoidsetPrefix(Stringprefix){
this.prefix=prefix;
}
}
子类:
packagereadcolor;
importjava.io.File;
importjava.util.Collections;
importjava.util.Comparator;
importjava.util.HashMap;
importjava.util.LinkedHashMap;
importjava.util.LinkedList;
importjava.util.Map.Entry;
importjava.util.Set;
publicclassHashMapSortUtilsextendsHashMapSortUtil{
privateintcounter;//计数器,默认从多少开始进行命名==>1
privateintnameLength;//命名的长度,其实就是计数器之前需要添加几个0==>3
privateintnameExpansion=0;//记录名字超长了需要进行扩容的次数
//prefix(在父类里面),counter,nameLength组成的结果就是对应的Mus001
privateHashMaptempFileMap=newHashMap();//记录在进行重命名时,目标文件有重复时,将源文件拷贝出来与将要命名的名字记录到HashMap里面
publicHashMapSortUtils(){//构造方法
super();
}
publicHashMapSortUtils(HashMapsortMap,Integercounter,IntegernameLength,Stringprefix){//构造方法
super();
super.setSortMap(sortMap);
super.setPrefix(prefix);
this.counter=counter;
this.nameLength=nameLength;
}
/**
*将图片按照像素点个数进行排序的方法
*参数:无
*返回值:无
**/
@Override
publicLinkedHashMapsortFileMap(){
LinkedHashMaplinkedHashMap=newLinkedHashMap();
Set>mapEntries=super.getSortMap().entrySet();//将传进来需要进行排序的HashMap获取到每个节点
LinkedList>timeList=newLinkedList>(mapEntries);//将每个节点放到List集合中,方便利用Collections的方法进行排序
Collections.sort(timeList,newComparator>(){//利用Comparator接口进行排序
@Override
publicintcompare(Entryo1,Entryo2){
if(o1.getValue()==o2.getValue()){//如果两个文件的绿色像素点相同,就用文件的名字进行比较
returno2.getKey().compareTo(o1.getKey());
}
return((Integer)o2.getValue()).compareTo((Integer)o1.getValue());//利用文件的绿色像素点进行比较
}
});
for(Entryentry:timeList){//将排好序之后的文件放到LinkedHashMap中,因为如果方法HashMap中的话,你会发现它的顺序又是乱的了-o-
linkedHashMap.put(entry.getKey(),entry.getValue());
}
returnlinkedHashMap;
}
/**
*重命名文件的方法
*参数:linkedTimeMap:需要进行文件重命名的HashMap
*返回值:无
**/
@Override
publicvoidrenameFiles(LinkedHashMaplinkedTimeMap){
Set>entrySet=linkedTimeMap.entrySet();
for(Entryentry:entrySet){
renameFile(entry.getKey(),createFileName(entry.getKey())/*根据之前设置文件的名字(counter、nameLength、prefix)生成文件名*/);//重命名文件
}
//最后重命名剩下的源文件的备份文件
renameTempFiles();
}
/**
*根据之前设置文件的名字(counter、nameLength、prefix)生成文件名
*参数:oldFile:源文件
*返回值:生成名字之后的文件
**/
privateFilecreateFileName(FileoldFile){
//通过父类获取到prefix
Stringprefix=super.getPrefix();
//获取结束
StringnewFileName="";
newFileName+=prefix;//先将前缀拼接上
intnameLen=String.valueOf(counter).length();//获取计数器的长度
if(nameLen>nameLength){//如果计数器超长了,那么命名的长度(nameLength)就需要进行扩容,不然会出现文件名重复的情况
nameLength++;
nameExpansion++;//这里记录是因为,当后面的操作出现错误时,这里可能需要将原来的长度进行恢复
}
if(nameLen<=nameLength){
intd_Value=String.valueOf(Math.pow(10,nameLength)-1).length()-String.valueOf(counter).length()-2;//计算需要填补的0的个数,这里减2是因为去除double数据后面的.0
for(inti=0;i"+newFile.getAbsolutePath());
return;
}
}
//重命名失败就将计数器减一,并且将命名的长度还原到原来的长度
System.out.println("====================================重命名失败:"+oldFile.getAbsolutePath()+"====================================");
counter--;
nameLength-=nameExpansion;
}
/**
*重命名剩下的源文件的备份文件
*参数:无
*返回值:无
**/
privatevoidrenameTempFiles(){
Set>entrySet=tempFileMap.entrySet();
for(Entryentry:entrySet){
//调用重命名的方法进行重命名
renameFile(entry.getKey(),entry.getValue());
}
}
publicintgetCounter(){
returncounter;
}
publicvoidsetCounter(intcounter){
this.counter=counter;
}
publicintgetNameLength(){
returnnameLength;
}
publicvoidsetNameLength(intnameLength){
this.nameLength=nameLength;
}
}
由于counter(计数器)和nameLength(命名的长度)在进行排序和文件重命名的时候会频繁的使用到,因此我把他们放到了子类里面,避免多次调用父类的getter和setter方法。虽然我代码里面注释写得很清楚,但是还是有一些小伙伴不习惯看注释,那我稍微做一下解释,但是代码的逻辑还是要大家下来看一下!如果在博客上不太方便的话,可以直接copy到eclipse里面或者idea里面进行逻辑的分析!
(1)在主方法或其他方法需要调用到这个类型,可以直接利用该类的构造方法来调用到这个类:
publicHashMapSortUtils(HashMapsortMap,Integercounter,IntegernameLength,Stringprefix){ ...... }
这个构造方法会将需要进行排序和重命名的HashMap加载到该类的成员变量中,该类所有方法都可以调用该HashMap,并且计数器开始的位置(counter)、命名的长度(nameLength)、命名前缀(prefix)都加载到成员变量中,其中HashMap和前缀属于父类的变量。(相信大多数人都知道,我就乱解释一番了。。。)
(2)将传进来的HashMap进行排序的方法:
publicLinkedHashMapsortFileMap(){ ...... }
该方法就是利用java工具类Collections下面的sort方法进行排序,需要注意的是,最后之所以返回的是一个LinkedHashMap是因为HashMap是无序的,如果排完序还是用HashMap装排序的结果,那么就有可能没有达到排序预期的效果
(3)将排好序的HashMap中的文件重命名的方法:
publicvoidrenameFiles(LinkedHashMaplinkedTimeMap){ ...... }
该方法主要分为两个步骤:a.利用createFileName方法将之前设置好的prefix(前缀)、nameLength(命名的长度)、counter(计数器)组成新的名字;b.将HashMap中所有的entry节点利用renameFile方法进行判断是否可以直接重命名,如果可以直接重命名就直接重命名,如果需要重新命名的文件已经存在就将源文件copy一份出来,然后将拷贝文件和新的名字方法一个HashMap中,等到程序的第c步才执行这部分文件的重命名!c.将之前未进行重命名的源文件进利用renameTempFiles方法行统一的重命名!
4.文件操作的工具类
文件操作是一个公共的类,进行文件的复制、删除、获取所有文件、创建文件夹等等,都可以写做一个公共的方法,大家可以自行去了解这个类的作用,这里不再过多的赘述(嘻嘻,又可以偷波懒了),不过我这里是错误的示范,我用接口的方式来实现的,真正的生产中是不会这样做的,因为文件操作是基本上不会变的,这里我只是想单纯的联系一下接口的操做,那么废话不多说,直接上代码,都是文件操作的基础代码:
文件操作的接口:
packagereadcolor;
importjava.io.File;
importjava.util.List;
publicinterfaceFileService{
voidcopyFile(StringsourcePath,StringtargetPath)throwsException;
voidcopyFile(FilesourceFile,FiletargetFile)throwsException;
voidmkDirs(Stringpath)throwsException;
ListgetAllFiles(StringsourcePath);
voidremoveFiles(Stringpath);
voidremoveFiles(FilesourceFile);
}
文件操作的实现类:
packagereadcolor;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.FileOutputStream;
importjava.util.ArrayList;
importjava.util.List;
publicclassFileServiceImplimplementsFileService{
@Override
publicvoidcopyFile(StringsourcePath,StringtargetPath)throwsException{
copyFile(newFile(sourcePath),newFile(targetPath));
}
@Override
publicvoidcopyFile(FilesourceFile,FiletargetFile)throwsException{
FileInputStreamfis=newFileInputStream(sourceFile);
FileOutputStreamfos=newFileOutputStream(targetFile);
byte[]buffer=newbyte[1024];
intlen=0;
while((len=fis.read(buffer))!=-1){
fos.write(buffer,0,len);
fos.flush();
}
fos.close();
fis.close();
}
@Override
publicvoidmkDirs(Stringpath)throwsException{
FiledestFile=newFile(path);
if(!destFile.exists()){
destFile.mkdirs();
}
}
@Override
publicListgetAllFiles(StringsourcePath){
ArrayListfiles=newArrayList();
Filefile=newFile(sourcePath);
if(file.exists()&&!file.isHidden()){
if(file.isFile()){
files.add(file);
}
if(file.isDirectory()){
File[]fs=file.listFiles();
for(Filef:fs){
if(!f.isHidden()){
if(f.isFile()){
files.add(file);
}
if(f.isDirectory()){
files.addAll(getAllFiles(sourcePath+File.separator+f.getName()));
}
}
}
}
}
returnfiles;
}
@Override
publicvoidremoveFiles(Stringpath){
removeFiles(newFile(path));
}
@Override
publicvoidremoveFiles(FilesourceFile){
if(!sourceFile.isDirectory()){
if(sourceFile.delete())System.out.println("删除文件:"+sourceFile.getAbsolutePath()+"成功");
}else{
File[]files=sourceFile.listFiles();
for(Filefile:files){
if(file.isDirectory()){
removeFiles(file);
if(file.delete())System.out.println("删除文件夹:"+file.getAbsolutePath()+"成功");
}else{
if(file.delete())System.out.println("删除文件:"+file.getAbsolutePath()+"成功");
}
}
}
}
}
好的,一切准备就绪,那我们直接开始运行代码,看看效果如何:
先准备好图片:
是不是感觉前面的图片要稍微绿一点呢?该程序可以进行重复执行的,暂时没有出现命名失败的情况,如果有小伙伴试了然后报错了,记得留言喔,我看看是啥问题,然后看看能不能再优化一下。。。(闻到了头发掉落的气息)
总结
最后,我们可以稍微改动几行代码,然后将所有的图片只输出绿色像素点来做一个直观的感受:
packagereadcolor;
importjava.awt.image.BufferedImage;
importjava.io.File;
importjava.io.FileNotFoundException;
importjava.io.IOException;
importjava.util.HashMap;
importjava.util.LinkedHashMap;
importjavax.imageio.ImageIO;
publicclassReadColor{
privatestaticintcount=0;
publicstaticvoidmain(String[]args){
HashMapimageMap=newHashMap();//用hashMap将文件和对应的像素点数量装到一起
FilefileDir=newFile("D:\\Download\\TestFile");//将要进行排序的文件目录
File[]listFiles=fileDir.listFiles();
for(FilereadFile:listFiles){
getImagePixel(readFile,imageMap);//获取图片的绿色像素点数量的多少
}
HashMapSortUtilshashMapSortUtils=newHashMapSortUtils(imageMap,1,3,"Mus");
LinkedHashMapsortFileMap=hashMapSortUtils.sortFileMap();//将图片按照像素点的数量进行排序
hashMapSortUtils.renameFiles(sortFileMap);//将排好序的文件重命名(不然离开控制台就看不到文件的排序了>o<)
System.out.println(imageMap);
}
privatestaticHashMapgetImagePixel(FilereadFile,HashMapimageMap){
intred=0;//记录像素点的红色
intgreen=0;//记录像素点的绿色
intblue=0;//记录像素点的蓝色
intcounter=0;//程序计数器
BufferedImagebi=null;
try{
bi=ImageIO.read(readFile);//通过ImageIO来读取图片,以便获取图片的RGB信息
}catch(IOExceptione){
e.printStackTrace();
}
intwidth=bi.getWidth();//获取图片的宽度
intheight=bi.getHeight();//获取图片的高度
intminx=bi.getMinX();//获取图片的坐标起点x轴
intminy=bi.getMinY();//获取图片的坐标起点y轴
for(inti=minx;i>16;//过滤掉图片的绿色和蓝色
green=(pixel&0xff00)>>8;//过滤掉图片的绿色
blue=(pixel&0xff);//最后剩下的就是蓝色啦
if(green-red>30&&green-blue>30){//绿色的范围
counter++;
}else{
bi.setRGB(i,j,0xffffff);
}
}
}
imageMap.put(readFile,counter);//将文件和像素点的个数记录到HashMap中
try{
ImageIO.write(bi,"jpg",newFile("D:\\Download\\TestFile1\\"+count+".jpg"));
}catch(FileNotFoundExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}
count++;
returnimageMap;
}
}
是不是只提取出了绿色像素点呢,大家在这个的基础上就可以选择自己喜欢的颜色进行排序了。反正我把这个程序送给我朋友的时候,遭到了他半个小时的感谢(问候),大家只是自己可以玩一玩,千万别去乱动别人的硬盘喔!(最后的最后,程序并没有什么实际的使用价值,只是学习了一些新的方法或者技巧,实际上我进行图像处理的时候都是直接选用photoshop进行操作的,哈哈啊哈哈!)
到此这篇关于java根据图片中绿色像素点的多少进行排序的文章就介绍到这了,更多相关java绿色像素点排序内容请搜索毛票票以前的文章或继续浏览下面的相关文章希望大家以后多多支持毛票票!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。