【转】在OpenCV中自适应确定canny算法的分割阈值

本文介绍如何在OpenCV中实现Canny边缘检测算法的自适应高低阈值设置,通过对梯度图像进行直方图分析来自动确定阈值,从而避免手动设定阈值的不便。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在OpenCV中用canny算子进行边缘检测速度很快,不过有点不爽的就是高低阈值需要输入。在matlab中,如果不指定阈值的话,由函数自适应确定,因此仿照matlab中的做法,对canny函数进行了修改,以便当用户没有指定高低阈值时,由函数自适应确定阈值。

  我在OpenCv原码库中增加了一个函数,用于确定高低阈值。
// 仿照matlab,自适应求高低两个门限
CV_IMPL void AdaptiveFindThreshold(CvMat *dx, CvMat *dy, double *low, double *high)
{
 CvSize size;
 IplImage *imge=0;
 int i,j;
 CvHistogram *hist;
 int hist_size = 255;
    float range_0[]={0,256};
    float* ranges[] = { range_0 };
 double  PercentOfPixelsNotEdges = 0.7;
 size = cvGetSize(dx);
 imge = cvCreateImage(size, IPL_DEPTH_32F, 1);
 // 计算边缘的强度, 并存于图像中
 float maxv = 0;
 for(i = 0; i < size.height; i++ )
 {
  const short* _dx = (short*)(dx->data.ptr + dx->step*i);
        const short* _dy = (short*)(dy->data.ptr + dy->step*i);
  float* _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;
  }
 }
 
 // 计算直方图
 range_0[1] = maxv;
 hist_size = (int)(hist_size > maxv ? maxv:hist_size);
 hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, ranges, 1);
 cvCalcHist( &imge, hist, 0, NULL );
 int total = (int)(size.height * size.width * PercentOfPixelsNotEdges);
 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);
}

 

在把cvCanny函数进行以下修改。
在函数体中,当程序用两个sobel算子计算完水平和垂直两个方向的梯度强度过后加入以下代码
// 自适应确定阈值
 if(low_thresh == -1 && high_thresh == -1)
 {
  AdaptiveFindThreshold(dx, dy, &low_thresh, &high_thresh);
 }

 

这样,在调用cvCanny函数时,指定高低门限为-1,则cvCanny函数就自适应确定门限。

 

最后,别忘了重新编译cv库,对lib和dll库进行更新。

【转自:http://www.china-vision.net/blog/user2/15975/archives/2007/804.html】

### 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、付费专栏及课程。

余额充值