cvCanny函数中, 高低阈值自适应计算方法

        OpenCV的Canny算法实现函数的参数中, 需要输入高低阈值, 如果高低阈值输入不对, 通常等不到理想的边缘效果.
网上有人仿Matlab, 实现了自适应高低阈值, 代码如下:

void HYAdaptiveFindThreshold(CvMat *dx, CvMat *dy, double *low, double *high)
{
	CvSize size = cvGetSize(dx);
	IplImage* imge = cvCreateImage(size, IPL_DEPTH_32F, 1);
	
	// 计算边缘的强度, 并存于图像中
	int i, j;
	short* _dx = 0;
	short* _dy = 0;
	float* _image = 0;
	float maxv = 0;
	for(i = 0; i < size.height; ++i)
	{
		_dx = (short*)(dx->data.ptr + dx->step * i);
		_dy = (short*)(dy->data.ptr + dy->step * i);
		_image = (float *)(imge->imageData + imge->widthStep * i);
		for(j = 0; j < size.width; ++j)
		{
			_image[j] = (float)(abs(_dx[j]) + abs(_dy[j]));
			maxv = maxv < _image[j] ? _image[j]: maxv;
		}
	}
	
	int hist_size = 255;
	float range_0[] = {0, 256};
	float* ranges[] = {range_0};

	// 计算直方图
	range_0[1] = maxv;	// 最大值
	hist_size = (int)(hist_size > maxv ? maxv : hist_size);
	
	CvHistogram* hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1);	
	cvCalcHist(&imge, hist, 0, 0);
	
	double dPercentOfPixelsNotEdges = 0.97;
	int total = (int)(size.height * size.width * dPercentOfPixelsNotEdges);
	float sum=0;
	int icount = hist->mat.dim[0].size;

	float *h = (float*)cvPtr1D(hist->bins, 0);
	for(i = 0; i < icount; ++i)
	{
		sum += h[i];
		if(sum > total)
			break; 
	}
	// 计算高低门限
	*high = (i + 1) * maxv / hist_size ;
	*low = *high * 0.4 ;
	cvReleaseImage(&imge);
	cvReleaseHist(&hist);
}
    至于为什么这样来求出高低阈值, 自己也不是很理解. 其中CvMat *dx和CvMat *dy分别是用两个Sobel算子计算水平和垂直两个方向的梯度强度得到的.


看看cvCanny函数的代码:
......
	//梯度  
	dx = cvCreateMat( size.height, size.width, CV_16SC1 );  
	dy = cvCreateMat( size.height, size.width, CV_16SC1 );  
	cvSobel( src, dx, 1, 0, aperture_size );  
	cvSobel( src, dy, 0, 1, aperture_size );  

	// 我们可以在这里自适应计算高低阈值
	if(low_thresh == -1 && high_thresh == -1)   
	{   
		HYAdaptiveFindThreshold(dx, dy, &low_thresh, &high_thresh);   
	}
......
      重编一下OpenCV的代码, cvCanny函数的两个高低阈值就可以实现自适应了.
我们也可以自己求出用Sobel算子求出水平和垂直方向的强度, 然后求出高低阈值, 然后再调用cvCanny, 但是这样子就重复了Sobel算子的计算了.


参考:
http://read.pudn.com/downloads171/sourcecode/graph/texture_mapping/791537/StraightLineFinder/StraightLineFinder/StraightLineFinder.cpp__.htm
http://blog.chinaunix.net/uid-14231482-id-2826875.html
http://blog.youkuaiyun.com/sunlylorn/article/details/8015825
### Canny算子结合自适应阈值的图像处理 为了实现Canny算子与自适应阈值相结合的图像处理算法,在OpenCV库中可以通过一系列函数调用来完成这一过程。具体来说,先利用`cv2.cvtColor()`转换颜色空间以便后续操作更高效;接着应用高斯模糊减少噪声影响,再计算自适应阈值得到高低阈值范围,最后使用`cv2.Canny()`执行边缘检测。 #### 颜色空间转换与预处理 由于彩色图像是三维数组形式存储RGB三个通道的数据,而灰度图像是二维数组只含单个亮度信息,因此对于大多数情况下进行边缘提取前需将原图转成灰度模式以简化运算并提高效率[^1]: ```python import cv2 import numpy as np def preprocess_image(image_path): img = cv2.imread(image_path) gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换成灰色图片 blurred_img = cv2.GaussianBlur(gray_img, (5, 5), 0) # 应用高斯滤波去除噪音 return blurred_img ``` #### 计算自适应阈值 传统固定阈值可能无法很好地适用于不同光照条件下的图像,所以采用自适应方式确定上下限更为合理。这里可以根据局部区域内的平均强度或中位数值动态调整参数设置[^4]: ```python def adaptive_thresholding(blurred_img): block_size = 11 # 设置block size大小 c_constant = 2 # 减去常数项 high_thresh = cv2.adaptiveThreshold( blurred_img, maxValue=255, adaptiveMethod=cv2.ADAPTIVE_THRESH_GAUSSIAN_C, thresholdType=cv2.THRESH_BINARY_INV, blockSize=block_size, C=c_constant) low_thresh = 0.5 * high_thresh.max() # 取最高阈值一半作为低阈值 return int(low_thresh), int(high_thresh.max()) ``` #### 执行Canny边缘检测 有了上述准备之后就可以直接调用`cv2.Canny()`来进行最终的边缘识别工作了。此函数接收两个重要参数——即高低阈值,当像素梯度大于等于高阈值时被认定为强边沿点;介于两者之间的则视为弱边沿候选者待进一步确认;低于低阈值一律舍弃[^2][^3]: ```python def canny_edge_detection(image_path): processed_img = preprocess_image(image_path) low_thres, high_thres = adaptive_thresholding(processed_img) edges = cv2.Canny(processed_img, low_thres, high_thres) resized_edges = cv2.resize(edges, None, fx=0.5, fy=0.5, interpolation=cv2.INTER_AREA) return resized_edges ``` 通过以上步骤能够有效地组合Canny算子和自适应阈值技术来增强图像边缘特征的表现力,从而更好地服务于各类应用场景需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值