天天看點

OpenCV學習之Hough變換檢測圓

Hough變換檢測圓

我們在之前利用Hough變換實作了直線的檢測,因為兩個特征(k,b)或者(theta,r)就能确定一條直線,是以我們的Hough空間是二維的。一個圓由3個特征組成,分别是圓心的橫坐标,縱坐标,以及圓的半徑,是以我們的Hough空間是三維的。

圓的方程:(x-a)^2 + (y-b)^2 = r^2

過一點(x0,y0),a,b,r的關系就是:(x0-a)^2 + (y0-b)^2 = r^2

是以,我們的Hough空間[a是橫坐标,b是縱坐标,r是豎坐标]

我們要用一個二重循環去填充Hough空間

跟直線檢測一樣,我們現在是在三維數組裡找局部最大值,确定圓的(x,y,r)

聽完之後是不是覺得方法很簡單,跟檢測直線沒什麼差別,也用不到極坐标。

但是,三維累加器中會産生許多噪聲并且使得結果不穩定的稀疏分布!

是以,由Hough梯度法來改進這個算法。

Hough梯度法

  • 利用canny檢測提取邊緣
  • 對每一個邊緣點,我們可以計算出梯度[其實就是圓心和邊緣點連線方向]
  • 計算出梯度後,我們就可以得到一條垂直于該點切線的直線,我們就有一個二維數組H,用來填充這條直線上所有點
  • H中出現頻率最高的肯定就是圓心
  • 對于得到的圓心中的每一個,計算那些邊緣點到該圓心的距離,若某個距離很充分出現次數足夠,就可以認為這是一個合格的圓
//Hough變換檢測圓
#include "cv.h"
#include "highgui.h"
#include "math.h"
int main(int argc, char** argv) {
    IplImage* img = cvLoadImage("corner.tif", );
    IplImage* gray = cvCreateImage(cvGetSize(img), , );
    CvMemStorage* storage = cvCreateMemStorage();
    cvCvtColor(img, gray, CV_BGR2GRAY);
    cvSmooth(gray, gray, CV_GAUSSIAN, , );
    //cvHoughCircles(image,storage,method,dp,min_dist,p1 = 100,p2 = 100,min_radius = 0,max_radius = 0);
    //CV_HOUGH_GRADIENT H.K于2003年發表的21HT方法
    //dp檢測圓心累加器的分辨率,1不變,2累加器尺寸為原圖一半
    //min_dist 檢測到的圓心之間的最小距離。取值太小,在一個圓被分解為多個圓。太大則漏檢
    //p1在CV_HOUGH_GRADIENT情況下,此參數為傳遞給Canny邊緣檢測算子的兩個門檻值較高的那個,低門檻值為其一半
    //p2取值越小則誤檢很多不存在的圓
    //mix_radius 被搜尋圓得最小半徑,小于此半徑被忽略
    //max_radius 最大半徑,預設為max(width,height);
    CvSeq* circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, , gray->height / , , );
    int i;
    for (i = ; i < circles->total; i++) {
        float* p = (float*)cvGetSeqElem(circles, i);
        cvCircle(img, cvPoint(cvRound(p[]), cvRound(p[])), , CV_RGB(, , ), -, , );
        cvCircle(img, cvPoint(cvRound(p[]), cvRound(p[])), cvRound(p[]), CV_RGB(, , ), , , );

    }
    cvNamedWindow("circles", );
    cvShowImage("circles", img);
    cvWaitKey();
    return ;
}