天天看點

最大熵門檻值分割實作

原理:

最大熵門檻值分割實作

實作:

int maxentropy(Mat& src, Mat& dst)
{
	int thresh = 0;
	int histogram[256] = { 0 };
	for (int i = 0; i < src.rows; ++i)
	{
		const uchar* ptr = src.ptr<uchar>(i);
		for (int j = 0; j < src.cols; ++j)
		{
			if (ptr[j] == 0) continue;//排除掉黑色的像素點		
			histogram[ptr[j]]++;
		}
	}

	float p = 0.0; //機率
	float max_entropy = 0.0; //最大熵
	int totalnum = src.rows*src.cols;
	for (int i = 0; i < 256; ++i)
	{
		float front_entropy = 0.0; //前景熵
		float back_entropy = 0.0; //背景熵

		//計算前景像素數
		int frontnum = 0;
		for (int j = 0; j < i; ++j) 
		{
			frontnum += histogram[j];
		}
		//計算前景熵
		for (int j = 0; j < i; ++j)
		{
			if (histogram[j] != 0)
			{
				p = (float)histogram[j] / frontnum;
				front_entropy += p*log(1 / p);
			}
		}

		//計算背景熵
		for (int k = i; k < 256; ++k) 
		{
			if (histogram[k] != 0)
			{
				p = (float)histogram[k] / (totalnum - frontnum);
				back_entropy += p*log(1 / p);
			}
		}

		//計算最大熵
		if (front_entropy + back_entropy > max_entropy) 
		{
			max_entropy = front_entropy + back_entropy;
			thresh = i ;
		}
	}

	//門檻值處理
	dst = src.clone();
	for (int i = 0; i < dst.rows; ++i)
	{
		uchar* ptr = dst.ptr<uchar>(i);
		for (int j = 0; j < dst.cols; ++j)
		{
			if (ptr[j] > thresh)
				ptr[j] = 255;
			else
				ptr[j] = 0;
		}
	}
	return thresh;
}