最大熵阈值分割_阈值分割 最大熵法 - CSDN
  • 最大熵阈值分割

    万次阅读 2017-03-20 22:45:51
    1.频率和概率  直方图每个矩形框的数值描述的是图像中相应灰度值的频率。因此,可以说直方图是一种离散的频率分布。给定一个大小为M*N的图像I,直方图中所有矩形框所代表的数值之和,即为图像中的像素数量,即: ...

    1.频率和概率

        直方图每个矩形框的数值描述的是图像中相应灰度值的频率。因此,可以说直方图是一种离散的频率分布。给定一个大小为M*N的图像I,直方图中所有矩形框所代表的数值之和,即为图像中的像素数量,即:

        相对应的归一化直方图表示为:

       0<=i<K 通常被解释为一个随机过程的概率分布或概率密度函数,表示的是图像中像素灰度值为i所出现的概率。i的累积概率值为1,即概率分布p必须满足以下关系:

        与累积概率所所对应的累积直方图H是一个离散的分布函数P(),(通常也称为累积分布函数或cdf):

    2.最大熵阈值分割

        熵是信息理论中一个重要的概念,这种方法常用于数据压缩领域。熵是一种统计测量方法,用以确定随机数据源中所包含的信息数量。例如,包含有N个像素的图像I,可以解释为包含有N个符号的信息,每一个符号的值都独立获取于有限范围K(e.g.,256)中的不同灰度值。

       将数字图像建模为一种随机信号处理,意味着必须知道图像灰度中每一个灰度g所发生的概率,即:

      因为所有概率应该事先知道,所以这些概率也称为先验概率。对于K个不同灰度值g=0,…,K-1的概率向量可以表示为:

     上述概率向量也称为概率分布或称为概率密度函数(pdf)。实际数字图像处理应用当中,先验的概率通常是不知道的,但是这些概率可以通过在一幅图像或多幅图像中观察对应灰度值所发生的频率,从而估算出其概率。图像概率密度函数p(g)可以通过归一化其对应的直方图获得其概率,即:

    3.最大熵

        数字图像中给定一个估算的概率密度函数p(g),数字图像中的熵定义为:

    4.用图像熵进行图像分割

        利用图像熵为准则进行图像分割有一定历史了,学者们提出了许多以图像熵为基础进行图像分割的方法。我们介绍一种由Kapuret al提出来,现在仍然使用较广的一种图像熵分割方法。

    给定一个特定的阈值q(0<=q<K-1),对于该阈值所分割的两个图像区域C0,C1,其估算的概率密度函数可表示为:


     同样的,背景熵可以改写为:





    5.代码实现及结果

    int MakeTable(double *S1,double *S2,double *NormalizeHist,int HistSize)
    {	int i;
    
    	double s0 = 0,s1;
    	for (i=0;i < HistSize;i++)
    	{
    		if (NormalizeHist[i]>0)
    		{
    			 s0 = s0+NormalizeHist[i]*log(NormalizeHist[i]);
    		}
    		S1[i] = s0;
    	}
    
    	s1 = 0;
    	for (i = HistSize-1;i >= 0;i--)
    	{
    		S2[i] = s1;
    		if (NormalizeHist[i]>0)
    		{
    			s1 = s1+NormalizeHist[i]*log(NormalizeHist[i]);
    		}
    	}
    	return 0;
    }
    
    int Get_Max_Entropy_Threshold(T_U32 *Hist,DWORD width,DWORD height)
    {
    	int i,q,HistSize = 256,qMax = -1;
    	double NormalizeHist[256] = {0},H01 = 0,H0 = 0,H1 = 0,P1 = 0,P0 = 0, Hmax = -9999 ;
    	double S1[256] = {0},S2[256] = {0};
    
    	for (i = 0;i < HistSize;i++)
    		NormalizeHist[i] = Hist[i]/(double)(width*height);
    
    	MakeTable(S1,S2,NormalizeHist,HistSize);
    
    	for (q = 0; q < HistSize-1;q++)
    	{
    		P0 += NormalizeHist[q];
    		P1 = 1 - P0;
    
    		if(P0 > 0)
    			H0 = -(1*S1[q])/P0+log(P0);
    		else
    			P0 = 0;
    
    		if(P1 > 0)
    			H1 = -(1*S2[q])/P1+log(P1);
    		else
    			H1 = 0;
    
    		H01 = H0+H1;
    
    		if (H01 > Hmax)
    		{
    			Hmax = H01;
    			qMax = q;
    		}
    
    	}
    	return qMax;
    }
    int Max_Entropy_Threshold(IMAGE_TYPE *BMP8_img)
    {
    	DWORD width,height,i,j,bfsize;
    	WORD  biBitCount;
    	T_U8 *dst,*bmp,k;
    	T_U32 line_byte,Threshold,index,Hist[256] = {0};
    	
    	BITMAPFILEHEADER bf;
    	BITMAPINFOHEADER bi;
    	
    	FILE *Max_Entropy_ThresholdBMP_fp = fopen("Max_Entropy_Threshold.bmp","wb");
    	
    	if(NULL == Max_Entropy_ThresholdBMP_fp)
    	{
    		printf("Can't open IsoData_Threshold.bmp\n");
    		return -1;
    	}
    	bmp = BMP8_img;
    	memset(&bf, 0, sizeof(bf));
    	memset(&bi, 0, sizeof(bi));
    	memcpy(&bf,bmp,14);
    	memcpy(&bi,&bmp[14],40);
    	
    	height = bi.biHeight;
    	width  = bi.biWidth;
    	bfsize = bf.bfSize;
    	biBitCount = bi.biBitCount;
    	line_byte = (width * 8 / 8 + 3) / 4 * 4; 
    	dst = BMP8_img+54+1024;
    
    	for (i = 0; i < height;i++)
    	{
    		for (j = 0;j < width;j++)
    		{
    			Hist[dst[i*line_byte+j]]++;
    		}
    	}
    	
    
    	dst = BMP8_img+54+1024;
    	Threshold = Get_Max_Entropy_Threshold(Hist,width,height);
    	for(i = 0;i < height;i++)
    	{
    		for(j = 0;j < width;j++)
    		{
    
    			index = i*line_byte+j;
    			k = dst[index];
    			
    			if(k >= Threshold)
    				dst[index] = 255;
    			else
    				dst[index] = 0;
    			
    		}
    	}
    	
    	fwrite(BMP8_img,bfsize,1,Max_Entropy_ThresholdBMP_fp);
    	fclose(Max_Entropy_ThresholdBMP_fp);
    	Max_Entropy_ThresholdBMP_fp = NULL;
    	
    	return 0;
    
    }

    结果:










    展开全文
  • 阈值分割最大熵分割法

    千次阅读 2015-07-24 10:37:11
    第一次尝试写博客,希望能坚持下去。。。言归正传,下面开始介绍最近在学习的最大熵分割法。 最近在做红外小目标检测,用到一个最大熵分割法,之后会把 tophat+最大熵分割法 贴出来。...设分割阈值为设分割阈值为t,

    第一次尝试写博客,希望能坚持下去。。。
    最近在做红外小目标检测,用到一个最大熵分割法,ok,下面介绍一下。


    最大熵分割法

    现在主要用的熵算法有 P 氏熵算法,KSW 熵算法、JM 熵算法下面以经典的 KSW 熵算法为例介绍其原理和计算过程。

    KSW熵算法

    设分割阈值为设分割阈值为t,

      

    T为{0,1,2,...t}的灰度分布,B为{t+1,t+2,...L-1}的灰度分布,则概率分布为:

                                                                                                                             


    式中

           

    则这两个概率密度相关的熵为:

      

     

    定义函数φ(t)为H(T)和H(B)的和,则

     

    求出φ(t)最大时的灰度级t即为所求的最佳阈值。

    灰度直方图的求法参见 http://blog.csdn.net/xiaowei_cqu/article/details/7600666


    代码如下:

    
    
    #include <cv.h>
    #include <opencv2/opencv.hpp>  
    #include <opencv2/legacy/legacy.hpp>
    using namespace cv;
    
    float calc_entropy(CvHistogram *hist, int begin, int end)
    {
    	float total = 0;  // 总概率
    	// 得到总的Pi
    	for(int i = begin; i < end; i++)
    	{
    		total += cvQueryHistValue_1D(hist,i);
    	}
    
    	float entropy = 0;  // 熵
    	
    	for(int i = begin; i < end; i++)
    	{
    		float probability = cvQueryHistValue_1D(hist, i);
    		if(probability == 0)
    			continue;
    		probability /= total;
    
    		entropy += -probability*log(probability);
    	}
    
    	return entropy;
    }
    
    int ksw_entropy(IplImage *img)
    {
    	assert(img != NULL);
    	assert(img->depth == 8);  
        assert(img->nChannels == 1);  
    
    	float range[2] = {0,255};
    	float *ranges[1] = {&range[0]};
    	int sizes = 256;
    
    	// 创建直方图
    	CvHistogram *hist = cvCreateHist(1, &sizes, CV_HIST_ARRAY, ranges, 1);
    	// 直方图计算
    	cvCalcHist(&img, hist, 0, 0);
    	// 直方图归一化
    	cvNormalizeHist(hist, 1.0); 
    
    	int threshold = 0;
    	float max_entropy = 0;
    	// 循环计算,得到做大熵以及分割阈值
    	for(int i = 0; i < sizes; i++)
    	{
    		float entropy = calc_entropy(hist, 0, i) + calc_entropy(hist, i+1, sizes);
    		if(entropy > max_entropy)
    		{
    			max_entropy = entropy;
    			threshold = i;
    		}
    	}
    
    	return threshold;
    }
    int main(int argc, char **argv)
    {
    	IplImage *img = cvLoadImage("1.bmp", CV_LOAD_IMAGE_GRAYSCALE);
    	IplImage *reimg = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
    
    	int threshold = ksw_entropy(img);
    	cvThreshold(img, reimg, threshold, 255, CV_THRESH_BINARY); 
    
    	cvNamedWindow("img");
    	cvShowImage("img", img);
    	cvNamedWindow("reimg");
    	cvShowImage("reimg", reimg);
    
    	cvWaitKey(0);
    	return 0;
    }

    在学习获取灰度直方图的时候,有一个函数让我费解了半天,cvNormalizeHist,灰度归一化,刚开始就是搞不懂这个灰度归一化是指的什么,

    opencv给出的函数解释如下:



    什么叫the sum of the bins becomes equal to factor,好吧,后来明白了,其实意思就是说,把直方图纵坐标的值相加的和等于第二个参数,所以如果设为1的话,那纵坐标的值就是该灰度级的概率了。

    下面是实验图片:

                 

                                      图1  原图                                          图2   最大熵阈值分割后图片

    效果很不理想吧,所以在做阈值分割前需要加入tophat,后面博客会讲到。

    全文完。


    展开全文
  • 最大熵阈值分割算法原理及实现

    千次阅读 热门讨论 2019-05-14 19:41:01
    前面介绍了OTSU算法,对于阈值分割法,不得不介绍另外一种较为突出的算法——最大熵阈值分割法(KSW熵算法)。 最大熵阈值分割法和OTSU算法类似,假设将图像分为背景和前景两个部分。熵代表信息量,图像信息量越大...

    写在前面

    前面介绍了OTSU算法,对于阈值分割法,不得不介绍另外一种较为突出的算法——最大熵阈值分割法(KSW熵算法)。

    最大熵阈值分割法和OTSU算法类似,假设将图像分为背景和前景两个部分。熵代表信息量,图像信息量越大,熵就越大,最大熵算法就是找出一个最佳阈值使得背景与前景两个部分熵之和最大。

     

    原理

    由于和OTSU算法类似,所以原理上就不再赘述和推导,言简意赅。

             熵的公式:

                                                                 

     

     

    基于OpenCV实现 

    #include <iostream>
    #include <opencv2/core.hpp>
    #include <opencv2/highgui.hpp>
    #include <opencv2/imgproc.hpp>
    
    int Max_Entropy(cv::Mat& src, cv::Mat& dst, int thresh, int p){
    	const int Grayscale = 256;
    	int Graynum[Grayscale] = { 0 };
    	int r = src.rows;
    	int c = src.cols;
    	for (int i = 0; i < r; ++i){
    		const uchar* ptr = src.ptr<uchar>(i);   
    		for (int j = 0; j < c; ++j){   
    			if (ptr[j] == 0)				//排除掉黑色的像素点
    				continue;
    			Graynum[ptr[j]]++;
    		}
    	}
    
    	float probability = 0.0; //概率
    	float max_Entropy = 0.0; //最大熵
    	int totalpix = r*c;
    	for (int i = 0; i < Grayscale; ++i){
    
    		float HO = 0.0; //前景熵
    		float HB = 0.0; //背景熵
    
    	    //计算前景像素数
    		int frontpix = 0;
    		for (int j = 0; j < i; ++j){
    			frontpix += Graynum[j];
    		}
    		//计算前景熵
    		for (int j = 0; j < i; ++j){
    			if (Graynum[j] != 0){
    				probability = (float)Graynum[j] / frontpix;
    				HO = HO + probability*log(1/probability);
    			}
    		}
    
    		//计算背景熵
    		for (int k = i; k < Grayscale; ++k){
    			if (Graynum[k] != 0){
    				probability = (float)Graynum[k] / (totalpix - frontpix);
    				HB = HB + probability*log(1/probability);
    			}
    		}
    
    		//计算最大熵
    		if(HO + HB > max_Entropy){
    			max_Entropy = HO + HB;
    			thresh = i + p;
    		}
    	}
    
    	//阈值处理
    	src.copyTo(dst);
    	for (int i = 0; i < r; ++i){
    		uchar* ptr = dst.ptr<uchar>(i);
    		for (int j = 0; j < c; ++j){
    			if (ptr[j]> thresh)
    				ptr[j] = 255;
    			else
    				ptr[j] = 0;
    		}
    	}
    	return thresh;
    }
    
    
    int main(){
    	cv::Mat src = cv::imread("I:\\Learning-and-Practice\\2019Change\\Image process algorithm\\Img\\tttt.png");
    	if (src.empty()){
    		return -1;
    	}
    	if (src.channels() > 1)
    		cv::cvtColor(src, src, CV_RGB2GRAY);
    
    	cv::Mat dst, dst2;
    	int thresh = 0;
    	double t2 = (double)cv::getTickCount();
    	thresh = Max_Entropy(src, dst, thresh,10); //Max_Entropy
    	std::cout << "Mythresh=" << thresh << std::endl;
    	t2 = (double)cv::getTickCount() - t2;
    	double time2 = (t2 *1000.) / ((double)cv::getTickFrequency());
    	std::cout << "my_process=" << time2 << " ms. " << std::endl << std::endl;
    
    	double  Otsu = 0;
    	Otsu = cv::threshold(src, dst2, Otsu, 255, CV_THRESH_OTSU + CV_THRESH_BINARY);
    	std::cout << "Otsuthresh=" << Otsu << std::endl;
    	
    
    	cv::namedWindow("src", CV_WINDOW_NORMAL);
    	cv::imshow("src", src);
    	cv::namedWindow("dst", CV_WINDOW_NORMAL);
    	cv::imshow("dst", dst);
    	cv::namedWindow("dst2", CV_WINDOW_NORMAL);
    	cv::imshow("dst2", dst2);
    	//cv::imwrite("I:\\Learning-and-Practice\\2019Change\\Image process algorithm\\Image Filtering\\MeanFilter\\TXT.jpg",dst);
    	cv::waitKey(0);
    }

     

    效果

                                   原图                                                            最大熵法                                                            Otsu

    阈值及效率

     

    发现最大熵法 的阈值会偏高,我在代码中加了一个偏置矫正因子p,可以适当调节。

     

    参考:

    https://blog.csdn.net/bendanban/article/details/47058355

    https://blog.csdn.net/lz0499/article/details/64164477

    展开全文
  • 图像阈值分割最大熵

    千次阅读 2018-08-28 10:55:47
    图像最大熵阈值分割的原理:使选择的阈值分割图像目标区域、背景区域两部分灰度统计的信息量为最大。  具体描述: 1. 根据信息熵定义,计算原始图像的信息熵H0,选择最大、最小灰度灰度的均值为初始阈值T0; 2. ...

        图像最大熵阈值分割的原理:使选择的阈值分割图像目标区域、背景区域两部分灰度统计的信息量为最大。

        具体描述:

    1. 根据信息熵定义,计算原始图像的信息熵H0,选择最大、最小灰度灰度的均值为初始阈值T0;

    2. 根据T0将图像分割为G1和G2两个区域,均值分别为M1和M2,更新阈值为T2=0.5*(M1+M2);

    3. 计算G1和G2的信息熵Hd和Hb,比较Hd+Hb与H0的大小,如果相等或在规定的范围内,或者达到最大迭代次数,则将T2最为最终阈值输出,否则T0=T2,H0=Hd+Hb,重复第2步直到满足条件。

    function ThreshValue = My_MaxEntropy(Imag)
    % 最大熵计算阈值
    % 输入:
    %    Imag:二维数组,数值表示灰度;
    % 输出:
    %    ThreshValue:阈值
    [X, Y] = size(Imag);
    V_max = max(max(Imag));
    V_min = min(min(Imag));
    T0 = (V_max + V_min) / 2;      % 初始分割阈值
    h = My_imhist(Imag);              % 计算图像的直方图
    grayp = h/(X*Y);                      % 求图像像素概率
    % 计算初始熵
    H0 = 0;
    for i = 1 : 256
        if grayp(i) > 0
            H0 = H0 - grayp(i)*log(grayp(i));
        end
    end
    % 开始迭代计算
    cout = 100;                            % 设置最大迭代次数
    while cout > 0
        Tmax = 0;          % 初始化
        T1 = T0;   
        A1 = 0;              % 分割区域G1的点数
        A2 = 0;              % 分割区域G2的点数
        B1 = 0;              % 分割区域G1的灰度总和
        B2 = 0;              % 分割区域G2灰度总和
        for i = 1 : X        % 计算灰度平均值
            for j = 1 : Y
                if(Imag(i, j) <= T1)
                    A1 = A1 + 1;
                    B1 = B1 + Imag(i, j);
                else
                    A2 = A2 + 1;
                    B2 = B2 + Imag(i, j);
                end
            end
        end
        M1 = B1 / A1;              % 分割区域G1的平均灰度
        M2 = B2 / A2;              % 分割区域G2的平均灰度
        T2 = (M1 + M2) / 2;     % 更新阈值
        TT = floor(T2);
        grayPd = sum(grayp(1 : TT));    % 计算分割区域G1的概率和
        if grayPd == 0
            grayPd = eps;
        end
        grayPb = 1 - grayPd;
        if grayPb == 0
            grayPb = eps;
        end
        % 计算分割后区域G1和G2的信息熵
        Hd = 0;
        Hb = 0;
        for i = 1 : 256
            if i <= TT
                if grayp(i) > 0
                    Hd = Hd - grayp(i)/grayPd*log(grayp(i)/grayPd);
                end
            else
                if grayp(i) > 0
                    Hb = Hb - grayp(i)/grayPb*log(grayp(i)/grayPb);
                end
            end
        end
        H1 = Hd + Hb;      % 总的熵
        % 退出条件
        if abs(H0 - H1) < 0.0001 
            Tmax = T2;
            break;
        else 
            T0 = T2;
            H0 = H1;
        end
        cout = cout - 1;
    end
    % 返回阈值
    ThreshValue = floor(Tmax);
    end
    
    % 灰度直方图
    function h = My_imhist(Imag)
    h = zeros(256, 1);
    for k = 1 : 256
        h(k) = 0;
        for i = 1 : size(Imag, 2)
            for j = 1 : size(Imag, 2)
                if Imag(i, j) == k - 1
                    h(k) = h(k) + 1;
                end
            end
        end
    end
    end

     

    展开全文
  • 转自:...lt;opencv2/imgproc/imgproc.hpp&gt; #include &lt;opencv2/core/core.hpp&gt; #include &...opencv2/highgui/highgui.hpp&...#include ...
  • 最大熵阈值分割代码

    2016-12-07 10:13:48
    理论在这里 http://blog.csdn.net/happygirlliu520/article/details/47026649 ...//最大熵阈值分割 float opencv::calEntropy(const Mat& src) { ASSERT(CV_8UC1 == src.type()); double pix_probility[256
  • 最大熵阈值分割

    千次阅读 2017-12-28 10:58:25
    现在主要用的熵算法有 P 氏熵算法,KSW 熵算法、JM 熵算法下面以经典的 KSW 熵算法为例介绍其原理和...设分割阈值为设分割阈值为t,   T为{0,1,2,...t}的灰度分布,B为{t+1,t+2,...L-1}的灰度分布,则概率分布为:
  • 一、计算图像的直方图 1.概念及原理 (1)直方图是一个简单的表,它给出了一幅图像或一组图像中拥有给定数值的像素数量。例如灰度图像的直方图有265个条目(或称为容器)。0号容器给出值为0的像素个数,1号容器给...
  •  近期在做图像处理灰阶分割的研究,发现网上有很多将一维最大熵阈值分割的文章与程序代码,但是二维最大熵的资源相对较小。故本博客的目的就在于此,在学习的过程中记录相关笔记,以便帮助后面的研究者少走些弯路。...
  • 一维最大熵阈值分割

    2013-10-16 16:50:47
    最大熵阈值分割原理中,熵和最大处取得最佳阈值,请问为什么?? 熵代表了最不确定性的情况,众所周知,一般来说分类问题越靠近两类的边界,则分布的不确定性就越大,熵的值也就越大。 图像分割:...
  • 最大熵阈值分割
  • 一维最大熵阈值分割应该比较好理解,可参见:http://blog.sina.com.cn/s/blog_159aff7940102xbm4.html 二维 一、灰度直方图 二、熵(这里实在看不懂,请大神赐教) 虽然看不懂,但还是按书上敲一次,代码...
  • 阈值分割是一种常用的图像分割方法,基于灰度阈值的选取将图像灰度划分为一个或几个集合,实现图像的分割。阈值分割方法的关键是阈值选取准则,常用的准则有最大类间方差(OTSU 大津法)和信息熵。信息熵包括很多种...
  • 最大熵阈值分割原始经典英文论文,值得仔细阅读,图像处理经典论文
  • OTSU阈值分割: static int OtsuThreshold(unsigned char* Input, int count) { __int32 AppearTime[256]; for (int i = 0, v; i < 256; i++)AppearTime[i] = 0; for (int i = 0, v; i < count; i++) ...
  • 1.最大熵原理 原理自己还是不是很清楚,-p*log(p)当p增大的时候log(p)减小,那么随着阈值的增加,前景(或者背景)的熵值的变化应该不是单调的(没有证明,只是自己感觉)。但我试着求出随着阈值变化的背
  • 最大熵阈值分割算法的C语言实现

    千次阅读 2009-03-03 13:34:00
    /*=================================================================== 代码内容:最大熵阈值分割 = 修改日期:2009-3-3
1 2 3 4 5 ... 20
收藏数 1,085
精华内容 434
关键字:

最大熵阈值分割