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