Hough Transform using OpenCV
一般在偵測霍夫線前會有前處理動作邊緣偵測
,而霍夫圓不用,因為該API已包含此功能。
要計算線可使用卡迪爾座標系統(Cartesian coordinate system)及極座標系統(Polar coordinate system)
卡迪爾座標的線公式 = y = kx + b
© from OpenCV
極座標的線公式 = r = xcosθ + ysinθ
OpenCV提供兩個API供開發者使用:
- The Standard Hough Transform
HoughLines
- The Probabilistic Hough Line Transform
HoughLinesP
兩者之間的差別在於
© from OpenCV
void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )
image
輸入影像lines
輸出結果(r,θ),r是代表到原點的距離(影像的左上角為原點),θ是角度rho
極坐標中極徑r的最小單位theta
極坐標中極角Ɵ的最小單位threshold
門檻值srn
多尺度霍夫轉換rho的分母stn
多尺度霍夫轉換theta的分母
cv::Mat grayImg, cannyImg;
cv::cvtColor( srcImg, grayImg, cv::COLOR_BGR2GRAY );
cv::Canny(grayImg, cannyImg, 50, 150, 3);
cv::Mat houghImg;
std::vector<cv::Vec2f> lines;
cv::cvtColor( cannyImg, houghImg, cv::COLOR_GRAY2BGR );
cv::HoughLines(cannyImg, lines, 1, CV_PI/180, 250, 0, 0 );
for( size_t i = 0; i < lines.size(); i++ )
{
float rho = lines[i][0], theta = lines[i][1];
cv::Point pt1, pt2;
double a = std::cos(theta), b = std::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));
cv::line( houghImg, pt1, pt2, cv::Scalar(0,0,255), 3, cv::LINE_AA);
}
void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength=0, double maxLineGap=0 )
image
輸入影像lines
輸出結果(x_1, y_1, x_2, y_2),(x_1,y_1)及(x_2, y_2)來表示線的兩端點rho
極坐標中極徑r的最小單位theta
極坐標中極角Ɵ的最小單位threshold
門檻值minLineLength
線小於此門檻值將不列入考慮maxLineGap
線與線之間的間隔不得超過此門檻值
cv::Mat grayImg, cannyImg;
cv::cvtColor( srcImg, grayImg, cv::COLOR_BGR2GRAY );
cv::Canny(grayImg, cannyImg, 50, 150, 3);
cv::Mat houghImg;
std::vector<cv::Vec2f> lines;
cv::cvtColor( cannyImg, houghImg, cv::COLOR_GRAY2BGR );
cv::HoughLines(cannyImg, lines, 1, CV_PI/180, 250, 0, 0 );
std::vector<cv::Vec4i> linesP;
cv::HoughLinesP(cannyImg, linesP, 1, CV_PI/180, 50, 100, 5 );
for( size_t i = 0; i < linesP.size(); i++ )
{
cv::Vec4i l = linesP[i];
cv::line( houghImg, cv::Point(l[0], l[1]), cv::Point(l[2], l[3]), cv::Scalar(255,0,0), 3, CV_AA);
}
void HoughCircles(InputArray image, OutputArray circles, int method, double dp, double minDist, double param1=100, double param2=100, int minRadius=0, int maxRadius=0 )
image
輸入影像circles
輸出結果 (x, y, radius)method
目前支援CV_HOUGH_GRADIENTdp
累加器圖像的解析度minDist
兩個圓之間的距離(值太小可能會產生很多鄰近的圓出現,反之,太大則有可能會沒偵測到某些圓)param1
cv::Canny()的參數,此值代表上限門檻,而下限則為上限的一半param2
累加器的門檻值minRadius
最小圓半徑maxRadius
最大圓半徑
cv::Mat grayImg, cannyImg;
cv::cvtColor( srcImg, grayImg, cv::COLOR_BGR2GRAY );
cv::Mat houghImg;
cv::cvtColor( cannyImg, houghImg, cv::COLOR_GRAY2BGR );
std::vector<cv::Vec3f> circles;
cv::HoughCircles(grayImg, circles, cv::HOUGH_GRADIENT, 2, grayImg.rows/4, 200, 100 );
for( size_t i = 0; i < circles.size(); i++ )
{
cv::Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
circle( houghImg, center, 3, cv::Scalar(0,255,0), -1, 8, 0 );
circle( houghImg, center, radius, cv::Scalar(0,0,255), 3, 8, 0 );
}
偵測結果如下:
原圖
HoughLines
HoughLinesP
HoughCircles
詳細Sample Code請參考GitHub