OpenCV Hough Line變換

2021-02-19 17:04 更新

目標(biāo)

在本教程中,您將學(xué)習(xí)如何:

理論

注意
下面的解釋屬于Bradski和Kaehler 的“ 學(xué)習(xí)OpenCV ”一書。

Hough Line變換

  1. Hough Line變換是用于檢測(cè)直線的變換。
  2. 為了應(yīng)用變換,首先需要邊緣檢測(cè)預(yù)處理。

它是如何工作的?

  1. 如你所知,圖像空間中的一行可以用兩個(gè)變量表示。例如:在笛卡爾坐標(biāo)系中:參數(shù):(m,b);在極坐標(biāo)系中:參數(shù):(r,θ)

Hough Line變換

對(duì)于Hough 變換,我們將在極地系統(tǒng)中表達(dá)線條。因此,線性方程可以寫為:Hough Line變換

Hough Line變換

排列術(shù)語:r=xcosθ+ysinθ

  • 通常,對(duì)于每個(gè)點(diǎn)(x0,y0),我們可以定義通過該點(diǎn)的行給出如下公式:

Hough Line變換

意思是每一對(duì)的 (rθ,θ)表示通過每一排的 (x0,y0)


  • 如果對(duì)于給定的 (x0,y0)我們繪制通過它的線族,我們得到一個(gè)正弦曲線,例如,對(duì)于x0=8y0=6 ,我們得到以下圖(在平面 θ - r)

Hough Line變換

我們只需考慮這樣的情況: r>0 和 0<θ<2π.

  • 我們可以對(duì)圖像中的所有點(diǎn)執(zhí)行上述相同的操作。如果兩個(gè)不同點(diǎn)的曲線在平面θ - r相交,那意味著兩個(gè)點(diǎn)都屬于同一行。例如,按照上面的例子,并繪制兩個(gè)點(diǎn)的x1=4, y1=9 和 x2=12, y2=3,,我們得到:

Hough Line變換

三個(gè)曲線在一個(gè)點(diǎn)(0.925,9.6)相交,這些坐標(biāo)是參數(shù) ( θ,r) 或其中(x0,y0), (x1,y1) 和 (x2,y2) lay.

  • 上面所有的東西是什么意思?這意味著一般來說,通過找到曲線之間的交點(diǎn)數(shù)可以檢測(cè)到一條線。更多的相交曲線意味著由該交點(diǎn)表示的線具有更多的點(diǎn)。通常,我們可以定義檢測(cè)線路所需的最小交點(diǎn)數(shù)的閾值。
  • 這就是Hough Line變換所做的。它跟蹤圖像中每個(gè)點(diǎn)的曲線之間的交點(diǎn)。如果交叉點(diǎn)的數(shù)量高于某個(gè)閾值,則它將其聲明為具有交點(diǎn)的參數(shù)(θ,rθ)的行。

標(biāo)準(zhǔn)和概率Hough Line變換

OpenCV實(shí)現(xiàn)了兩種Hough線變換:

一個(gè)。標(biāo)準(zhǔn)Hough變換

  • 它幾乎包含在上一節(jié)中我們剛剛解釋的內(nèi)容。它給你一個(gè)向量的結(jié)果(θ,rθ)
  • 在OpenCV中,它使用函數(shù)cv :: HoughLines實(shí)現(xiàn)

灣 概率霍夫線變換

Code

  1. 這個(gè)程序是做什么的?加載圖像應(yīng)用標(biāo)準(zhǔn)Hough Line變換或概率線變換。在兩個(gè)窗口中顯示原始圖像和檢測(cè)到的線。
  2. 我們將從這里下載我們將要解釋的示例代碼。這里可以找到一個(gè)稍微優(yōu)雅的版本(其中顯示了Hough 標(biāo)準(zhǔn)和帶有軌跡的概率更改閾值)。
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
using namespace cv;
using namespace std;
static void help()
{
    cout << "\nThis program demonstrates line finding with the Hough transform.\n"
            "Usage:\n"
            "./houghlines <image_name>, Default is ../data/pic1.png\n" << endl;
}
int main(int argc, char** argv)
{
    cv::CommandLineParser parser(argc, argv,
        "{help h||}{@image|../data/pic1.png|}"
    );
    if (parser.has("help"))
    {
        help();
        return 0;
    }
    string filename = parser.get<string>("@image");
    if (filename.empty())
    {
        help();
        cout << "no image_name provided" << endl;
        return -1;
    }
    Mat src = imread(filename, 0);
    if(src.empty())
    {
        help();
        cout << "can not open " << filename << endl;
        return -1;
    }
    Mat dst, cdst;
    Canny(src, dst, 50, 200, 3);
    cvtColor(dst, cdst, COLOR_GRAY2BGR);
#if 0
    vector<Vec2f> lines;
    HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 );
    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( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA);
    }
#else
    vector<Vec4i> lines;
    HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 );
    for( size_t i = 0; i < lines.size(); i++ )
    {
        Vec4i l = lines[i];
        line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, LINE_AA);
    }
#endif
    imshow("source", src);
    imshow("detected lines", cdst);
    waitKey();
    return 0;
}

說明

  • 加載圖像
Mat src = imread(filename, 0);
if(src.empty())
{
  help();
  cout << "can not open " << filename << endl;
  return -1;
}
  • 使用Canny檢測(cè)器檢測(cè)圖像的邊緣
Canny(src,dst,50,200,3);

現(xiàn)在我們將應(yīng)用Hough Line變換。我們將解釋如何使用可用于此目的的兩個(gè)OpenCV功能:

  • 標(biāo)準(zhǔn)霍夫線變換

首先,你應(yīng)用變換:

vector<Vec2f> lines;
HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 );

具有以下參數(shù):

  1. dst:邊緣檢測(cè)器的輸出。它應(yīng)該是一個(gè)灰度圖像(盡管事實(shí)上它是二進(jìn)制的)
  2. 行:一個(gè)向量,將存儲(chǔ)檢測(cè)到的行的參數(shù)(r,θ)
  3. rho:參數(shù)的分辨率(以像素為單位)。我們使用1像素。r
  4. theta:以弧度表示的參數(shù)的分辨率。我們使用1度(CV_PI / 180)θ
  5. threshold:將“* detect *”一行的最小交點(diǎn)數(shù)
  6. srn和stn:默認(rèn)參數(shù)為零。查看OpenCV參考了解更多信息

然后通過繪制線條顯示結(jié)果。

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( cdst, pt1, pt2, Scalar(0,0,255), 3, LINE_AA);
}
  • Probabilistic Hough Line變換

首先你應(yīng)用變換:

vector<Vec4i> lines;
HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 );

有論據(jù):

  1. dst:邊緣檢測(cè)器的輸出。它應(yīng)該是一個(gè)灰度圖像(盡管事實(shí)上它是二進(jìn)制的)
  2. 行:將存儲(chǔ)檢測(cè)到的行的參數(shù)的(xstart,ystart,xend,yend)
  3. rho:參數(shù)的分辨率(以像素為單位)。我們使用1像素。r
  4. theta:以弧度表示的參數(shù)的分辨率。我們使用1度(CV_PI / 180)θ
  5. threshold:將“* detect *”一行的最小交點(diǎn)數(shù)
  6. minLinLength:可以形成一行的最小點(diǎn)數(shù)。小于這個(gè)點(diǎn)數(shù)的行被忽略。
  7. maxLineGap:在同一行中考慮的兩點(diǎn)之間的最大差距。

然后通過繪制線條顯示結(jié)果。

for( size_t i = 0; i < lines.size(); i++ )
{
  Vec4i l = lines[i];
  line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, LINE_AA);
}
  • 顯示原始圖像和檢測(cè)到的線條:
imshow("source", src);
imshow("detected lines", cdst);
  • 等到用戶退出程序
waitKey();

結(jié)果

注意
以下結(jié)果是使用我們?cè)凇?nbsp;代碼”部分提到的稍微優(yōu)雅的版本獲得的。它仍然實(shí)現(xiàn)與上述相同的內(nèi)容,只添加Threshold的Trackbar。

使用輸入圖像,如:

Hough Line變換

我們通過使用Probabilistic Hough Line變換得到以下結(jié)果:

Hough Line變換

您可能會(huì)發(fā)現(xiàn)在更改閾值時(shí)檢測(cè)到的行數(shù)會(huì)有所不同。解釋很明顯:如果建立更高的Threshold,將檢測(cè)到更少的行(因?yàn)槟枰嗟狞c(diǎn)來聲明檢測(cè)到的行)。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)