《OpenCV3编程入门》学习笔记7 图像变换(二 )霍夫变换
7.2 霍夫變換
7.2.1 概述
1.特征提取技術,運用兩個坐標空間之間的變換將在一個空間中具有相同形狀的曲線或直線映射到另一個坐標空間的一個點上形成峰值,從而把檢測任意形狀的問題轉化為統計峰值問題,用于檢測直線、曲線、圓、橢圓等。
2.分類:(1)霍夫線變換(2)霍夫圓變換
7.2.2 霍夫線變換
1.原理:
(1)直線在坐標空間的表示:
??1)笛卡爾坐標系:斜率和截距(m,b)表示
??2)極坐標系:極徑和極角(r,θ)
??霍夫變換采用極坐標系表示直線:
????????????????
??即:
?????????????????
(2)對于通過點(x0,y0)的一族直線,可表示為:
????????????????
(3)對于給定點(x0,y0),在極坐標對極徑極角平面繪出所有通過它的直線,得到一條正弦曲線,如給定點(8,6):
???????????
(4)對圖像中所有點繪制正弦曲線,如果兩個不同點曲線在平面θ-r相交,意味著它們通過同一條直線,如點(9,4)和點(12,3):
???????????
(5)上述說明,一條直線能夠通過平面θ-r尋找交于一點的曲線數量來檢測,而越多曲線交于一點表示直線由更多的點組成,可以通過設置直線上點的閾值來定義多少條曲線交于一點,才認為檢測到了一條直線
(6)所以,霍夫變換追蹤圖像中每個點對應曲線間的交點,如果交于一點的曲線數量超過閾值,可認為這個交點代表的參數對(θ,r)在原圖像中為一條直線
2.分類:
(1)標準霍夫變換(Standard Hough Transform,SHT),HoughLines函數調用
(2)多尺度霍夫變換(Multi-Scale Hough Transform,MSHT):SHT在多尺度下的變種,HoughLines調用
(3)累計概率霍夫變換(Progressive Probabilistic Hough Transform,PPHT):SHT的一個改進,在一定范圍內進行霍夫變換,計算單獨線段的方向及范圍,從而減少計算量,縮短計算時間,HoughLinesP調用
7.2.2.1 標準/多尺度霍夫變換:HoughLines()函數
1.作用:可以找出采用標準霍夫變換的二值圖像線條
2.函數原型:
void HoughLines(InputArray image, OuputArray lines, double rho, double theta, int threshold, double srn=0,double stn=0)
3.參數說明:
(1)輸入圖像,8位單通道二進制圖像
(2)檢測到線條的輸出矢量,一條線由兩個元素矢量(ρ,θ)表示,ρ是距坐標原點(0,0)距離,θ是弧度線條旋轉角度
(3)以像素為單位的距離精度,直線搜索時的進步尺寸單位半徑
(4)以弧度為單位的角度精度,直線搜索時的進步尺寸單位角度
(5)累加平面的閾值參數,識別某部分為圖中一條直線時在累加平面中必須達到的值
(6)多尺度霍夫變換中第三個參數rho的除數距離,默認值0,粗略的累加器進步尺寸直接為rho,精確的累加器進步尺寸為rho/srn
(7)多尺度霍夫變換中第四個參數theta的除數距離,默認值0,srn和stn同時為0表示使用SHT,否則兩參數都應為正數
4.調用示例:
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{//【1】載入原圖Mat srcImage = imread("1.png");Mat midImage, dstImage;//【2】進行邊緣檢測,將HoughLines函數輸入圖像處理為邊緣二值圖Canny(srcImage, midImage, 50, 200, 3);//【3】轉換邊緣檢測后的邊緣二值圖像為灰度圖cvtColor(midImage, dstImage, CV_GRAY2BGR);//【4】進行霍夫線變換vector<Vec2f>lines;//定義一個矢量結構lines用于存放得到的線性矢量集合HoughLines(midImage, lines, 1, CV_PI / 180, 150, 0, 0);//【5】依次在灰度圖中繪制出每條線段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(dstImage, pt1, pt2, Scalar(55, 100, 195), 1, LINE_AA);}//【5】顯示原始圖imshow("【原始圖】", srcImage);//【6】邊緣檢測后的圖imshow("【邊緣檢測效果圖】", midImage);//【7】顯示效果圖imshow("【霍夫線變換效果圖】", dstImage);waitKey(0);return 0;
}
運行效果:
7.2.2.2 累計概率霍夫變換:HoughLinesP()函數
1.函數原型:
void HoughLinesP(InputArray image, OuputArray lines, double rho, double theta, int threshold, double minLineLength=0, double maxLineGap=0)
2.參數說明:
(1)輸入圖像,8位單通道二進制圖像
(2)檢測到線條的輸出矢量,一條線由4個元素矢量(x_1,y_1,x_2,y_2)表示
(3)以像素為單位的距離精度,直線搜索時的進步尺寸單位半徑
(4)以弧度為單位的角度精度,直線搜索時的進步尺寸單位角度
(5)累加平面的閾值參數,識別某部分為圖中一條直線時在累加平面中必須達到的值
(6)表示最低線段的長度,默認值0,比這個設定參數短的線段不被顯現
(7)允許將同一行點與點之間連接起來的最大距離,默認值0
3.調用示例:
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{//【1】載入原始圖和Mat變量定義 Mat srcImage = imread("1.png");Mat midImage, dstImage;//【2】進行邊緣檢測,將HoughLines函數輸入圖像處理為邊緣二值圖Canny(srcImage, midImage, 50, 200, 3);//【3】轉換邊緣檢測后的邊緣二值圖像為灰度圖cvtColor(midImage, dstImage, CV_GRAY2BGR);//【4】進行累計概率霍夫線變換vector<Vec4i>lines;//定義一個矢量結構lines用于存放得到的線段矢量集合HoughLinesP(midImage, lines, 1, CV_PI / 180, 80, 50, 10);//【5】依次在圖中繪制出每條線段for (size_t i = 0; i < lines.size(); i++){Vec4i l = lines[i];line(dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186, 88, 255), 1, CV_AA);}//【6】顯示原始圖 imshow("【原始圖】", srcImage);//【7】邊緣檢測后的圖 imshow("【邊緣檢測效果圖】", midImage);//【8】顯示效果圖 imshow("【累計概率霍夫變換效果圖】", dstImage);waitKey(0);return 0;
}
運行效果:
7.2.3 霍夫圓變換
1.與霍夫線變換類似,只是點對應的二維極徑極角空間被三維的圓心點x,y,和半徑r空間取代,用三個參數表示圓:
?????????????????
2.方法:霍夫梯度法
(1)對圖像進行邊緣檢測
(2)對邊緣圖像中的每一個非零點,考慮其局部梯度,即用Sobel()函數計算x,y方向的Sobel一階導數得到的梯度
(3)利用得到的梯度,由斜率(從一個指定的最小值到指定的最大值的距離)指定的直線上的每一個點都在累加器中被累加
(4)標記邊緣圖像中每一個非0像素位置
(5)從二維累加器中這些點中選擇大于給定閾值且大于其所有近鄰的候選中心,按累加值降序排列
(6)對每個中心,考慮所有非0像素,按照像素與中心距離排序,從最大半徑的最小距離算起,選擇非0像素最支持的一條半徑
(7)如果一個中心收到邊緣圖像非0像素最充分的支持,并且到前期被選擇的中心有足夠的距離,它就會被保留
3.霍夫梯度法的缺點:
(1)Sobel導數計算局部梯度,假設它可以視作一條局部切線,數值不穩定,可能產生噪聲
(2)邊緣圖像中的整個非0像素集被看作每個中心的候選部分,如果把累加器閾值設置偏低,算法費時
(3)過于相近的中心不會被保留,同心圓或過于相似圓保留最大的圓,極端
4.函數:HoughCircles()函數
5.函數原型:
void HoughCircles(InputArray image,OutputArray circles, int method, double dp, double minDist, double param1=100, double param2=100, int minRadius=0, int maxRadius=0)
6.參數說明:
(1)輸入圖像,8位灰度單通道圖像
(2)檢測到的圓輸出矢量,每個矢量包含3個元素的浮點矢量(x,y,radius)
(3)使用的檢測方法,HOUGH_GRADIENT
(4)用來檢測圓心的累加器圖像的分辨率與輸入圖像之比的倒數,允許創建一個比輸入圖像分辨率低的累加器,如果dp=1累加器和輸入圖像具有相同的分辨率,如果dp=2累加器具有輸入圖像一半的寬度和高度
(5)霍夫變換檢測到的圓的圓心之間的最小距離,設置太小多個相鄰圓可能檢測為一個,太大某些圓不能被檢測出來
(6)第三個參數設置的檢測方法對應的參數,即霍夫梯度法,表示傳遞給canny邊緣檢測算子的高閾值,低閾值為高閾值的一半,默認100
(7)第三個參數設置的檢測方法對應的參數,即霍夫梯度法,表示在檢測階段圓心的累加器閾值。越小越可以檢測到更多不存在的圓,越大能通過檢測的圓越接近完美圓形,默認100
(8)圓半徑的最小值,默認0
(9)圓半徑的最大值,默認0
7.調用示例:
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main()
{//【1】載入原始圖和Mat變量定義 Mat srcImage = imread("1.jpg");Mat midImage, dstImage;//【2】顯示原始圖imshow("【原始圖】", srcImage);//【3】轉為灰度圖,進行圖像平滑cvtColor(srcImage, midImage, CV_BGR2GRAY);GaussianBlur(midImage, midImage, Size(9, 9), 2, 2);//【4】進行霍夫圓變換vector<Vec3f> circles;HoughCircles(midImage, circles, CV_HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);//【5】依次在圖中繪制出圓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(srcImage, center, 3, Scalar(0, 255, 0), -1, 8, 0);//繪制圓輪廓circle(srcImage, center, radius, Scalar(155, 50, 255), 3, 8, 0);}//【6】顯示效果圖 imshow("【效果圖】", srcImage);waitKey(0);return 0;
}
運行效果:
7.2.4 霍夫變換綜合示例
/*
效果:
滾動條改變閾值threshold,動態控制霍夫線變換檢測的線條多少
*/
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;//全局變量聲明
Mat g_srcImage, g_dstImage, g_midImage;//原始圖、中間圖和效果圖
vector<Vec4i> g_lines; //定義一個矢量結構g_lines用于存放得到的線段矢量集合
int g_nthreshold = 100; //變量接收的TrackBar位置參數//全局函數聲明
static void on_HoughLinesP(int, void*);
static void ShowHelpText();int main()
{//改變console字體顏色system("color 3F");ShowHelpText();//載入原始圖和Mat變量定義 Mat g_srcImage = imread("1.jpg");//顯示原始圖 imshow("【原始圖】", g_srcImage);//創建滾動條namedWindow("【效果圖】", 1);createTrackbar("值", "【效果圖】", &g_nthreshold, 150, on_HoughLinesP);//進行邊緣檢測和轉化為灰度圖Canny(g_srcImage, g_midImage, 50, 200, 3); //進行一次canny邊緣檢測cvtColor(g_midImage, g_dstImage, CV_GRAY2BGR);//轉化邊緣檢測后的圖為灰度圖//調用一次回調函數,調用一次HoughLinesP函數on_HoughLinesP(g_nthreshold, 0);waitKey(0);return 0;
}//累計概率霍夫變換回調函數
static void on_HoughLinesP(int, void*)
{//定義局部變量儲存全局變量Mat dstImage = g_dstImage.clone();Mat midImage = g_midImage.clone();//調用HoughLinesP函數vector<Vec4i> mylines;HoughLinesP(midImage, mylines, 1, CV_PI / 180, g_nthreshold + 1, 50, 10);//循環遍歷繪制每一條線段for (size_t i = 0; i < mylines.size(); i++){Vec4i l = mylines[i];line(dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(23, 180, 55), 1, CV_AA);}//顯示圖像imshow("【效果圖】", dstImage);
}//ShowHelpText( )函數
static void ShowHelpText()
{//輸出一些幫助信息printf("\n\n\n\t請調整滾動條觀察圖像效果~\n\n");
}
運行效果:
總結
以上是生活随笔為你收集整理的《OpenCV3编程入门》学习笔记7 图像变换(二 )霍夫变换的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 女人不孕不育的症状有哪些
- 下一篇: 《OpenCV3编程入门》学习笔记7 图