目錄
一、前言
終於更新到霍夫直線變換了,跟以前寫的博客成功接軌。opencv基礎博客也即將更新完畢,感謝大家的支持,我們要再接再厲呀!
如果想看其他有關於OpenCV學習方法介紹、學習教程、代碼實戰、常見報錯及解決方案等相關內容,可以直接看我的OpenCV分類:
【OpenCV系列】:https://blog.csdn.net/shuiyixin/article/category/7581855
如果你想了解更多有關於計算機視覺、OpenCV、機器學習、深度學習等相關技術的內容,想與更多大佬一起溝通,那就掃描下方二維碼加入我們吧!
二、霍夫變換
1、霍夫變換是個啥
我們先來了解一下霍夫變換是個啥
霍夫變換是一種特徵檢測(feature extraction),被廣泛應用在圖像分析(image analysis)、計算機視覺(computer vision)以及數位影像處理(digital image processing)。
霍夫變換是用來辨別找出物件中的特徵,其流程大致如下:
給定一個物件、要辨別的形狀的種類,算法會在參數空間(parameter space)中執行投票來決定物體的形狀,而這是由累加空間(accumulator space)裏的局部最大值(local maximum)來決定。
2、常用霍夫變換
我們會經常使用到如下兩個霍夫變換:
1.霍夫直線變換:在圖像中尋找直線
2.霍夫圓變換:在圖像中尋找圓。
這個博客,我們一起來了解一下啥是霍夫直線變換,。如果你想了解霍夫圓變換,請轉移到:
【opencv學習筆記】022之霍夫圓變換:https://blog.csdn.net/shuiyixin/article/details/79898107
三、霍夫直線變換
1、講解
上面我們知道霍夫直線變換,就是用來檢測直線的,那怎麼知道一條線是直線呢?
假設我們有上圖這個紅色的直線,大家看到這個θ和r,學過極座標的同學應該就能知道了,我們要用極座標來表示直線了。
對於一條直線來說,我們首先要知道它的平面直角座標表示(只考慮二維平面):
而對於上圖,我們能知道:
根據上面的公式,我們能夠推導出如下公式:
推導過程可以如下:
得到這個公式,有什麼作用呢?
我們知道x和y是直線上的點,我們爲了方便講解,我們取一條直線來說明:
對於上面這條直線,有如下五個點是在直線上的:
所以我們可以得到五條直線:
如果我們以θ爲橫座標,r爲縱座標,當我們把這五條直線畫在同一個座標系中,我們能得到下面這幅圖:
我們發現,這五條直線交於同一點,這就是直線有的特點,我們就通過這個特點,將所有的直線累加,那交點處因爲是所有直線的累加,其像素值一定是最高的,我們知道,像素越高,在圖像上越亮,當達到255的時候,是最亮,即爲白色。所以我們可以通過這種方式來檢測到直線。
2、API
1.HoughLines
接下來我們講一下API。霍夫直線有兩個API,首先我們先講一個偏專業的
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
);
函數參數含義如下:
(1)InputArray類型的src ,8位,單通道二進制源圖像。
(2)OutputArray類型的lines,直線的輸出向量。每一直線都由一個雙元素向量表示。rho是距座標原點的距離(0,0)(圖像左上角)。theta是以弧度爲單位的線旋轉角度。
(3)double類型的rho,累加器的距離分辨率(像素)
(4)double類型的theta,累加器的角度分辨率(弧度)。
(5)int類型的threshold,累加器閾值參數。只返回獲得足夠累加器數量的直線。
(6)double類型的srn,對於多尺度Hough變換,它是距離分辨率rho的除數,粗累加器距離分辨率爲rho,精確累加器分辨率爲rho/srn。如果srn=0和stn=0,則使用經典Hough變換。否則,這兩個參數都應爲正。
(7)double類型的sth,對於多尺度Hough變換,它是距離分辨率θ的除數。
(8)double類型的min_theta,用於標準和多尺度Hough變換,檢查直線的最小角度。必須介於0和maxθ之間。
(9)double類型的max_theta,用於標準和多尺度Hough變換,用於檢查線條的最大角度。必須介於最小θ和CVπ之間。
2.HoughLinesP
接下來我們先講一個實用性更高的
HoughLines(
InputArray image,
OutputArray lines,
double rho,
double theta,
int threshold,
double minLineLength = 0,
double maxLineGap = 0
);
函數參數含義如下:
(1)InputArray類型的src ,8位,單通道二進制源圖像。
(2)OutputArray類型的lines,直線的輸出向量。每一直線都由一個雙元素向量表示。rho是距座標原點的距離(0,0)(圖像左上角)。theta是以弧度爲單位的線旋轉角度。
(3)double類型的rho,累加器的距離分辨率(像素)
(4)double類型的theta,累加器的角度分辨率(弧度)。
(5)int類型的threshold,累加器閾值參數。只返回獲得足夠累加器數量的直線。
(6)double類型的minLineLength,最小直線長度。小於該值的線段將被拒絕。
(7)double類型的maxLineGap,同一行上的點之間鏈接它們所允許的最大間距。
3、代碼展示
如果我們使用HoughLines,代碼如下:
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src, src_gray, dst;
src = imread("E:/image/HoughLines.bmp");
if (!src.data)
{
cout << "could not load image !";
return -1;
}
imshow("【輸入圖像】", src);
Canny(src, src_gray, 0, 255);
cvtColor(src_gray, dst, CV_GRAY2BGR);
imshow("【獲取邊緣】", src_gray);
vector<Vec2f> lines;
HoughLines(src_gray, lines, 1, CV_PI / 180, 100);
for (size_t i = 0; i < lines.size(); i++) {
float rho = lines[i][0]; // 極座標中的r長度
float 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(dst, pt1, pt2, Scalar(0, 0, 255), 5, CV_AA);
}
imshow("【輸出圖像】", dst);
waitKey(0);
return 0;
}
如果我們使用HoughLinesP,代碼如下:
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat src, src_gray, dst;
src = imread("E:/image/HoughLines.bmp");
if (!src.data)
{
cout << "could not load image !";
return -1;
}
imshow("【輸入圖像】", src);
Canny(src, src_gray, 0, 255);
cvtColor(src_gray, dst, CV_GRAY2BGR);
imshow("【獲取邊緣】", src_gray);
vector<Vec4f> plines;
HoughLinesP(src_gray, plines, 1, CV_PI / 180.0, 10, 0, 10);
cout << plines.size() << endl;
Scalar color = Scalar(0, 0, 255);
for (size_t i = 0; i < plines.size(); i++) {
Vec4f hline = plines[i];
line(dst, Point(hline[0], hline[1]), Point(hline[2], hline[3]), color, 3, LINE_AA);
}
imshow("【輸出圖像】", dst);
waitKey(0);
return 0;
}
4、執行結果
可以看到他把所有的直線全部都標註出來,大家也可以自己調整參數觀看效果哦。
大家也可以自己嘗試一下呀,一定要多做練習!