OpenCV霍夫變換(Hough Transform)直線檢測(cè)詳解
霍夫變換(Hough Transform)的主要思想:
一條直線在平面直角坐標(biāo)系(x-y)中可以用y=ax+b式表示,對(duì)于直線上一個(gè)確定的點(diǎn)(x0,y0),總符合y0-ax0=b,而它可以表示為參數(shù)平面坐標(biāo)系(a-b)中的一條直線。因此,圖像中的一個(gè)點(diǎn)對(duì)應(yīng)參數(shù)平面的一條直線,同樣,圖像中的一條直線對(duì)應(yīng)參數(shù)平面上的一個(gè)點(diǎn)。
基本Hough變換檢測(cè)直線:
由于同一條直線上的不同點(diǎn)在參數(shù)平面中是會(huì)經(jīng)過同一個(gè)點(diǎn)的多條線。對(duì)圖像的所有點(diǎn)作霍夫變換,檢測(cè)直線就意味著找到對(duì)應(yīng)參數(shù)平面中的直線相交最多的點(diǎn)。對(duì)這些交點(diǎn)做票數(shù)累計(jì),然后取出票數(shù)大于最小投票數(shù)的點(diǎn),即為原坐標(biāo)系里檢測(cè)出的直線。
一般,直線的參數(shù)方程為 ρ=xcosθ+ysinθ
OpenCV中的基本霍夫變換直線檢測(cè)函數(shù) cv::HoughLines:
函數(shù)輸入為一幅二值圖像(有很多待檢測(cè)點(diǎn)),其中一些點(diǎn)排列后形成直線,通常這是一幅邊緣圖像,比如來自Sobel算子或Canny算子。函數(shù)的輸出是cv::Vec2f的向量,每個(gè)元素都是一對(duì)代表檢測(cè)到的直線的浮點(diǎn)數(shù)(ρ, θ)。函數(shù)的作法是先求出原圖像中每點(diǎn)的極坐標(biāo)方程,若相交于一點(diǎn)的極坐標(biāo)曲線的個(gè)數(shù)大于最小投票數(shù),則將該點(diǎn)(ρ, θ)(參數(shù)坐標(biāo)系點(diǎn))放入輸出向量。
#include "opencv2/highgui.hpp" #include "opencv2/core.hpp" #include "opencv2/imgproc.hpp" #include <iostream> #define PI 3.1415926 class LineFinder{ private: std::vector<cv::Vec2f> lines; double deltaRho; // 參數(shù)坐標(biāo)系的步長(zhǎng)(theta表示與直線垂直的角度) double deltaTheta; int minVote; // 判斷是直線的最小投票數(shù) public: LineFinder() { deltaRho = 1; deltaTheta = PI / 180; minVote = 80; } void setAccResolution(double dRho, double dTheta) { deltaRho = dRho; deltaTheta = dTheta; } void setMinVote(int minv) { minVote = minv; } // Hough變換檢測(cè)直線;rho=1,theta=PI/180參數(shù)坐標(biāo)系里的步長(zhǎng),threshold=最小投票數(shù) void findLines(cv::Mat& binary){ lines.clear(); cv::HoughLines(binary, lines, deltaRho, deltaTheta, minVote); } void drawDetectedLines(cv::Mat& result){ std::vector<cv::Vec2f>::const_iterator it = lines.begin(); while (it != lines.end()) { // 以下兩個(gè)參數(shù)用來檢測(cè)直線屬于垂直線還是水平線 float rho = (*it)[0]; float theta = (*it)[1]; if (theta < PI / 4. || theta > 3.*PI / 4.) { // 若檢測(cè)為垂直線,直線交于圖片的上下兩邊,先找交點(diǎn) cv::Point pt1(rho / cos(theta), 0); cv::Point pt2((rho - result.rows*sin(theta)) / cos(theta), result.rows); cv::line(result, pt1, pt2, cv::Scalar(255), 1); // } else // 若檢測(cè)為水平線,直線交于圖片的左右兩邊,先找交點(diǎn) { cv::Point pt1(0, rho / sin(theta)); cv::Point pt2(result.cols, (rho - result.cols*cos(theta)) / sin(theta)); cv::line(result, pt1, pt2, cv::Scalar(255), 1); } ++it; } } }; int main(int argc, char *argv[]) { cv::Mat image = cv::imread("D:/VS_exercise/images/road1.jpg"); cv::Mat imageGray; cv::Mat contours; cv::cvtColor(image, imageGray, cv::COLOR_RGB2GRAY); cv::Canny(imageGray, contours, 190, 300); // 在原圖的拷貝上畫直線 cv::Mat result(contours.rows, contours.cols, CV_8U, cv::Scalar(255)); image.copyTo(result); // Hough變換檢測(cè) LineFinder finder; finder.setMinVote(130); finder.findLines(contours); finder.drawDetectedLines(result); // 顯示 cv::namedWindow("Detected Lines with Hough"); cv::imshow("Detected Lines with Hough", result); cv::waitKey(0); return 0; }
概率Hough變換檢測(cè)線段:
霍夫變換檢測(cè)直線的目的,是找到二值圖像中經(jīng)過足夠多數(shù)量點(diǎn)的所有直線,當(dāng)同一直線穿過許多點(diǎn),便意味著這條線的存在足夠明顯。
概率霍夫變換在原算法的基礎(chǔ)上增加了一些改動(dòng),主要是:
1. 不再系統(tǒng)地逐行掃描圖像,而是隨機(jī)挑選(輪廓圖像的)前景點(diǎn),一旦累加器中的某一項(xiàng)交點(diǎn)的票數(shù)達(dá)到給定的最小值,就搜索輪廓圖像在對(duì)應(yīng)直線上的前景點(diǎn),連成線段(要小于maxLineGap),然后記錄線段參數(shù)(起終點(diǎn)),最后刪除所有經(jīng)過的點(diǎn)(即使它們并未投過票)。
2. 概率霍夫變換定義了兩個(gè)額外的參數(shù):一個(gè)是可以接受的最小線段長(zhǎng)度(minLineLength),另一個(gè)是允許組成連續(xù)線段的最大像素間隔(maxLineGap),雖然額外步驟增加了算法的復(fù)雜度,但由于參與投票的點(diǎn)數(shù)有所減少,因此得到了一些補(bǔ)償。
openCV中的概率霍夫變換直線檢測(cè)函數(shù) cv::HoughLinesP:
函數(shù)的輸出是cv::Vec4i組成的向量,每個(gè)元素是檢測(cè)到的線段的兩個(gè)坐標(biāo)點(diǎn)(pt1x, pt1y, pt2x, pt2y)。
#include "opencv2/highgui.hpp" #include "opencv2/core.hpp" #include "opencv2/imgproc.hpp" #define PI 3.1415926 class LineFinder{ private: std::vector<cv::Vec4i> lines; double deltaRho; // 步長(zhǎng)(theta表示與直線垂直的角度) double deltaTheta; int minVote; // 判斷是直線的最小投票數(shù) double minLength; // 判斷是直線的最小線段長(zhǎng)度 double maxGap; // 允許組成連續(xù)線段的最大像素間隔 public: LineFinder() { deltaRho = 1; deltaTheta = PI / 180; minVote = 10; minLength = 0.0; maxGap = 0.0; } void setAccResolution(double dRho, double dTheta) { deltaRho = dRho; deltaTheta = dTheta; } void setMinVote(int minv) { minVote = minv; } void setLineLengthAndGap(double length, double gap) { minLength = length; maxGap = gap; } // Hough變換檢測(cè)線段 void findLines(cv::Mat& binary) { lines.clear(); cv::HoughLinesP(binary, lines, deltaRho, deltaTheta, minVote, minLength, maxGap); } void drawDetectedLines(cv::Mat &image, cv::Scalar color = cv::Scalar(255)) { std::vector<cv::Vec4i>::const_iterator it2 = lines.begin(); while (it2 != lines.end()) { cv::Point pt1((*it2)[0], (*it2)[1]); cv::Point pt2((*it2)[2], (*it2)[3]); cv::line(image, pt1, pt2, color, 1.5); //畫線段 ++it2; } } }; int main(int argc, char *argv[]) { cv::Mat image = cv::imread("D:/VS_exercise/images/road1.jpg"); cv::Mat imageGray; cv::Mat contours; cv::cvtColor(image, imageGray, cv::COLOR_RGB2GRAY); // 邊緣檢測(cè) cv::Canny(imageGray, contours, 190, 300); // Hough變換檢測(cè) LineFinder finder; finder.setMinVote(80); finder.setLineLengthAndGap(100, 10); //概率Hough變換增加的兩個(gè)參數(shù) finder.findLines(contours); finder.drawDetectedLines(image); // 顯示 cv::imshow("Detected Lines with Hough", image); cv::waitKey(0); return 0; }
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- 利用Opencv中Houghline方法實(shí)現(xiàn)直線檢測(cè)
- python opencv實(shí)現(xiàn)直線檢測(cè)并測(cè)出傾斜角度(附源碼+注釋)
- Python+OpenCV圖像處理——實(shí)現(xiàn)直線檢測(cè)
- OpenCV實(shí)現(xiàn)圖像的直線檢測(cè)
- Java+opencv3.2.0實(shí)現(xiàn)hough直線檢測(cè)
- opencv3/C++實(shí)現(xiàn)霍夫圓/直線檢測(cè)
- OpenCV利用霍夫變換進(jìn)行直線檢測(cè)
- Opencv Hough算法實(shí)現(xiàn)圖片中直線檢測(cè)
- 詳解在Python中使用OpenCV進(jìn)行直線檢測(cè)
- OpenCV實(shí)現(xiàn)直線檢測(cè)
相關(guān)文章
ubuntu系統(tǒng)vscodeC++編譯環(huán)境配置與使用方式
這篇文章主要介紹了ubuntu系統(tǒng)vscodeC++編譯環(huán)境配置與使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12