参考: 【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