基于古老的Marr视觉理论,视觉识别和场景重建的基础即第一阶段为局部显著性探测。探测到的主要特征为直觉上可刺激底层视觉的局部显著性——特征点、特征线、特征块。
SalientDetection 已经好就没有复习过了,DNN在识别领域的超常表现在各个公司得到快速应用,在ML上耗了太多时间,求职时被CV的知识点虐死...
一:点探测总结(SIft、PCA-SIft、Surf、GLOH)
原文链接(SIFT):http://www.cnblogs.com/cfantaisie/archive/2011/06/14/2080917.html ,文章有修改!为个人意见。
(一)、Sift特征点生成的主要步骤
1)、尺度空间的生成;
2)、检测尺度空间极值点;
3)、精确定位极值点;
4)、为每个关键点指定方向参数;
(五)、点-区块检测总结:
参考链接:特征提取方法 SIFT,PCA-SIFT,GLOH,SURF 对比总结
总结论文:A comparison of SIFT, PCA-SIFT and SURF 对三种方法给出了性能上的比较,源图片来源于Graffiti datase,对原图像进行尺度、旋转、模糊、亮度变化、仿射变换等变化后,再与原图像进行匹配,统计匹配的效果。效果以可重复出现性为评价指标。
method |
Time |
Scale |
Rotation |
Blur |
Illumination |
Affine |
Sift |
common |
best |
best |
common |
common |
good |
PCA-sift |
good |
good |
good |
best |
good |
best |
Surf |
best |
common |
common |
good |
best |
good |
由此可见,SIFT在尺度和旋转变换的情况下效果最好,SURF在亮度变化下匹配效果最好,在模糊方面优于SIFT,而尺度和旋转的变化不及SIFT,旋转不变上比SIFT差很多。速度上看,SURF是SIFT速度的3倍。
采用NN作为匹配策略的特征描述子性能测评结果:
线段检测与圆检测主要运用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; }