基于边缘改进的全局阈值 opencv

算法步骤:

 

注意点:1.2步骤中采用百分比阈值 ,阈值的百分数应设置较大值(如99.7%),可以排除背景中的干扰点

99.97%时候的二值图(为了可视化,灰度值范围设置为0-255)

90%的二值图

2.最后一步中,通过otsu计算阈值时候,灰度值为0的像素点不计入计算。

核心算法:

void edge_threshold(Mat &src)
{
	Mat src1 = src.clone();
	Mat dst, thre, dst_x, dst_y;

	medianBlur(src1, src1, 3);

	Mat kernel_x = (Mat_<int>(3, 3) << -1, -2, -1, 0, 0, 0, 1, 2, 1);
	Mat kernel_y = (Mat_<int>(3, 3) << -1, 0, 1, -2, 0, 2, -1, 0, 1);

	filter2D(src1, dst_x, CV_16SC1, kernel_x);
	filter2D(src1, dst_y, CV_16SC1, kernel_y);

	convertScaleAbs(dst_x, dst_x);
	convertScaleAbs(dst_y, dst_y);

	dst = dst_x + dst_y;

	int hist[256] = { 0 };
	uchar * d_data = dst.data;
	for (int j = 0; j < dst.rows; j++)
	{
		for (int i = 0; i < dst.cols; i++)
		{
			if (d_data[j*dst.step + i] != 0)
			{
				hist[d_data[j*dst.step + i]]++;	
			}
		}
	}
	long sum = 0, Amount = 0;
	double percent;
		
	int T = 0;
	for (int k = 0; k < 256; k++)
	{
		Amount += hist[k];
	}

	for (int i = 0; i < 256; i++)
	{
		sum += hist[i];
		if (sum >= Amount*0.9)
		{
			T = i;
			break;
		}
	}

	threshold(dst, thre, T, 1, THRESH_BINARY);

	Mat src2;
	src2 = thre.mul(src1);//取thre 中的像素值为1的像素点。

	Mat src3;
	
	threshold(src1, src3, OtsuThreshold(src2), 255, THRESH_BINARY);
	imshow("result", src3);
}

otsu算法:

int OtsuThreshold(Mat src)
{
	int threshold;

	int height = src.rows; 
	int width = src.cols;

	//histogram  
	float histogram[256] = { 0 };
	uchar * s_data = src.data;
	for (int i = 0; i < height; i++)
	{
		for (int j = 0; j < width; j++)
		{
			if (s_data[i*src.step + j] != 0)//排除直方图中的0像素值 
				histogram[s_data[i*src.step + j]]++;
		}
	}
	
	int m = 0, n = 0; //m:第一个有像素的灰度值 n:最后一个有像素的灰度值
	long sum_value = 0;//非零像素个数
	bool singel = true;
	for (int i = 1; i < 256; i++)
	{
		if (histogram[i] != 0 && singel)
		{
			m = i;
			singel = false;
		}

		if (histogram[i] != 0)
		{
			sum_value++;
		}
	}

	for (int j = 255; j >= 0; j--)
	{
		if (histogram[j] != 0)
		{
			n = j;
			break;
		}
	}

	float  sum0, sum1, cnt0, cnt1, w0, w1, u0, u1, u, variance;
	float maxVariance = 0;
	for (int i = m+1; i <= n; i++)
	{
		 sum0 = 0;
	     sum1 = 0;
		 cnt0 = 0;
		 cnt1 = 0;
		 w0 = 0;
		 w1 = 0;

		 if (histogram[i] != 0)
		 {
			 for (int j = m; j < i; j++)
			 {
				 cnt0 += histogram[j];
				 sum0 += j * histogram[j];
			 }

			 u0 = (double)sum0 / cnt0;
			 w0 = (double)cnt0 / sum_value;

			 for (int j = i; j <= n; j++) 
			 {
				 cnt1 += histogram[j];
				 sum1 += j * histogram[j];
			 }

			 u1 = (double)sum1 / cnt1;
			 w1 = (double)cnt1 / sum_value;

			 u = u0 * w0 + u1 * w1; //图像的平均灰度
		
			 variance = w0 * w1 *  (u0 - u1) * (u0 - u1);
			 if (variance > maxVariance)
			 {
				 maxVariance = variance;
				 threshold = i;
			 }
		 }
	}

	return threshold;
}

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值