(驚艷)基於谷底最小值的閾值的圖像分割(改進HSV中的H分量可以用imhist(H)提取)


 

 

任務概述:將這張圖片作為輸入 , 然后摳出只有斑點的圖片

 

 

靈感來源:

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,運行

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM