您好,登錄后才能下訂單哦!
本篇文章為大家展示了利用java怎么根據圖片中綠色像素的多少進行排序,內容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細介紹希望你能有所收獲。
Java是一門面向對象編程語言,可以編寫桌面應用程序、Web應用程序、分布式系統和嵌入式系統應用程序。
public static void main(String[] args) { HashMap<File, Object> imageMap = new HashMap<File, Object>();//用hashMap將文件和對應的像素點數量裝到一起 File fileDir = new File("D:\\Download\\TestFile");//將要進行排序的文件目錄 File[] listFiles = fileDir.listFiles(); for (File readFile : listFiles) { getImagePixel(readFile, imageMap);//獲取圖片的綠色像素點數量的多少 } HashMapSortUtils hashMapSortUtils = new HashMapSortUtils(imageMap, 1, 3, "Mus"); LinkedHashMap<File,Object> sortFileMap = hashMapSortUtils.sortFileMap();//將圖片按照像素點的數量進行排序 hashMapSortUtils.renameFiles(sortFileMap);//將排好序的文件重命名(不然離開控制臺就看不到文件的排序了>o<) System.out.println(imageMap);//這里只是用來看具體像素點有多少的,并沒有實際的意義 }
是不是很簡單呢?跟大象裝冰箱一樣,只有三個步驟:
1.將文件目錄下的所有圖片含有的綠色像素點全部讀取出來,然后將對應的文件名和像素點個數暫存在HashMap里;
2.將圖片根據綠色像素點的多少進行排序;
3.將排好序的圖片重命名,然后進行排序輸出(Tips:文件會進行重命名的,所有不要直接在源文件上直接玩喔,注意文件的備份);
好了,那我們就直接開始看每個方法具體是怎樣實現的吧,按順序進行講解!(以下大家就注意看代碼中的注釋了,不再做重復的解釋了)
private static HashMap<File, Object> getImagePixel(File readFile, HashMap<File, Object> imageMap) { int red = 0;//記錄像素點的紅色 int green = 0;//記錄像素點的綠色 int blue = 0;//記錄像素點的藍色 int counter = 0;//程序計數器 BufferedImage bi = null; try { bi = ImageIO.read(readFile);//通過ImageIO來讀取圖片,以便獲取圖片的RGB信息 } catch (IOException e) { e.printStackTrace(); } int width = bi.getWidth();//獲取圖片的寬度 int height = bi.getHeight();//獲取圖片的高度 int minx = bi.getMinX();//獲取圖片的坐標起點x軸 int miny = bi.getMinY();//獲取圖片的坐標起點y軸 for(int i = minx; i < width; i++){ for(int j = miny; j < height; j++){ int pixel = bi.getRGB(i, j); red = (pixel & 0xff0000) >> 16;//過濾掉圖片的綠色和藍色 green = (pixel & 0xff00) >> 8;//過濾掉圖片的綠色 blue = (pixel & 0xff);//最后剩下的就是藍色啦 if(green - red > 30 && green - blue > 30){//綠色的范圍 counter++; } } } imageMap.put(readFile, counter);//將文件和像素點的個數記錄到HashMap中 return imageMap; }
由于排序不光在這里可以使用,在其他情況下也可能會使用到(比如說根據文件的創建時間進行排序,都可以用到排序的)。所以我將排序寫成了一個抽象類,其他情況下只需要繼承這個抽象類,然后具體實現自己想要實現的方法就行了!具體的現如下:
抽象類:
package readcolor; import java.io.File; import java.util.HashMap; import java.util.LinkedHashMap; public abstract class HashMapSortUtil { private HashMap<File, Object> sortMap;//全局變量Map,就是主方法需要傳過來進行排序的Map private String prefix;//前綴,用來命名自己的文件 ==> Mus public abstract LinkedHashMap<File, Object> sortFileMap();//進行排序的方法 public abstract void renameFiles(LinkedHashMap<File, Object> linkedTimeMap);//重命名的方法 public HashMap<File, Object> getSortMap() { return sortMap; } public void setSortMap(HashMap<File, Object> sortMap) { this.sortMap = sortMap; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } }
子類:
package readcolor; import java.io.File; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.Map.Entry; import java.util.Set; public class HashMapSortUtils extends HashMapSortUtil{ private int counter;//計數器,默認從多少開始進行命名 ==> 1 private int nameLength;//命名的長度,其實就是計數器之前需要添加幾個0 ==> 3 private int nameExpansion = 0;//記錄名字超長了需要進行擴容的次數 //prefix(在父類里面),counter,nameLength組成的結果就是對應的Mus001 private HashMap<File, File> tempFileMap = new HashMap<File, File>();//記錄在進行重命名時,目標文件有重復時,將源文件拷貝出來與將要命名的名字記錄到HashMap里面 public HashMapSortUtils() {//構造方法 super(); } public HashMapSortUtils(HashMap<File, Object> sortMap, Integer counter, Integer nameLength, String prefix) {//構造方法 super(); super.setSortMap(sortMap); super.setPrefix(prefix); this.counter = counter; this.nameLength = nameLength; } /** * 將圖片按照像素點個數進行排序的方法 * 參數:無 * 返回值:無 * */ @Override public LinkedHashMap<File, Object> sortFileMap() { LinkedHashMap<File,Object> linkedHashMap = new LinkedHashMap<File, Object>(); Set<Entry<File, Object>> mapEntries = super.getSortMap().entrySet();//將傳進來需要進行排序的HashMap獲取到每個節點 LinkedList<Entry<File, Object>> timeList = new LinkedList<Entry<File, Object>>(mapEntries);//將每個節點放到List集合中,方便利用Collections的方法進行排序 Collections.sort(timeList, new Comparator<Entry<File, Object>>() {//利用Comparator接口進行排序 @Override public int compare(Entry<File, Object> o1, Entry<File, Object> o2) { if(o1.getValue() == o2.getValue()){//如果兩個文件的綠色像素點相同,就用文件的名字進行比較 return o2.getKey().compareTo(o1.getKey()); } return ((Integer) o2.getValue()).compareTo((Integer)o1.getValue());//利用文件的綠色像素點進行比較 } }); for (Entry<File, Object> entry : timeList) {//將排好序之后的文件放到LinkedHashMap中,因為如果方法HashMap中的話,你會發現它的順序又是亂的了-o- linkedHashMap.put(entry.getKey(), entry.getValue()); } return linkedHashMap; } /** * 重命名文件的方法 * 參數:linkedTimeMap:需要進行文件重命名的HashMap * 返回值:無 * */ @Override public void renameFiles(LinkedHashMap<File, Object> linkedTimeMap) { Set<Entry<File,Object>> entrySet = linkedTimeMap.entrySet(); for (Entry<File, Object> entry : entrySet) { renameFile(entry.getKey(), createFileName(entry.getKey())/*根據之前設置文件的名字(counter、nameLength、prefix)生成文件名*/);//重命名文件 } //最后重命名剩下的源文件的備份文件 renameTempFiles(); } /** * 根據之前設置文件的名字(counter、nameLength、prefix)生成文件名 * 參數:oldFile:源文件 * 返回值:生成名字之后的文件 * */ private File createFileName(File oldFile) { //通過父類獲取到prefix String prefix = super.getPrefix(); //獲取結束 String newFileName = ""; newFileName += prefix;//先將前綴拼接上 int nameLen = String.valueOf(counter).length();//獲取計數器的長度 if(nameLen > nameLength){//如果計數器超長了,那么命名的長度(nameLength)就需要進行擴容,不然會出現文件名重復的情況 nameLength++; nameExpansion++;//這里記錄是因為,當后面的操作出現錯誤時,這里可能需要將原來的長度進行恢復 } if(nameLen <= nameLength){ int d_Value = String.valueOf(Math.pow(10, nameLength) - 1).length() - String.valueOf(counter).length() - 2;//計算需要填補的0的個數,這里減2是因為去除double數據后面的.0 for (int i = 0; i < d_Value; i++) { newFileName += "0"; } } newFileName += counter;//將計數器添加到名字上 String oldFileName = oldFile.getName();//獲取源文件的名字 String dirName = oldFile.getParentFile().getAbsolutePath();//獲取源文件的上級文件夾的路徑 File newFile = new File(dirName + File.separator + newFileName + oldFileName.substring(oldFileName.lastIndexOf(".")));//利用新的文件名生成文件 counter++;//計數器需要進行+1 return newFile; } /** * 將源文件重命名為新文件的名字 * 參數:oldFile:源文件, newFile:新文件 * 返回值:無 * */ private void renameFile(File oldFile, File newFile) { //=================如果源文件和新文件都存在,并且源文件和新文件的名字不相同,那么就需要將源文件備份處理,等其他文件重命名完之后再執行這類文件的重命名操作================= if(oldFile.exists() && oldFile.isFile() && newFile.exists() && newFile.isFile()){ if(!newFile.getName().equals(oldFile.getName())){ //===============================將源文件做備份處理=============================== File oldFileTemp = null; int fileTempCounter = 0; //使用do...while...循環確保暫存文件中沒有重復的名字 do{ oldFileTemp = new File(oldFile.getAbsolutePath() + fileTempCounter + System.currentTimeMillis()); fileTempCounter++; }while(oldFileTemp.exists() && oldFileTemp.isFile()); //將源文件的內容復制到備份文件中 try{ new FileServiceImpl().copyFile(oldFile, oldFileTemp); }catch (Exception e){ e.printStackTrace(); } //刪除源文件 oldFile.delete(); //將源文件的備份文件和源文件需要重命名的名字記錄到HashMap里面,最后進行這部分文件的命名操作 tempFileMap.put(oldFileTemp, newFile); return; } } //如果目標文件不存在或者目標文件名與源文件名相同,就直接進行重命名的操作 if(oldFile.exists() && oldFile.isFile()){ if(oldFile.renameTo(newFile)){ System.out.println("重命名成功:" + oldFile.getAbsolutePath() + "==>" + newFile.getAbsolutePath()); return; } } //重命名失敗就將計數器減一,并且將命名的長度還原到原來的長度 System.out.println("====================================重命名失敗:" + oldFile.getAbsolutePath() + "===================================="); counter--; nameLength -= nameExpansion; } /** * 重命名剩下的源文件的備份文件 * 參數:無 * 返回值:無 * */ private void renameTempFiles() { Set<Entry<File, File>> entrySet = tempFileMap.entrySet(); for (Entry<File, File> entry : entrySet) { //調用重命名的方法進行重命名 renameFile(entry.getKey(), entry.getValue()); } } public int getCounter() { return counter; } public void setCounter(int counter) { this.counter = counter; } public int getNameLength() { return nameLength; } public void setNameLength(int nameLength) { this.nameLength = nameLength; } }
由于counter(計數器)和nameLength(命名的長度)在進行排序和文件重命名的時候會頻繁的使用到,因此我把他們放到了子類里面,避免多次調用父類的getter和setter方法。雖然我代碼里面注釋寫得很清楚,但是還是有一些小伙伴不習慣看注釋,那我稍微做一下解釋,但是代碼的邏輯還是要大家下來看一下!如果在博客上不太方便的話,可以直接copy到eclipse里面或者idea里面進行邏輯的分析!
(1)在主方法或其他方法需要調用到這個類型,可以直接利用該類的構造方法來調用到這個類:
public HashMapSortUtils(HashMap<File, Object> sortMap, Integer counter, Integer nameLength, String prefix){ ...... }
這個構造方法會將需要進行排序和重命名的HashMap加載到該類的成員變量中,該類所有方法都可以調用該HashMap,并且計數器開始的位置(counter)、命名的長度(nameLength)、命名前綴(prefix)都加載到成員變量中,其中HashMap和前綴屬于父類的變量。(相信大多數人都知道,我就亂解釋一番了。。。)
(2)將傳進來的HashMap進行排序的方法:
public LinkedHashMap<File, Object> sortFileMap() { ...... }
該方法就是利用java工具類Collections下面的sort方法進行排序,需要注意的是,最后之所以返回的是一個LinkedHashMap是因為HashMap是無序的,如果排完序還是用HashMap裝排序的結果,那么就有可能沒有達到排序預期的效果
(3)將排好序的HashMap中的文件重命名的方法:
public void renameFiles(LinkedHashMap<File, Object> linkedTimeMap) { ...... }
該方法主要分為兩個步驟:a.利用createFileName方法將之前設置好的prefix(前綴)、nameLength(命名的長度)、counter(計數器)組成新的名字;b.將HashMap中所有的entry節點利用renameFile方法進行判斷是否可以直接重命名,如果可以直接重命名就直接重命名,如果需要重新命名的文件已經存在就將源文件copy一份出來,然后將拷貝文件和新的名字方法一個HashMap中,等到程序的第c步才執行這部分文件的重命名!c.將之前未進行重命名的源文件進利用renameTempFiles方法行統一的重命名!
文件操作是一個公共的類,進行文件的復制、刪除、獲取所有文件、創建文件夾等等,都可以寫做一個公共的方法,大家可以自行去了解這個類的作用,這里不再過多的贅述(嘻嘻,又可以偷波懶了),不過我這里是錯誤的示范,我用接口的方式來實現的,真正的生產中是不會這樣做的,因為文件操作是基本上不會變的,這里我只是想單純的聯系一下接口的操做,那么廢話不多說,直接上代碼,都是文件操作的基礎代碼:
文件操作的接口:
package readcolor; import java.io.File; import java.util.List; public interface FileService { void copyFile(String sourcePath, String targetPath) throws Exception; void copyFile(File sourceFile, File targetFile) throws Exception; void mkDirs(String path) throws Exception; List<File> getAllFiles(String sourcePath); void removeFiles(String path); void removeFiles(File sourceFile); }
文件操作的實現類:
package readcolor; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.ArrayList; import java.util.List; public class FileServiceImpl implements FileService{ @Override public void copyFile(String sourcePath, String targetPath) throws Exception { copyFile(new File(sourcePath), new File(targetPath)); } @Override public void copyFile(File sourceFile, File targetFile) throws Exception { FileInputStream fis = new FileInputStream(sourceFile); FileOutputStream fos = new FileOutputStream(targetFile); byte[] buffer = new byte[1024]; int len = 0; while((len = fis.read(buffer)) != -1){ fos.write(buffer, 0, len); fos.flush(); } fos.close(); fis.close(); } @Override public void mkDirs(String path) throws Exception { File destFile = new File(path); if(!destFile.exists()){ destFile.mkdirs(); } } @Override public List<File> getAllFiles(String sourcePath) { ArrayList<File> files = new ArrayList<File>(); File file = new File(sourcePath); if(file.exists() && !file.isHidden()){ if(file.isFile()){ files.add(file); } if(file.isDirectory()){ File[] fs = file.listFiles(); for (File f : fs) { if(!f.isHidden()){ if(f.isFile()){ files.add(file); } if(f.isDirectory()){ files.addAll(getAllFiles(sourcePath + File.separator + f.getName())); } } } } } return files; } @Override public void removeFiles(String path) { removeFiles(new File(path)); } @Override public void removeFiles(File sourceFile) { if (!sourceFile.isDirectory()){ if(sourceFile.delete()) System.out.println("刪除文件:" + sourceFile.getAbsolutePath() + "成功"); }else{ File[] files = sourceFile.listFiles(); for (File file : files) { if(file.isDirectory()){ removeFiles(file); if(file.delete()) System.out.println("刪除文件夾:" + file.getAbsolutePath() + "成功"); }else{ if(file.delete()) System.out.println("刪除文件:" + file.getAbsolutePath() + "成功"); } } } } }
好的,一切準備就緒,那我們直接開始運行代碼,看看效果如何:
先準備好圖片:
然后設置好文件的路徑:
運行java程序:
可以看到所有的文件都已經重新排序,并且已經進行重命名了,看看實際的效果:
是不是感覺前面的圖片要稍微綠一點呢?該程序可以進行重復執行的,暫時沒有出現命名失敗的情況,如果有小伙伴試了然后報錯了,記得留言喔,我看看是啥問題,然后看看能不能再優化一下。。。(聞到了頭發掉落的氣息)
最后,我們可以稍微改動幾行代碼,然后將所有的圖片只輸出綠色像素點來做一個直觀的感受:
package readcolor; import java.awt.image.BufferedImage; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.HashMap; import java.util.LinkedHashMap; import javax.imageio.ImageIO; public class ReadColor { private static int count = 0; public static void main(String[] args) { HashMap<File, Object> imageMap = new HashMap<File, Object>();//用hashMap將文件和對應的像素點數量裝到一起 File fileDir = new File("D:\\Download\\TestFile");//將要進行排序的文件目錄 File[] listFiles = fileDir.listFiles(); for (File readFile : listFiles) { getImagePixel(readFile, imageMap);//獲取圖片的綠色像素點數量的多少 } HashMapSortUtils hashMapSortUtils = new HashMapSortUtils(imageMap, 1, 3, "Mus"); LinkedHashMap<File,Object> sortFileMap = hashMapSortUtils.sortFileMap();//將圖片按照像素點的數量進行排序 hashMapSortUtils.renameFiles(sortFileMap);//將排好序的文件重命名(不然離開控制臺就看不到文件的排序了>o<) System.out.println(imageMap); } private static HashMap<File, Object> getImagePixel(File readFile, HashMap<File, Object> imageMap) { int red = 0;//記錄像素點的紅色 int green = 0;//記錄像素點的綠色 int blue = 0;//記錄像素點的藍色 int counter = 0;//程序計數器 BufferedImage bi = null; try { bi = ImageIO.read(readFile);//通過ImageIO來讀取圖片,以便獲取圖片的RGB信息 } catch (IOException e) { e.printStackTrace(); } int width = bi.getWidth();//獲取圖片的寬度 int height = bi.getHeight();//獲取圖片的高度 int minx = bi.getMinX();//獲取圖片的坐標起點x軸 int miny = bi.getMinY();//獲取圖片的坐標起點y軸 for(int i = minx; i < width; i++){ for(int j = miny; j < height; j++){ int pixel = bi.getRGB(i, j); red = (pixel & 0xff0000) >> 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", new File("D:\\Download\\TestFile1\\" + count +".jpg")); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } count++; return imageMap; } }
將圖片的非綠色像素點修改為白色,然后存到一個新的文件夾里,看看是什么效果:
上述內容就是利用java怎么根據圖片中綠色像素的多少進行排序,你們學到知識或技能了嗎?如果還想學到更多技能或者豐富自己的知識儲備,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。