一、原理
對于霍夫變換的原理這里就不進行描述啦,感興趣的可以自行搜索。也可以看知乎上面的這篇貼文通俗易懂理解——霍夫變換原理。
二、算法代碼
/*
*參數(shù)說明:
*src:待檢測的原圖像
*rho:以像素為單位的距離分辨率,即距離r離散時的單位長度
*theat:以角度為單位的距離分辨率,即角度Θ離散時的單位長度
*Threshold:累加器閾值,參數(shù)空間中離散化后每個方格被通過的
累計次數(shù)大于該閾值,則該方格代表的直線被視為在
原圖像中存在
*lines:檢測到的直線極坐標描述的系數(shù)數(shù)組,每條直線由兩個參
數(shù)表示,分別為直線到原點的距離r和原點到直線的垂線與
x軸的夾角Θ
*/
void myHoughLines(Mat &src,double rho,double theat,int Threshold,vector<Vec2f> &lines)
{
if (src.empty()|| rho<0.1 || theat>360|| theat<0)
return ;
int row = src.rows;
int col = src.cols;
Mat gray;
if (src.channels() > 1)
{//灰度化
cvtColor(src, gray, COLOR_BGR2GRAY);
}
else
src.copyTo(gray);
int maxDistance = sqrt(src.cols*src.cols + src.rows*src.rows);
int houghMat_cols = 360 / theat;//霍夫變換后距離夾角坐標下對應(yīng)的Mat的寬
int houghMat_rows = maxDistance / rho;//霍夫坐標距離夾角下對應(yīng)的Mat的高
Mat houghMat = Mat::zeros(houghMat_rows, houghMat_cols, CV_32FC1);
//邊緣檢測
Canny(gray, gray, 100, 200, 3);
//二值化
threshold(gray, gray, 160, 255, THRESH_BINARY);
//遍歷二值化后的圖像
for (int i = 0;i < row;i++)
{
for (int j = 0;j < col;j++)
{
if (gray.ptr<uchar>(i)[j] != 0)
{
/*從0到360度遍歷角度,得到一組關(guān)于距離夾角的離散點,即得到
一組關(guān)于經(jīng)過當(dāng)前點(i,j)按單位角度theat旋轉(zhuǎn)得到的直線*/
for (int k = 0;k < 360/ theat;k += theat)
{
double r = i*sin(k*CV_PI / 180) + j*cos(k*CV_PI / 180);
if (r >= 0)
{//直線到原點的距離必須大于0
//獲得在霍夫變換距離夾角坐標系下對應(yīng)的Mat的行的下標
int r_subscript = r / rho;
//經(jīng)過該直線的點數(shù)加1
houghMat.at<float>(r_subscript,k)= houghMat.at<float>(r_subscript, k)+1;
}
}
}
}
}
//經(jīng)過直線的點數(shù)大于閾值,則視為在原圖中存在該直線
for (int i = 0;i < houghMat_rows;i++)
{
for (int j = 0;j < houghMat_cols;j++)
{
if (houghMat.ptr<float>(i)[j] > Threshold)
{
//line保存直線到原點的距離和直線到坐標原點的垂線和x軸的夾角
Vec2f line(i*rho,j*theat*CV_PI/180);
lines.push_back(line);
}
}
}
}
三、效果測試
測試代碼文章來源:http://www.zghlxwxcb.cn/news/detail-745083.html
void drawLine(Mat &img, vector<Vec2f> lines, double rows, double cols, Scalar scalar, int n)
{
Point pt1, pt2;
for (int i = 0;i < lines.size();i++)
{
float rho = lines[i][0];//直線到坐標原點的距離
float theat = lines[i][1];//直線到坐標原點的垂線和x軸的夾角
double a = cos(theat);
double b = sin(theat);
double x0 = a*rho, y0 = b*rho;//直線與過坐標原點的垂線的交點
double length = max(rows, cols);//突出高寬的最大值
//計算直線上的一點
pt1.x = cvRound(x0 + length*(-b));
pt1.y = cvRound(y0 + length*(a));
//計算直線上的另一點
pt2.x = cvRound(x0 - length*(-b));
pt2.y = cvRound(y0 - length*(a));
while (pt1.x == pt2.x&&pt1.y == pt2.y)
{
//計算直線上的另一點
pt2.x = cvRound(x0 + length*(-b));
pt2.y = cvRound(y0 + length*(a));
}
//兩點繪制直線
line(img, pt1, pt2, scalar, n);
}
}
int main()
{
//Mat test = imread("../d.png");
Mat test = imread("../HoughLines.jpg");
vector<Vec2f> lines;
myHoughLines(test,1,1,100,lines);
for (int i = 0;i < lines.size();i++)
{
cout << "直線為:" << endl << lines[i] << endl;
}
Mat testResult = Mat::zeros(test.size(),CV_8U);//在全黑的圖像中畫出直線
//test.copyTo(testResult);//在原圖上畫出直線
drawLine(testResult, lines, test.rows, test.cols, Scalar(255),1);
imshow("原圖:", test);
imshow("變換后的直線:", testResult);
waitKey(0);
return 0;
}
上述代碼中的drawLine()函數(shù)是《OpenCV4快速入門》一書的代碼清單 7-2中的原函數(shù),只用于畫線。
測試原圖
測試效果
該算法代碼的解析在代碼的注釋中已經(jīng)寫明,對函數(shù)參數(shù)也進行了說明。我使用了多張圖片進行了測試,以及多次調(diào)整參數(shù)進行測試,發(fā)現(xiàn)在rho=1,theat=1,Threshold=100時的檢測效果可以達到最佳。文章來源地址http://www.zghlxwxcb.cn/news/detail-745083.html
到了這里,關(guān)于霍夫變換直線檢測算法實現(xiàn)OpenCV(C++)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!