1. 程式人生 > >OpenCV中的霍夫線變換和霍夫圓變換

OpenCV中的霍夫線變換和霍夫圓變換

word 得到 統計 不同 效率 兩種 做的 ndis pan

一、霍夫線變換
霍夫線變換是OpenCv中一種尋找直線的方法,輸入圖像為邊緣二值圖。

原理:

一條直線在圖像二維空間可由兩個變量表示, 例如:
1、在 笛卡爾坐標系: 可由參數: (m,b) 斜率和截距表示。
2、在 極坐標系: 可由參數: 技術分享圖片極徑和極角表示。
技術分享圖片
對於霍夫變換,我們將用 極坐標系 來表示直線。 因此,直線的表達式可為:技術分享圖片
化簡後得:技術分享圖片

一般來說對於點 技術分享圖片, 我們可以將通過這個點的一族直線統一定義為:
技術分享圖片
這就意味著每一對技術分享圖片 代表一條通過點 技術分享圖片 的直線。

如果對於一個給定點技術分享圖片 我們在極坐標對極徑極角平面繪出所有通過它的直線,將得到一條正弦曲線。例如,對於給定點 技術分享圖片 and 技術分享圖片我們可以繪出下圖 (在平面 \theta - r):
技術分享圖片


只繪出滿足下列條件的點 技術分享圖片and 技術分享圖片

我們可以對圖像中所有的點進行上述操作. 如果兩個不同點進行上述操作後得到的曲線在平面技術分享圖片 - r 相交, 這就意味著它們通過同一條直線. 例如, 接上面的例子我們繼續對點: 技術分享圖片, 技術分享圖片 和點 技術分享圖片技術分享圖片 繪圖,得到下圖:
技術分享圖片
這三條曲線在 技術分享圖片 - r 平面相交於點 (0.925, 9.6), 坐標表示的是參數對 (技術分享圖片, r) 或者是說點 技術分享圖片, 點 技術分享圖片 和點 技術分享圖片 組成的平面內的的直線。

那麽以上的材料要說明什麽呢? 這意味著一般來說, 一條直線能夠通過在平面 技術分享圖片- r 尋找交於一點的曲線數量來 檢測. 越多曲線交於一點也就意味著這個交點表示的直線由更多的點組成. 一般來說我們可以通過設置直線上點的 閾值 來定義多少條曲線交於一點我們才認為 檢測 到了一條直線.

這就是霍夫線變換要做的. 它追蹤圖像中每個點對應曲線間的交點. 如果交於一點的曲線的數量超過了 閾值, 那麽可以認為這個交點所代表的參數對 技術分享圖片在原圖像中為一條直線。

在OpenCV中霍夫線變換分為兩種:
1、標準霍夫線變換
原理在上面的部分已經說明了. 它能給我們提供一組參數對 技術分享圖片 的集合來表示檢測到的直線
在OpenCV 中通過函數 HoughLines 來實現
2、統計概率霍夫線變換
這是執行起來效率更高的霍夫線變換. 它輸出檢測到的直線的端點 技術分享圖片
在OpenCV 中它通過函數 HoughLinesP 來實現

實現:

1、標準霍夫線變換

函數為:

void HoughLines( InputArray image, OutputArray lines,
                              double rho, double theta, int threshold,
                              double srn = 0, double stn = 0,
                              double min_theta = 0, double max_theta = CV_PI );

第一個參數為輸入圖像,應該為灰度圖,

第二個參數為輸出的檢測到的直線的容器
第三個參數為以參數極徑單位的分辨率
第四個是以弧度為單位的分辨率
第五個為一條直線所需最少的的曲線交點

int main()
{
    RNG rng(12345);
    Mat a = imread("1RT05508-0.jpg");
    imshow("原圖", a);
    cvtColor(a, a, CV_RGB2GRAY);     //轉為灰度圖
    Canny(a, a, 100, 300, 3);         //進行邊緣檢測
    Mat bbb;
    cvtColor(a, bbb, CV_GRAY2BGR);
    vector<Vec2f> lines;
    HoughLines(a, lines, 1, CV_PI / 180, 100);    //檢測
    for (size_t i = 0; i < lines.size(); i++)    //開始劃線
    {
        float rho = lines[i][0], theta = lines[i][1];
        Point pt1, pt2;
        double a = cos(theta), b = sin(theta);
        double x0 = a*rho, y0 = b*rho;
        pt1.x = cvRound(x0 + 1000 * (-b));
        pt1.y = cvRound(y0 + 1000 * (a));
        pt2.x = cvRound(x0 - 1000 * (-b));
        pt2.y = cvRound(y0 - 1000 * (a));
        line(bbb, pt1, pt2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 3, CV_AA);       //實現隨機顏色
    }
    imshow("效果圖", bbb);
    cvWaitKey(10000);

}

效果圖:
技術分享圖片
各參數的作用和標準霍夫變換相同

2、統計概率霍夫線變換
函數為:

void HoughLinesP( InputArray image, OutputArray lines,
                               double rho, double theta, int threshold,
                               double minLineLength = 0, double maxLineGap = 0 );
int main()
{
    RNG rng(12345);
    Mat a = imread("1RT05508-0.jpg");
    imshow("原圖", a);
    cvtColor(a, a, CV_RGB2GRAY);     //轉為灰度圖
    Canny(a, a, 100, 300, 3);         //邊緣檢測
    Mat bbb;
    cvtColor(a, bbb, CV_GRAY2BGR);
    vector<Vec4i> lines;
    HoughLinesP(a, lines, 1, CV_PI / 180, 50, 50, 10);   //檢測
    for (size_t i = 0; i < lines.size(); i++)       //劃線
    {
        Vec4i l = lines[i];
        line(bbb, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 3, CV_AA);      //用的是隨機顏色
    }
    imshow("效果圖", bbb);
    cvWaitKey(10000);

}

效果圖:
技術分享圖片

二、霍夫圓變換
是OpenCv中用於檢測圓的一種方法,使用 HoughCircles函數。
原理:
霍夫圓變換的基本原理和霍夫線變換類似, 只是點對應的二維極徑極角空間被三維的圓心點x, y還有半徑r空間取代。

對直線來說, 一條直線能由參數極徑極角 (r, 技術分享圖片) 表示. 而對圓來說, 我們需要三個參數來表示一個圓, 如上文所說現在原圖像的邊緣圖像的任意點對應的經過這個點的所有可能圓是在三維空間有下面這三個參數來表示了,其對應一條三維空間的曲線. 那麽與二維的霍夫線變換同樣的道理, 對於多個邊緣點越多這些點對應的三維空間曲線交於一點那麽他們經過的共同圓上的點就越多,類似的我們也就可以用同樣的閾值的方法來判斷一個圓是否被檢測到, 這就是標準霍夫圓變換的原理, 但也正是在三維空間的計算量大大增加的原因, 標準霍夫圓變化很難被應用到實際中:

這裏的 技術分享圖片表示圓心的位置 (下圖中的綠點) 而 r 表示半徑, 這樣我們就能唯一的定義一個圓了。

實現:

函數為:

void HoughCircles( InputArray image, OutputArray circles,
                               int method, double dp, double minDist,
                               double param1 = 100, double param2 = 100,
                               int minRadius = 0, int maxRadius = 0 );

src_gray: 輸入圖像 (灰度圖)
circles: 存儲下面三個參數: x_{c}, y_{c}, r 集合的容器來表示每個檢測到的圓.
CV_HOUGH_GRADIENT: 指定檢測方法. 現在OpenCV中只有霍夫梯度法
dp = 1: 累加器圖像的反比分辨率
min_dist = src_gray.rows/8: 檢測到圓心之間的最小距離
param_1 = 200: Canny邊緣函數的高閾值
param_2 = 100: 圓心檢測閾值.
min_radius = 0: 能檢測到的最小圓半徑, 默認為0.
max_radius = 0: 能檢測到的最大圓半徑, 默認為0

int main()
{
    RNG rng(12345);
    Mat a = imread("8907540_150847495169_2.jpg");
    a.resize(350);
    imshow("原圖", a);
    cvtColor(a, a, CV_RGB2GRAY);     //轉為灰度圖
    vector<Vec3f> circles;
    HoughCircles(a, circles, CV_HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);    //檢測
    cvtColor(a, a, CV_GRAY2BGR); 
    for (size_t i = 0; i < circles.size(); i++)    //開始畫圓
    {
        Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
        int radius = cvRound(circles[i][2]);     //繪制圓心  
        circle(a, center, 3, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), -1, 8, 0);     //繪制圓  
        circle(a, center, radius, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 3, 8, 0);    //依舊是隨機顏色
    }
    imshow("效果圖", a);
    cvWaitKey(10000);

}

效果圖:
技術分享圖片

OpenCV中的霍夫線變換和霍夫圓變換