OpenCV(十八)霍夫变换(直线、线段与圆检测)
目錄
一、基礎(chǔ)理論
1、作用:
2、定義
3、原理
二、直線檢測
?1、基礎(chǔ)理論
?1、原理
2、過程
2、HoughLines函數(shù)(直線檢測)
3、HoughLinesP函數(shù)(線段檢測)
三、圓檢測
1、基礎(chǔ)理論
1、概念
?2、原理
2、HoughCircles函數(shù)
C++ API:?
python API:
總代碼
參考資料
一、基礎(chǔ)理論
1、作用:
提取直線和圓等幾何形狀。
2、定義
霍夫變換(Hough Transform)是圖像處理中的一種特征提取技術(shù),它通過一種投票算法檢測具有特定形狀的物體。Hough變換是圖像處理中從圖像中識別幾何形狀的基本方法之一。Hough變換的基本原理在于利用點(diǎn)與線的對偶性,將原始圖像空間的給定的曲線通過曲線表達(dá)形式變?yōu)?strong>參數(shù)空間的一個(gè)點(diǎn)。這樣就把原始圖像中給定曲線的檢測問題轉(zhuǎn)化為尋找參數(shù)空間中的峰值問題。也即把檢測整體特性轉(zhuǎn)化為檢測局部特性。比如直線、橢圓、圓、弧線等。
????????原則上霍夫變換可以檢測任何形狀,但復(fù)雜的形狀需要的參數(shù)就多,霍夫空間的維數(shù)就多,因此在程序?qū)崿F(xiàn)上所需的內(nèi)存空間以及運(yùn)行效率上都不利于把標(biāo)準(zhǔn)霍夫變換應(yīng)用于實(shí)際復(fù)雜圖形的檢測中。霍夫梯度法是霍夫變換的改進(jìn)(圓檢測),它的目的是減小霍夫空間的維度,提高效率。
3、原理
直線檢測原理:將要檢測的對象轉(zhuǎn)到霍夫空間中,利用累加器找到最優(yōu)解,即為所求直線。
(注:檢測前要對圖像二值化處理)
圓檢檢測原理:霍夫梯度法,找到達(dá)到閾值的原點(diǎn)和半徑。
兩個(gè)點(diǎn)決定直線的斜率和截距情況:
三個(gè)點(diǎn)決定直線斜率和截距情況:
極坐標(biāo)系:
求出了“極坐標(biāo)”空間下相交的點(diǎn),自然也就可以用哪個(gè)和求出直線的三個(gè)點(diǎn)坐標(biāo)。
?
得到曲線:采用不同的遍歷值
?使用累加器檢測直線:
累加器是一個(gè)二維數(shù)組。
二、直線檢測
?1、基礎(chǔ)理論
霍夫變換 (Hough Line Transform) 是圖像處理中的一種特征提取技術(shù). 通過平面空間到極值坐標(biāo)空間的轉(zhuǎn)換, 可以幫助我們實(shí)現(xiàn)直線檢測
?1、原理
1、首先邊緣檢測,得到許多點(diǎn)
2、遍歷第一個(gè)點(diǎn)的各個(gè)方向的,得到第一個(gè)點(diǎn)的曲線
3、遍歷每一個(gè)點(diǎn),得到多條曲線
4、多曲線相交,就是最終的和,通過它可以確定最終直線
(左:笛卡爾坐標(biāo)系? ? ? ? 右:霍夫空間)????????
2、過程
1、首先邊緣檢測,得到許多點(diǎn)
2、遍歷第一個(gè)點(diǎn)的各個(gè)方向的,得到第一個(gè)點(diǎn)的曲線
???????
3、遍歷每一個(gè)點(diǎn),得到多條曲線
4、多曲線相交,就是最終的和,通過它可以確定最終直線
2、HoughLines函數(shù)(直線檢測)
HoughLines函數(shù):
void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )
- 第一個(gè)參數(shù),InputArray類型的image,輸入圖像,即源圖像,需為8位的單通道二進(jìn)制圖像,可以將任意的源圖載入進(jìn)來后由函數(shù)修改成此格式后,再填在這里。
- 第二個(gè)參數(shù),InputArray類型的lines,經(jīng)過調(diào)用HoughLines函數(shù)后儲存了霍夫線變換檢測到線條的輸出矢量。每一條線由具有兩個(gè)元素的矢量表示,其中,是離坐標(biāo)原點(diǎn)((0,0)(也就是圖像的左上角)的距離。?是弧度線條旋轉(zhuǎn)角度(0~垂直線,π/2~水平線)。
- 第三個(gè)參數(shù),double類型的rho,以像素為單位的距離精度。另一種形容方式是直線搜索時(shí)的進(jìn)步尺寸的單位半徑。PS:Latex中/rho就表示?。
- 第四個(gè)參數(shù),double類型的theta,以弧度為單位的角度精度。另一種形容方式是直線搜索時(shí)的進(jìn)步尺寸的單位角度。
- 第五個(gè)參數(shù),int類型的threshold,累加平面的閾值參數(shù),即識別某部分為圖中的一條直線時(shí)它在累加平面中必須達(dá)到的值。大于閾值threshold的線段才可以被檢測通過并返回到結(jié)果中。
- 第六個(gè)參數(shù),double類型的srn,有默認(rèn)值0。對于多尺度的霍夫變換,這是第三個(gè)參數(shù)進(jìn)步尺寸rho的除數(shù)距離。粗略的累加器進(jìn)步尺寸直接是第三個(gè)參數(shù)rho,而精確的累加器進(jìn)步尺寸為rho/srn。
- 第七個(gè)參數(shù),double類型的stn,有默認(rèn)值0,對于多尺度霍夫變換,srn表示第四個(gè)參數(shù)進(jìn)步尺寸的單位角度theta的除數(shù)距離。且如果srn和stn同時(shí)為0,就表示使用經(jīng)典的霍夫變換。否則,這兩個(gè)參數(shù)應(yīng)該都為正數(shù)。
HoughLines(dst, lines, 1, CV_PI / 180, 150);// 距離精度(像素) 角度精度(弧度) 累加平面閾值
//霍夫直線檢測
void Hough_Line()
{//1、邊緣檢測Canny(src, dst, 50, 200, 3);imshow("canny edge", dst);//2、霍夫變換vector<Vec2f> lines; //定義一個(gè)矢量結(jié)構(gòu)lines用于存放得到的線段矢量集合 HoughLines(dst, lines, 1, CV_PI / 180, 150);// 距離精度(像素) 角度精度(弧度) 累加平面閾值 //3、依次繪制每條線段for (size_t i = 0; i < lines.size(); i++){float rho = lines[i][0], theta = lines[i][1]; //距離精度、角度精度Point pt1, pt2; //定義兩點(diǎn)p1和p2double a = cos(theta), b = sin(theta); //a:cos b:sin//以x0和y0作為參照點(diǎn),求出(x1, y1)和(x2, y2)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(200, 0, 0), 3); //繪制直線}imshow("Hough", dst);
}
3、HoughLinesP函數(shù)(線段檢測)
HoughLinesP函數(shù):
此函數(shù)在HoughLines的基礎(chǔ)上末尾加了一個(gè)代表Probabilistic(概率)的P,表明它可以采用累計(jì)概率霍夫變換(PPHT)來找出二值圖像中的線段。
void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength=0, double maxLineGap=0 )
- 第一個(gè)參數(shù),InputArray類型的image,輸入圖像,即源圖像,需為8位的單通道二進(jìn)制圖像,可以將任意的源圖載入進(jìn)來后由函數(shù)修改成此格式后,再填在這里。
- 第二個(gè)參數(shù),InputArray類型的lines,經(jīng)過調(diào)用HoughLinesP函數(shù)后后存儲了檢測到的線條的輸出矢量,每一條線由具有四個(gè)元素的矢量(x_1,y_1, x_2, y_2)??表示,其中,(x_1, y_1)和(x_2, y_2)?是是每個(gè)檢測到的線段的結(jié)束點(diǎn)。
- 第三個(gè)參數(shù),double類型的rho,以像素為單位的距離精度。另一種形容方式是直線搜索時(shí)的進(jìn)步尺寸的單位半徑。
- 第四個(gè)參數(shù),double類型的theta,以弧度為單位的角度精度。另一種形容方式是直線搜索時(shí)的進(jìn)步尺寸的單位角度。
- 第五個(gè)參數(shù),int類型的threshold,累加平面的閾值參數(shù),即識別某部分為圖中的一條直線時(shí)它在累加平面中必須達(dá)到的值。大于閾值threshold的線段才可以被檢測通過并返回到結(jié)果中。
- 第六個(gè)參數(shù),double類型的minLineLength,有默認(rèn)值0,表示最低線段的長度,比這個(gè)設(shè)定參數(shù)短的線段就不能被顯現(xiàn)出來。
- 第七個(gè)參數(shù),double類型的maxLineGap,有默認(rèn)值0,允許將同一行點(diǎn)與點(diǎn)之間連接起來的最大的距離。
HoughLinesP(dst, lines, 1, CV_PI / 180, 80, 50, 10);// 距離精度(像素) 角度精度(弧度) 累加平面閾值 最低線段長度 同一行點(diǎn)與點(diǎn)連接的最大距離
//霍夫線段檢測
void Hough_LineP()
{//1、邊緣檢測Canny(src, dst, 50, 200, 3);imshow("canny edge", dst);//2、霍夫變換vector<Vec4i> lines; //定義一個(gè)矢量結(jié)構(gòu)lines用于存放得到的線段矢量集合 HoughLinesP(dst, lines, 1, CV_PI / 180, 80, 50, 10);// 距離精度(像素) 角度精度(弧度) 累加平面閾值 最低線段長度 同一行點(diǎn)與點(diǎn)連接的最大距離//3、依次繪制每條線段for (size_t i = 0; i < lines.size(); i++){Vec4i l = lines[i];line(dst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(255, 0, 0), 3);}imshow("Hough", dst);
}
?
三、圓檢測
1、基礎(chǔ)理論
1、概念
??
霍夫圓變換 (Hough Circle Transform) 的原理和霍夫直線變換類似. 對于一條直線, 我們可以用參數(shù)表示, 對于圓我們需要三個(gè)參數(shù) ?,分別代表三個(gè)參數(shù) 圓心(x, y), r半徑。?(也叫霍夫梯度法)
因?yàn)榛舴驁A檢測對噪聲比較敏感, 所以首先要對圖像做中值濾波。
?2、原理
霍夫變換圓檢測是基于圖像梯度實(shí)現(xiàn):
圓心檢測的原理︰圓心是圓周法線的交匯處,設(shè)置一個(gè)閾值,在某點(diǎn)的相交的直線的條數(shù)大于這個(gè)閾值就認(rèn)為該交匯點(diǎn)為圓心。
圓半徑確定原理:圓心到圓周上的距離〔半徑)是相同的,設(shè)置一個(gè)閾值,只要相同距離的數(shù)量大于該閾值,就認(rèn)為該距離是該圓心的半徑。
(霍夫圓檢測里面包含有canny邊緣檢測)
2、HoughCircles函數(shù)
C++ API:?
void HoughCircles(InputArray image,OutputArray circles, int method, double dp, double minDist, double param1=100,double param2=100, int minRadius=0, int maxRadius=0 )
- 第一個(gè)參數(shù),InputArray類型的image,輸入圖像,即源圖像,需為8位的灰度單通道圖像。
- 第二個(gè)參數(shù),InputArray類型的circles,經(jīng)過調(diào)用HoughCircles函數(shù)后此參數(shù)存儲了檢測到的圓的輸出矢量,每個(gè)矢量由包含了3個(gè)元素的浮點(diǎn)矢量(x, y, radius)表示。
- 第三個(gè)參數(shù),int類型的method,即使用的檢測方法,目前OpenCV中就霍夫梯度法一種可以使用,它的標(biāo)識符為CV_HOUGH_GRADIENT,在此參數(shù)處填這個(gè)標(biāo)識符即可。
- 第四個(gè)參數(shù),double類型的dp,用來檢測圓心的累加器圖像的分辨率于輸入圖像之比的倒數(shù),且此參數(shù)允許創(chuàng)建一個(gè)比輸入圖像分辨率低的累加器。上述文字不好理解的話,來看例子吧。例如,如果dp= 1時(shí),累加器和輸入圖像具有相同的分辨率。如果dp=2,累加器便有輸入圖像一半那么大的寬度和高度。
- 第五個(gè)參數(shù),double類型的minDist,為霍夫變換檢測到的圓的圓心之間的最小距離,即讓我們的算法能明顯區(qū)分的兩個(gè)不同圓之間的最小距離。這個(gè)參數(shù)如果太小的話,多個(gè)相鄰的圓可能被錯(cuò)誤地檢測成了一個(gè)重合的圓。反之,這個(gè)參數(shù)設(shè)置太大的話,某些圓就不能被檢測出來了。
- 第六個(gè)參數(shù),double類型的param1,有默認(rèn)值100。它是第三個(gè)參數(shù)method設(shè)置的檢測方法的對應(yīng)的參數(shù)。對當(dāng)前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示傳遞給canny邊緣檢測算子的高閾值,而低閾值為高閾值的一半。
- 第七個(gè)參數(shù),double類型的param2,也有默認(rèn)值100。它是第三個(gè)參數(shù)method設(shè)置的檢測方法的對應(yīng)的參數(shù)。對當(dāng)前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示在檢測階段圓心的累加器閾值。它越小的話,就可以檢測到更多根本不存在的圓,而它越大的話,能通過檢測的圓就更加接近完美的圓形了。
- 第八個(gè)參數(shù),int類型的minRadius,有默認(rèn)值0,表示圓半徑的最小值。
- 第九個(gè)參數(shù),int類型的maxRadius,也有默認(rèn)值0,表示圓半徑的最大值。
HoughCircles(dst, circles, HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);// 霍夫梯度法 dp 圓心間最小距離 高閾值 累加閾值 圓半徑最小、最大值
python API:
def HoughCircles(image: Any,method: Any,dp: Any,minDist: Any,circles: Any = None,param1: Any = None,param2: Any = None,minRadius: Any = None,maxRadius: Any = None) -> None參數(shù):?
- 第二個(gè)參數(shù),int類型的method,即使用的檢測方法,目前OpenCV中就霍夫梯度法一種可以使用,它的標(biāo)識符為CV_HOUGH_GRADIENT,在此參數(shù)處填這個(gè)標(biāo)識符即可。
- 第三個(gè)參數(shù),double類型的dp,用來檢測圓心的累加器圖像的分辨率于輸入圖像之比的倒數(shù),且此參數(shù)允許創(chuàng)建一個(gè)比輸入圖像分辨率低的累加器。上述文字不好理解的話,來看例子吧。例如,如果dp= 1時(shí),累加器和輸入圖像具有相同的分辨率。如果dp=2,累加器便有輸入圖像一半那么大的寬度和高度。
- 第四個(gè)參數(shù),double類型的minDist,為霍夫變換檢測到的圓的圓心之間的最小距離,即讓我們的算法能明顯區(qū)分的兩個(gè)不同圓之間的最小距離。這個(gè)參數(shù)如果太小的話,多個(gè)相鄰的圓可能被錯(cuò)誤地檢測成了一個(gè)重合的圓。反之,這個(gè)參數(shù)設(shè)置太大的話,某些圓就不能被檢測出來了。
- 第五個(gè)參數(shù),InputArray類型的circles,經(jīng)過調(diào)用HoughCircles函數(shù)后此參數(shù)存儲了檢測到的圓的輸出矢量,每個(gè)矢量由包含了3個(gè)元素的浮點(diǎn)矢量(x, y, radius)表示。
- 第六個(gè)參數(shù),double類型的param1,有默認(rèn)值100。它是第三個(gè)參數(shù)method設(shè)置的檢測方法的對應(yīng)的參數(shù)。對當(dāng)前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示傳遞給canny邊緣檢測算子的高閾值,而低閾值為高閾值的一半。
- 第七個(gè)參數(shù),double類型的param2,也有默認(rèn)值100。它是第三個(gè)參數(shù)method設(shè)置的檢測方法的對應(yīng)的參數(shù)。對當(dāng)前唯一的方法霍夫梯度法CV_HOUGH_GRADIENT,它表示在檢測階段圓心的累加器閾值。它越小的話,就可以檢測到更多根本不存在的圓,而它越大的話,能通過檢測的圓就更加接近完美的圓形了。
- 第八個(gè)參數(shù),int類型的minRadius,有默認(rèn)值0,表示圓半徑的最小值。
- 第九個(gè)參數(shù),int類型的maxRadius,也有默認(rèn)值0,表示圓半徑的最大值。
//霍夫圓檢測
void Hough_Circle()
{//1、轉(zhuǎn)化為灰度圖并圖像平滑cvtColor(src, gray, COLOR_BGR2GRAY);GaussianBlur(gray, dst, Size(9, 9), 2, 2);imshow("濾波", dst);//2、霍夫圓變換(用灰度圖)vector<Vec3f> circles;HoughCircles(dst, circles, HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);// 霍夫梯度法 dp 圓心間最小距離 高閾值 累加閾值 圓半徑最小、最大值 //3、依次在圖中繪制出圓 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(src, center, 3, Scalar(0, 255, 255), -1);//繪制圓輪廓 circle(src, center, radius, Scalar(0, 255, 255), 3);}imshow("Hough", src);
}
最佳地匹配每個(gè)圖像,參數(shù)不一樣?
HoughCircles(dst, circles, HOUGH_GRADIENT, 1.5, 10, 50, 100, 0, 0);
HoughCircles(dst, circles, HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);
總代碼
//霍夫變換(直線和圓檢測)
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include<vector>using namespace cv;
using namespace std;Mat src, dst, gray;//霍夫直線檢測(不推薦)
void Hough_Line()
{//1、邊緣檢測Canny(src, dst, 50, 200, 3);imshow("canny edge", dst);//2、霍夫變換vector<Vec2f> lines; //定義一個(gè)矢量結(jié)構(gòu)lines用于存放得到的線段矢量集合 HoughLines(dst, lines, 1, CV_PI / 180, 150);// 距離精度(像素) 角度精度(弧度) 累加平面閾值 //3、依次繪制每條線段for (size_t i = 0; i < lines.size(); i++){float rho = lines[i][0], theta = lines[i][1]; //距離精度、角度精度Point pt1, pt2; //定義兩點(diǎn)p1和p2double a = cos(theta), b = sin(theta); //a:cos b:sin//以x0和y0作為參照點(diǎn),求出(x1, y1)和(x2, y2)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(200, 0, 0), 3); //繪制直線}imshow("Hough", dst);
}//霍夫線段檢測(推薦)
void Hough_LineP()
{//1、邊緣檢測Canny(src, dst, 50, 200, 3);imshow("canny edge", dst);//2、霍夫變換vector<Vec4i> lines; //定義一個(gè)矢量結(jié)構(gòu)lines用于存放得到的線段矢量集合 HoughLinesP(dst, lines, 1, CV_PI / 180, 80, 100, 10);// 距離精度(像素) 角度精度(弧度) 累加平面閾值 最低線段長度 同一行點(diǎn)與點(diǎn)連接的最大距離//3、依次繪制每條線段for (size_t i = 0; i < lines.size(); i++){Vec4i l = lines[i];line(dst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(255, 0, 0), 3);}imshow("Hough", dst);
}//霍夫圓檢測
void Hough_Circle()
{//1、轉(zhuǎn)化為灰度圖并圖像平滑cvtColor(src, gray, COLOR_BGR2GRAY);GaussianBlur(gray, dst, Size(9, 9), 2, 2);imshow("濾波", dst);//2、霍夫圓變換(用灰度圖)vector<Vec3f> circles;HoughCircles(dst, circles, HOUGH_GRADIENT, 1.5, 10, 50, 100, 0, 0);// 霍夫梯度法 dp 圓心間最小距離 高閾值 累加閾值 圓半徑最小、最大值 //HoughCircles(dst, circles, HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);//3、依次在圖中繪制出圓 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(src, center, 3, Scalar(0, 0, 255), -1);//繪制圓輪廓 circle(src, center, radius, Scalar(0, 0, 255), 3);}imshow("Hough", src);
}int main()
{src = imread("Resource/4.jpg");imshow("原圖", src);Hough_Line(); //霍夫直線檢測Hough_LineP(); //霍夫線段檢測Hough_Circle(); //霍夫圓檢測waitKey(0);return 0;
}
參考資料
https://blog.csdn.net/zhu_hongji/article/details/81632611
【OpenCV】 ??高手勿入! 半小時(shí)學(xué)會基本操作 13?? 直線檢測_我是小白呀的博客-CSDN博客
OpenCV之霍夫變換_天下對手教會少林武僧-CSDN博客_opencv霍夫變換
Opencv2.4學(xué)習(xí)::邊緣檢測(5)Canny算法_dieju8330的博客-CSDN博客_canny
邊緣檢測-Canny_今天你學(xué)習(xí)了嗎?-CSDN博客
黑馬程序員人工智能教程_10小時(shí)學(xué)會圖像處理OpenCV入門教程_嗶哩嗶哩_bilibili
總結(jié)
以上是生活随笔為你收集整理的OpenCV(十八)霍夫变换(直线、线段与圆检测)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV(十六)边缘检测2 -- L
- 下一篇: OpenCV(十七)边缘检测3 -- C