任務概述:將這張圖片作為輸入 , 然后摳出只有斑點的圖片
靈感來源:
1. 黃色部分用綠色的掩蓋掉得到圖片B,然后A和B進行∩運算,相同的設置為0
2.統計單詞的子母數,開辟一個26個元素的數組,進來一個字母在相應的地方++,類似hashmap
3.為什么要用Hue這個分量下手,因為這幅圖就2個顏色,肯定會在2個地方突出來,然后中間的波谷
作為分隔點,其中一個突出來的部分置為0
4.Hue分量在[0,1]連續 變化 , 灰度值和R分量在【0,255】離散的變化,將【0,1】線性變化到【0,255】
R分量就像是隨機變量X,自身只能離散的取值 , H分量是double類型的,取值是連續的
I=imread('375.png');
hv=rgb2hsv(I); %自帶的函數就是good
H=hv(:,:,1);
S=hv(:,:,2);
V=hv(:,:,3); %也可以分別繪制H,S,V分量的圖片
[M,N,D] = size(I);
vec = zeros(1,256) %初始化一個256元素的行矩陣
for i=1:M
for j=1:N
if( round( H(i,j)*255 ) == 0 )
array(1,1) = array(1,1) +0 ;
% if( round( H(i,j)*255 )==257 )
% array(1,256) = array(1,256) +1 ;
else
vec( 1 , round( H(i,j)*255 ) ) = vec( 1 , round( H(i,j)*255 ) ) + 1; %見備注圖片 %改進自帶的函數
end
end
end
%寫入
Mat = array ;
fid = fopen('D:\data.txt','wt');
[row,col] = size(Mat);
for i=1 : row
for j = 1:col
fprintf(fid,'%g\n',Mat(i,j)); %換行
end
end
fclose(fid);
H_hist = imhist(H) 將451*235個值映射到[0,1]區間有多少(將H分量的所有取值映射到[0.255]這256個離散的點上:最精辟理解啊)
那個3段算法中也是將[0,x1]的任一一個點 映射到[0,y1] 這是一對一映射 ,上面那個是多對一映射
假設得到閾值(最后介紹方法) 44
這一步是將大於閾值的點統統處理掉
num = 44/255.0; %手動修改 [M,N] = size(H); for i=1:M for j=1:N if( H(i,j) > num ) % 綠色部分顯然要多些 V(i,j) = 0;
end; %V分量0是白色 end end V2 = V; temp = cat(3,H,S,V2); temp = hsv2rgb(temp); imshow(temp);
實現--基於谷底最小值的閾值
1、描述:
此方法實用於具有明顯雙峰直方圖的圖像,其尋找雙峰的谷底作為閾值,但是該方法不一定能獲得閾值,對於那些具有平坦的直方圖或單峰圖像,該方法不合適。
2、實現過程:
該函數的實現是一個迭代的過程,每次處理前對直方圖數據進行判斷,看其是否已經是一個雙峰的直方圖,如果不是,則對直方圖數據進行半徑為1(窗口大小為3)的平滑,如果迭代了一定的數量比如1000次后仍未獲得一個雙峰的直方圖,則函數執行失敗,如成功獲得,則最終閾值取兩個雙峰之間的谷底值作為閾值。
注意在編碼過程中,平滑的處理需要當前像素之前的信息,因此需要對平滑前的數據進行一個備份。另外,首數據類型精度限制,不應用整形的直方圖數據,必須轉換為浮點類型數據來進行處理,否則得不到正確的結果。
知乎上還有人求這個判斷雙峰的算法
package erer; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.Arrays; public class test { public static int GetMinimumThreshold(int[] HistGram) { int Y, Iter = 0; double[] HistGramC = new double[256]; // 基於精度問題,一定要用浮點數來處理,否則得不到正確的結果 double[] HistGramCC = new double[256]; // 求均值的過程會破壞前面的數據,因此需要兩份數據 for (Y = 0; Y < 256; Y++) { HistGramC[Y] = HistGram[Y]; HistGramCC[Y] = HistGram[Y]; } // 通過三點求均值來平滑直方圖 while (IsDimodal(HistGramCC) == false) // 判斷是否已經是雙峰的圖像了 { HistGramCC[0] = (HistGramC[0] + HistGramC[0] + HistGramC[1]) / 3; // 第一點 for (Y = 1; Y < 255; Y++) HistGramCC[Y] = (HistGramC[Y - 1] + HistGramC[Y] + HistGramC[Y + 1]) / 3; // 中間的點 HistGramCC[255] = (HistGramC[254] + HistGramC[255] + HistGramC[255]) / 3; // 最后一點 // // System.Buffer.BlockCopy(HistGramCC, 0, HistGramC, 0, 256 * // sizeof(double)); System.arraycopy(HistGramCC, 0, HistGramC, 0, 256); Iter++; if (Iter >= 1000) return -1; // 直方圖無法平滑為雙峰的,返回錯誤代碼 } // 閾值極為兩峰之間的最小值 boolean Peakfound = false; for (Y = 1; Y < 255; Y++) { if (HistGramCC[Y - 1] < HistGramCC[Y] && HistGramCC[Y + 1] < HistGramCC[Y]) Peakfound = true; if (Peakfound == true && HistGramCC[Y - 1] >= HistGramCC[Y] && HistGramCC[Y + 1] >= HistGramCC[Y]) return Y - 1; } return -1; } private static boolean IsDimodal(double[] HistGram) // 檢測直方圖是否為雙峰的 { // 對直方圖的峰進行計數,只有峰數位2才為雙峰 int Count = 0; for (int Y = 1; Y < 255; Y++) { if (HistGram[Y - 1] < HistGram[Y] && HistGram[Y + 1] < HistGram[Y]) { Count++; if (Count > 2) return false; } } if (Count == 2) return true; else return false; } public static void main(String args[]) throws IOException { File file = new File("D:\\data.txt");// Text文件 BufferedReader br = new BufferedReader(new FileReader(file));// 構造一個BufferedReader類來讀取文件 String s = null; int[] data1 = new int[256]; int i = 0; while ((s = br.readLine()) != null) {// 使用readLine方法,一次讀一行 // System.out.println(s); System.out.println("--------------"); try { String str = s; String str2 = str.replaceAll(" ", ""); System.out.println(str2); data1[i] = Integer.parseInt(str2); ; i++; } catch (NumberFormatException e) { e.printStackTrace(); } System.out.println(Arrays.toString(data1)); System.out.println(data1.length); } br.close(); ; int[] HistGram = new int[256]; System.arraycopy(data1, 0, HistGram, 0, 256); int num = GetMinimumThreshold(HistGram); System.out.println("閾值是" + num); } }
得到閾值是28,運行