opencv(17)---霍夫變換以及應用
基本概念
霍夫變換(Hough Transform)是影象處理中的一種特徵提取技術, 該過程在一個引數空間中通過計算累計結果的區域性最大值得到一個符合該特定形狀的集合作為霍夫變換的結果。
霍夫變換在OpenCV中主要分兩種:
霍夫線變換—檢測直線(線段)
霍夫圓變換—檢測圓- 用到的函式:
HoughLines()—標準霍夫變換、多尺度霍夫變換
HoughLinesP()—累計概率霍夫變換
HoughCricles()—霍夫圓變換
霍夫線變換
基本概念
霍夫線變換是一種尋找直線的方法, 一般在使用霍夫變換前首先將影象進行邊緣檢測處理, 一般霍夫變換的輸入為邊緣二值圖。
OpenCV支援三種不同的霍夫線變換
- 標準霍夫變換(SHT)
- 多尺度霍夫變換(MSHT)——是SHT在多尺度下的一個變種
- 累計概率霍夫變換(PPHT)——是SHT的改進, 在一定範圍內進行霍夫變換(減少 計算時間和運算量)
使用函式對應關係
- 標準霍夫變換(SHT)——HoughLines()函式
- 多尺度霍夫變換(MSHT)——HoughLines()函式
- 累計概率霍夫變換(PPHT)——HoughLinesP()函式
原理
霍夫線變換__標準霍夫變換—HoughLines()
函式原型
void 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 );
- src: 輸入原影象(一般為8位單通道二值影象)
- lines: 經過霍夫變換後檢測線條的輸出向量, 每一條線由兩個元素的向量(ρ, Θ)表示, 其中ρ是離座標原點的距離, Θ是弧度線條旋轉角度(0表示垂直線, π/2度表示水平線)
- rho: 以畫素為單位的距離精度, 另一種表述方式是直線搜尋時的進步尺寸的單位半徑
- theta: 以弧度為單位的角度精度, 另一種表述方式是直線搜尋時的進步尺寸的角度單位
- threshold: 累加平面的閾值引數, 即識別某部分為一條直線時它在累加平面中必須達到的值, 大於閾值threshold的線段才可以被檢測通過並返回到結果中
- srn: 預設值0, 對於多尺度的霍夫變換, 這是第三個引數進步尺寸rho的除數距離
- stn: 預設值0, 對於多尺度霍夫變換, 表示單位角度theta
- @param min_theta For standard and multi-scale Hough transform, minimum angle to check for lines.
Must fall between 0 and max_theta. - @param max_theta For standard and multi-scale Hough transform, maximum angle to check for lines.
Must fall between min_theta and CV_PI.
程式碼
Mat cannyImg;
Mat src = imread("D:\\1.png");
Mat dstImg = src.clone();
imshow("src", src);
//將影象轉為灰度圖
cvtColor(src, src, CV_BGR2GRAY);
//邊緣檢測
Canny(src, cannyImg, 50, 200, 3);
imshow("Canny", cannyImg);
//定義向量結構lines用於存放得到的線段向量集合
vector<Vec2f> lines;
//霍夫變換
HoughLines(cannyImg, lines, 1, CV_PI/180, 150, 0, 0);
//lines上有很多條線,線的個數為lines.size()
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(dstImg, pt1, pt2, Scalar(0, 0, 255), 1, CV_AA);
}
imshow("dst", dstImg);
waitKey(0);
destroyAllWindows();
執行結果
霍夫線變換__累計概率霍夫變換—HoughLinesP()
函式原型
void HoughLinesP( InputArray image, OutputArray lines,
double rho, double theta, int threshold,
double minLineLength = 0, double maxLineGap = 0 );
- src: 輸入原影象(一般為8位單通道二值影象)
- lines: 經過霍夫變換後檢測線條的輸出向量, 每一條線由4個元素向量(x_1,y_1,x_2,y_2)表示, 其中(x_1,y_1)和(x_2,y_2)是檢測到線段的結束點
rho: 以畫素為單位的距離精度, 另一種表述方式是直線搜尋時的進步尺寸的單位半徑 - theta: 以弧度為單位的角度精度, 另一種表述方式是直線搜尋時的進步尺寸的角度單位
- threshold: 累加平面的閾值引數, 即識別某部分為一條直線時它在累加平面中必須達到的值, 大於閾值threshold的線段才可以被檢測通過並返回到結果中
- minLineLength: 預設值0, 表示最低線段的長度, 小於則不顯示
- maxLineGap: 預設值0, 允許將同一行點與點之間連線起來的最大距離
程式碼
Mat cannyImg;
Mat src = imread("D:\\B.jpg");
Mat dstImg = src.clone();
imshow("src", src);
cvtColor(src, src, CV_BGR2GRAY);
Canny(src, cannyImg, 50, 200, 3);
vector<Vec4i> lines; //定義向量結構lines用於存放得到的線段向量集合
HoughLinesP(cannyImg, lines, 1, CV_PI/180, 150, 50, 10);
for(size_t i = 0; i<lines.size(); i++)
{
Vec4i l = lines[i];
line(dstImg, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 255, 0), 2, CV_AA);
}
imshow("dst", dstImg);
waitKey(0);
destroyAllWindows();
執行結果
霍夫圓變換
霍夫圓變換的基本原理和霍夫線變換大體上類似, 只是點對應的二維極徑極角空間被三維的圓心點x, y和半徑r空間取代, 如果用完全一樣的方法運算量較大, 執行速度較慢, 所以採用“霍夫梯度法”來做圓變換。
原理
霍夫梯度法的缺點
- 可能在輸出結果中產生噪聲
- 如果累加器閾值設定較低, 演算法需要較長時間, 每一箇中心只選擇一個圓, 對於同心圓只選擇一個
- 如果新的中心很接近已接受的中心, 則不會被保留下來
函式原型
HoughCircles( InputArray image, OutputArray circles,
int method, double dp, double minDist,
double param1 = 100, double param2 = 100,
int minRadius = 0, int maxRadius = 0 );
src: 輸入原影象(一般為8位單通道影象)
circles: 經過霍夫變換後檢測圓的輸出向量, 每個向量包含三個元素的浮點向量(x, y, radius)
dp: 用來檢測圓心的累加器影象的解析度與輸入影象之比的倒數, 且此引數允許建立一個比輸入影象解析度低的累加器。
dp=1, 累加器和輸入如下具有相同解析度;
dp=2, 累加器只有輸入影象一半大的寬度和高度minDist: 霍夫變換檢測到圓的圓心之間的最小距離, 分辨兩個不同圓
param1: 預設值100, 它是第三個引數method設定的對應引數, 表示傳遞給Canny邊緣運算元的高閾值, 低閾值是高閾值的一半
param2: 預設值100,它是第三個引數method設定的對應引數, 表示檢測階段圓心累加器閾值, 越小, 則會檢測到越多不存在的圓, 越大, 更多真正的圓被檢測到
minRadius/maxRadius: 表示圓半徑的最小值/最大值
程式碼
Mat src = imread("D:\\2.png");
Mat dst = src.clone();
imshow("src", src);
cvtColor(src, src, CV_BGR2GRAY);
GaussianBlur(src, src, Size(9, 9), 2, 2);
vector<Vec3f> circles;
HoughCircles(src, circles, CV_HOUGH_GRADIENT, 2, 30, 200, 100, 10, 200);
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(dst, center, 3, Scalar(0, 0, 255), -1, 8, 0);
circle(dst, center, radius, Scalar(0, 255, 0), 3, 8, 0);
}
imshow("dst", dst);
waitKey(0);
執行結果
應用
1.角點檢測:檢測四邊形
2.直線:檢測車道
3.圓:交通燈檢測