自适应Canny阈值算法
求取灰度图像的梯度图imge和梯度的最大值maxv;
设置梯度图的直方图hist的hist_size=maxv, ranges在[0, maxv]范围内,并计算直方图hist;
设置非边缘像素点占整幅图像像素点的比例PercentOfPixelsNotEdges;
设置total阈值,total = size.height * size.width * PercentOfPixelsNotEdges;
遍历直方图hist中,每个梯度值对应的像素点个数,并求和保存在sum变量中;
如果sum变量的值大于total的值,退出hist遍历的循环;
计算Canny的低阈值和高阈值。
a.如果某一像素位置的幅值超过高阈值, 该像素被保留为边缘像素。
b.如果某一像素位置的幅值小于低阈值, 该像素被排除。
c.如果某一像素位置的幅值在两个阈值之间, 该像素仅仅在连接到一个高于高阈值的像素时被保留。
Canny 推荐的 高:低 阈值比在 2:1 到3:1之间。
cvCanny函数中, 高低阈值自适应计算方法 - cay22的专栏 - CSDN博客
https://blog.csdn.net/bagboy_taobao_com/article/details/47158987
StraightLineFinder.rar StraightLineFinder.cpp
http://read.pudn.com/downloads171/sourcecode/graph/texture_mapping/791537/StraightLineFinder/StraightLineFinder/StraightLineFinder.cpp__.htm
在OpenCV中自适应确定canny算法的分割门限 - sunlylorn的专栏 - CSDN博客
https://blog.csdn.net/sunlylorn/article/details/8015825
Canny边缘检测及自适应门限 - NoNeil - CSDN博客
https://blog.csdn.net/debug__boy/article/details/8179730
一种自适应阈值的Canny边缘检测算法_图文_百度文库
https://wenku.baidu.com/view/607820c16137ee06eff9187b.html
#include <cv.h>
#include <highgui.h>
#include <math.h>
#include <iostream>
using namespace std;
void AdaptiveFindThreshold(const CvArr* image, double *low, double *high, int aperture_size=3);
void _AdaptiveFindThreshold(CvMat *dx, CvMat *dy, double *low, double *high);
int main(int argc, char** argv)
{
IplImage* pImg = NULL;
IplImage* pCannyImg = NULL;
double low_thresh = 0.0;
double high_thresh = 0.0;
if( argc == 2 && (pImg = cvLoadImage( argv[1], 0)) != 0 )
{
pCannyImg = cvCreateImage(cvGetSize(pImg), IPL_DEPTH_8U, 1);
CvMat *dx = (CvMat*)pImg;
CvMat *dy = (CvMat*)pCannyImg;
if(low_thresh == 0.0 && high_thresh == 0.0)
{
AdaptiveFindThreshold(pImg, &low_thresh, &high_thresh);
cout << "low_thresh: " << low_thresh << endl;
cout << "high_thresh: " << high_thresh << endl;
}
cvCanny(pImg, pCannyImg, low_thresh, high_thresh, 3);
cvNamedWindow("src", 1);
cvNamedWindow("canny",1);
cvShowImage( "src", pImg );
cvShowImage( "canny", pCannyImg );
cvWaitKey(0);
cvDestroyWindow( "src" );
cvDestroyWindow( "canny" );
cvReleaseImage( &pImg );
cvReleaseImage( &pCannyImg );
}
return 0;
}
void AdaptiveFindThreshold(const CvArr* image, double *low, double *high, int aperture_size)
{
cv::Mat src = cv::cvarrToMat(image);
const int cn = src.channels();
cv::Mat dx(src.rows, src.cols, CV_16SC(cn));
cv::Mat dy(src.rows, src.cols, CV_16SC(cn));
cv::Sobel(src, dx, CV_16S, 1, 0, aperture_size, 1, 0, cv::BORDER_REPLICATE);
cv::Sobel(src, dy, CV_16S, 0, 1, aperture_size, 1, 0, cv::BORDER_REPLICATE);
CvMat _dx = dx, _dy = dy;
_AdaptiveFindThreshold(&_dx, &_dy, low, high);
}
// 仿照matlab,自适应求高低两个门限
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;
}
}
if(maxv == 0){
*high = 0;
*low = 0;
cvReleaseImage( &imge );
return;
}
// 计算直方图
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);
}