参考:【OpenCV入门指南】第七篇 线段检测与圆检测
(一)、边缘检测
一维显著特征常见表示为边缘。边缘检测的预处理常用 高斯模糊;主要数学运算为计算一阶和二阶导数,寻找梯度和零交叉点,其中梯度计算可用快速卷积码实现;常见的算子有:
一阶::Roberts Cross算子,Prewitt算子,Sobel算子, Kirsch算子,罗盘算子;
二阶: Marr-Hildreth,在梯度方向的二阶导数过零点,Canny算子,Laplacian算子。
图像处理过程使用卷积实现边缘检测:常用的边缘检测模板有Laplacian算子、Roberts算子、Sobel算子、log(Laplacian-Gauss)算子、Kirsch算子和Prewitt算子等。
常见算子Sobel和Canny比较:Soble边缘检测算法比较简,实际应用中效率比canny边缘检测效率要高,但是边缘不如Canny检测的准确,但是很多实际应用的场合,sobel边缘却是首选,尤其是对效率要求较高,而对细纹理不太关心的时候,也可以作为预检测。
(二):快速几何形状检测图像处理过程使用卷积实现边缘检测:常用的边缘检测模板有Laplacian算子、Roberts算子、Sobel算子、log(Laplacian-Gauss)算子、Kirsch算子和Prewitt算子等。
常见算子Sobel和Canny比较:Soble边缘检测算法比较简,实际应用中效率比canny边缘检测效率要高,但是边缘不如Canny检测的准确,但是很多实际应用的场合,sobel边缘却是首选,尤其是对效率要求较高,而对细纹理不太关心的时候,也可以作为预检测。
1. 线段检测和圆检测:
线段检测与圆检测主要运用Hough变换,Hough变换是一种利用图像的全局特征将特定形状的边缘连接起来,形成连续平滑边缘的一种方法。它通过将源图像上的点影射到用于累加的参数空间,实现对已知解析式曲线进行识别。
在OpenCV编程中,线段检测和圆检测已经封装成函数了,直接使用cvHoughLines2和cvHoughCircles即可。Hough线检测函数原型:
CvSeq* cvHoughLines2( CvArr* image, //第一个参数表示输入图像,必须为二值图像(黑白图) void* line_storage,//第二个参数表示存储容器,和上一篇的轮廓检测一样,可以传入CvMemStorage类型的指针 int method,//第三个参数表示变换变量,可以取下面的值: //CV_HOUGH_STANDARD - 标准 Hough 变换. 每一线段由两浮点数(ρ,θ)表示,其中ρ是线段与原点(0,0)之间的距离,θ线段与 x-轴之间的夹角。 //CV_HOUGH_PROBABILISTIC - 概率Hough变换(若图像包含一些长的线性分割,效率更高)。返回线段分割而非整个线段。每个分割用起点和终点表示。 //CV_HOUGH_MULTI_SCALE - 传统 Hough 变换的多尺度变种。线段的编码方式与 CV_HOUGH_STANDARD 的一致。 double rho,//第四个参数表示与象素相关单位的距离精度。 double theta,//第五个参数表示弧度测量的角度精度。 int threshold,//第六个参数表示检测线段的最大条数,如果已经检测这么多条线段,函数返回。 double param1=0, //第七个参数与第三个参数有关,其意义如下: //对传统 Hough 变换,不使用(0); 对概率 Hough 变换,它是最小线段长度. 对多尺度 Hough 变换,它是距离精度 rho 的分母 (大致的距离精度是 rho 而精确的应该是 rho / param1 ). double param2=0//第八个参数与第三个参数有关,其意义如下: //对传统 Hough 变换,不使用 (0). //对概率 Hough 变换,此参数表示在同一线段上进行碎线段连接的最大间隔值(gap), 即当同一线段两碎线段间的间隔小于param2时,将其合二为一。 //对多尺度 Hough 变换,它是角度精度 theta 的分母 (大致的角度精度是 theta 而精确的角度应该是 theta / param2). );
函数实现:
// 图像中的线段检测 #include <opencv2/opencv.hpp> using namespace std; #pragma comment(linker, "/subsystem:"windows" /entry:"mainCRTStartup"") int main() { const char *pstrWindowsSrcTitle = "原图(http://blog.csdn.net/MoreWindows)"; const char *pstrWindowsLineName = "线段检测"; // 从文件中加载原图 Mat SrcImage = imread("D:/Circle.jpg", CV_LOAD_IMAGE_UNCHANGED); // 灰度图 Mat GrayImage= Mat(Size(SrcImage.rows, SrcImage.cols), CV_8SC1);//CV_32FC1); //cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY); // 边缘图 Mat CannyImage= Mat(Size(SrcImage.rows, SrcImage.cols), CV_8SC1);//CV_32FC1); cvCanny(pGrayImage, pCannyImage, 30, 90); //1、使用了Canny检测的方法!!! //cvSmooth(pCannyImage, pCannyImage); //线段检测(只能针对二值图像) //以下代码待修改!!!! CvMemStorage *pcvMStorage = cvCreateMemStorage(); double fRho = 1; double fTheta = CV_PI / 180; int nMaxLineNumber = 50; //最多检测条直线 double fMinLineLen = 50; //最小线段长度 double fMinLineGap = 10; //最小线段间隔 CvSeq *pcvSeqLines = cvHoughLines2(pCannyImage, pcvMStorage, CV_HOUGH_PROBABILISTIC, fRho, fTheta, nMaxLineNumber, fMinLineLen, fMinLineGap); // 绘制线段 IplImage *pColorImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 3); cvCvtColor(pCannyImage, pColorImage, CV_GRAY2BGR); for(int i = 0; i < pcvSeqLines->total; i++) { CvPoint* line = (CvPoint*)cvGetSeqElem(pcvSeqLines, i); cvLine(pColorImage, line[0], line[1], CV_RGB(255,0,0), 2); } cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE); cvShowImage(pstrWindowsSrcTitle, pSrcImage); cvNamedWindow(pstrWindowsLineName, CV_WINDOW_AUTOSIZE); cvShowImage(pstrWindowsLineName, pColorImage); cvReleaseMemStorage(&pcvMStorage); cvDestroyWindow(pstrWindowsSrcTitle); cvDestroyWindow(pstrWindowsLineName); //cvReleaseImage(&pSrcImage); //cvReleaseImage(&pGrayImage); //cvReleaseImage(&pCannyImage); //cvReleaseImage(&pColorImage); cvWaitKey(0); return 0; }
引用原结果:
Hough圆检测的代码:
#include <opencv2/opencv.hpp> using namespace std; #pragma comment(linker, "/subsystem:"windows" /entry:"mainCRTStartup"") int main() { const char *pstrWindowsSrcTitle = "原图(http://blog.csdn.net/MoreWindows)"; const char *pstrWindowsLineName = "圆检测"; // 从文件中加载原图 IplImage *pSrcImage = cvLoadImage("201.jpg", CV_LOAD_IMAGE_UNCHANGED); // 灰度图 IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1); cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY); //cvSmooth(pGrayImage, pGrayImage); // 圆检测(灰度图) CvMemStorage *pcvMStorage = cvCreateMemStorage(); double fMinCircleGap = pGrayImage->height / 10; CvSeq *pcvSeqCircles = cvHoughCircles(pGrayImage, pcvMStorage, CV_HOUGH_GRADIENT, 1, fMinCircleGap); //每个圆由三个浮点数表示:圆心坐标(x,y)和半径 // 绘制直线 IplImage *pColorImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 3); cvCvtColor(pGrayImage, pColorImage, CV_GRAY2BGR); int i; for (i = 0; i < pcvSeqCircles->total; i++) { float* p = (float*)cvGetSeqElem(pcvSeqCircles, i); cvCircle(pColorImage, cvPoint(cvRound(p[0]), cvRound(p[1])), cvRound(p[2]), CV_RGB(255, 0, 0), 2); } cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE); cvShowImage(pstrWindowsSrcTitle, pSrcImage); cvNamedWindow(pstrWindowsLineName, CV_WINDOW_AUTOSIZE); cvShowImage(pstrWindowsLineName, pColorImage); cvWaitKey(0); cvReleaseMemStorage(&pcvMStorage); cvDestroyWindow(pstrWindowsSrcTitle); cvDestroyWindow(pstrWindowsLineName); cvReleaseImage(&pSrcImage); cvReleaseImage(&pGrayImage); cvReleaseImage(&pColorImage); return 0; }
快速检测矩形的题目可以借鉴上述OpenCV原型里面的算法.....
待完成.....
han and zhu (2005)提出使用潜在的匹配矩形形状和嵌套结构(矩形和消失点之间)的语法来推导 矩形框 最有可能的对应线段...
计算机视觉:算法与应用 p196-p197