1. 程式人生 > >cvCanny函式中, 高低閾值自適應計算方法

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.csdn.net/sunlylorn/article/details/8015825