在《【OpenCV入門指南】第五篇輪廓檢測上》與《【OpenCV入門指南】第六篇輪廓檢測下》講解了OpenCV的輪廓檢測。本篇將講解在OpenCV中使用線段檢測與圓檢測。編程
線段檢測與圓檢測主要運用Hough變換,Hough變換是一種利用圖像的全局特徵將特定形狀的邊緣鏈接起來,造成連續平滑邊緣的一種方法。它經過將源圖像上的點影射到用於累加的參數空間,實現對已知解析式曲線進行識別。windows
在OpenCV編程中,線段檢測和圓檢測已經封裝成函數了,直接使用cvHoughLines2和cvHoughCircles便可,下面來看看函數介紹和實際代碼。app
《OpenCV入門指南》系列文章地址:http://blog.csdn.net/morewindows/article/category/863841函數
函數功能:檢測圖像中的線段編碼
函數原型:spa
CvSeq* cvHoughLines2( .net
CvArr* image, 指針
void* line_storage, orm
int method,blog
double rho,
double theta,
int threshold,
double param1=0, double param2=0
);
參數說明:
第一個參數表示輸入圖像,必須爲二值圖像(黑白圖)。
第二個參數表示存儲容器,和上一篇的輪廓檢測同樣,能夠傳入CvMemStorage類型的指針。
第三個參數表示變換變量,能夠取下面的值:
CV_HOUGH_STANDARD - 傳統或標準 Hough 變換. 每個線段由兩個浮點數 (ρ, θ) 表示,其中 ρ 是線段與原點(0,0) 之間的距離,θ 線段與 x-軸之間的夾角。
CV_HOUGH_PROBABILISTIC - 機率 Hough 變換(若是圖像包含一些長的線性分割,則效率更高)。它返回線段分割而不是整個線段。每一個分割用起點和終點來表示。
CV_HOUGH_MULTI_SCALE - 傳統 Hough 變換的多尺度變種。線段的編碼方式與 CV_HOUGH_STANDARD 的一致。
第四個參數表示與象素相關單位的距離精度。
第五個參數表示弧度測量的角度精度。
第六個參數表示檢測線段的最大條數,若是已經檢測這麼多條線段,函數返回。
第七個參數與第三個參數有關,其意義以下:
對傳統 Hough 變換,不使用(0).
對機率 Hough 變換,它是最小線段長度.
對多尺度 Hough 變換,它是距離精度 rho 的分母 (大體的距離精度是 rho 而精確的應該是 rho / param1 ).
第八個參數與第三個參數有關,其意義以下:
對傳統 Hough 變換,不使用 (0).
對機率 Hough 變換,這個參數表示在同一條線段上進行碎線段鏈接的最大間隔值(gap), 即當同一條線段上的兩條碎線段之間的間隔小於param2時,將其合二爲一。
對多尺度 Hough 變換,它是角度精度 theta 的分母 (大體的角度精度是 theta 而精確的角度應該是 theta / param2).
線段檢測的原理仍是有點複雜,有興趣請閱讀專業書籍,下面給一個份示例代碼:
[cpp] view plaincopy
// 圖像中的線段檢測
//By MoreWindows (http://blog.csdn.net/MoreWindows)
#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);
// 邊緣圖
IplImage *pCannyImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);
cvCanny(pGrayImage, pCannyImage, 30, 90);
//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);
int i;
for(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);
cvWaitKey(0);
cvReleaseMemStorage(&pcvMStorage);
cvDestroyWindow(pstrWindowsSrcTitle);
cvDestroyWindow(pstrWindowsLineName);
cvReleaseImage(&pSrcImage);
cvReleaseImage(&pGrayImage);
cvReleaseImage(&pCannyImage);
cvReleaseImage(&pColorImage);
return 0;
}
運行結果以下:
圓檢測函數要用到cvHoughCircles這個函數的函數原形以下:
CVAPI(CvSeq*) cvHoughCircles(
CvArr* image, void* circle_storage,
int method,
double dp,
double min_dist,
double param1 CV_DEFAULT(100),
double param2 CV_DEFAULT(100),
int min_radius CV_DEFAULT(0),
int max_radius CV_DEFAULT(0)
);
能夠看出cvHoughCircles與上面的cvHoughLines2函數比較相似,所以講下部分參數的意思就能夠了:
第二個參數表示Hough變換方式,目前只能用CV_HOUGH_GRADIENT。
第三個參數表示尋找圓弧圓心的累計分辨率,一般設置成1就能夠了。
第四個參數表示兩個不一樣圓之間的最小距離,因爲是按圓心來計算距離的,所以對同心圓的檢測就無能爲力了。
注意,圓檢測函數可使用灰度圖。
圓檢測的代碼以下:
[cpp] view plaincopy
// 圖像中的圓檢測
//By MoreWindows (http://blog.csdn.net/MoreWindows)
#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入門指南】第五篇輪廓檢測上》、《【OpenCV入門指南】第六篇輪廓檢測下》及《【OpenCV入門指南】第七篇線段檢測與圓檢測》介紹了圖像的輪廓檢測,線段檢測及圓檢測。
下面幾篇將介紹圖像的直方圖,這對統計圖像的信息以及根據這些信息來加強圖像很是有幫助。歡迎繼續瀏覽《【OpenCV入門指南】第八篇灰度直方圖》、《【OpenCV入門指南】第九篇灰度直方圖均衡化》與《【OpenCV入門指南】第十篇彩色直方圖均衡化》。