霍夫變換鐳射線中心提取(基於opencv)
阿新 • • 發佈:2018-12-20
平臺: VS2017 C++ OPENCV3庫
效果:
原圖 結果: 原圖: 結果:
步驟:
1.圖片預處理,引數可以自己調整
//邊緣檢測
Canny(srcImage, dstImage, 210, 250, 3);
//灰度化
cvtColor(midImage, dstImage, CV_GRAY2BGR);
2.霍夫變換,畫直線
// 定義向量結構存放檢測出來的直線
vector<Vec2f> lines;
//通過這個函式,我們就可以得到檢測出來的直線集合了
HoughLines(midImage, lines, 1, CV_PI / 180, 300, 0, 0);
//這裡注意第五個引數,表示閾值,閾值越大,表明檢測的越精準,速度越快,得到的直線越少(得到的直線都是很有把握的直線)
//這裡得到的lines是包含rho和theta的,而不包括直線上的點,所以下面需要根據得到的rho和theta來建立一條直線
//依次畫出每條線段
for (size_t i = 0; i < lines.size(); i++)
{
double rho = lines[i][0]; //就是圓的半徑r
double theta = lines[i][1]; //就是直線的角度
Point pt1, pt2;
double a = cos(theta), b = sin(theta);
double x0 = a * rho, y0 = b * rho;
/*cout << pt1.y << "asd" << pt2.y<<"jiaodu"<< theta<<"zhi"<<a;*/
pt1.x = cvRound(x0 + 800 * (-b)); // + - 800是為了我換下面的線
pt1.y = cvRound(y0 + 800 * (a));
pt2.x = cvRound(x0 - 800 * (-b));
pt2.y = cvRound(y0 - 800 * (a));
line(dstImage, pt1, pt2, Scalar(0, 100, 195), 2);
}
3.獲取四個座標
很簡單,橫著的線theta>1, 豎著的0<theta<1 把值賦給座標
if (theta >= 0 && theta < 1)
{
y1 = pt1.y;
y2 = pt2.y;
x1 = pt1.x;
x2 = pt2.x;
}
if (theta > 1)
{
/*cout << pt1;
cout << pt2;
cout << pt2.x;*/
x3 = pt2.x;
x4 = pt1.x;
y3 = pt2.y;
y4 = pt1.y;
}
4.計算交點
雖然是八個座標,但我只用了其中四組,後面會講到。 輸入四組點,就可以返回交點了
CvPoint CrossPoint(const CvPoint line1, const CvPoint line2, const CvPoint line3, const CvPoint line4) //交點
{
double x_member, x_denominator, y_member, y_denominator;
CvPoint cross_point;
x_denominator = line4.x*line2.y - line4.x*line1.y - line3.x*line2.y + line3.x*line1.y
- line2.x*line4.y + line2.x*line3.y + line1.x*line4.y - line1.x*line3.y;
x_member = line3.y*line4.x*line2.x - line4.y*line3.x*line2.x - line3.y*line4.x*line1.x + line4.y*line3.x*line1.x
- line1.y*line2.x*line4.x + line2.y*line1.x*line4.x + line1.y*line2.x*line3.x - line2.y*line1.x*line3.x;
if (x_denominator == 0)
cross_point.x = 0;
else
cross_point.x = x_member / x_denominator;
y_denominator = line4.y*line2.x - line4.y*line1.x - line3.y*line2.x + line1.x*line3.y
- line2.y*line4.x + line2.y*line3.x + line1.y*line4.x - line1.y*line3.x;
y_member = -line3.y*line4.x*line2.y + line4.y*line3.x*line2.y + line3.y*line4.x*line1.y - line4.y*line3.x*line1.y
+ line1.y*line2.x*line4.y - line1.y*line2.x*line3.y - line2.y*line1.x*line4.y + line2.y*line1.x*line3.y;
+ line1.y*line2.x*line4.y - line1.y*line2.x*line3.y - line2.y*line1.x*line4.y + line2.y*line1.x*line3.y;
if (y_denominator == 0)
cross_point.y = 0;
else
cross_point.y = y_member / y_denominator;
return cross_point; //平行返回(0,0)
}
5.畫圓圈
Point e1, e2, e3, e4, u;
e1 = Point(x1, y1);
e2 = Point(x2, y2);
e3 = Point(x3, y3);
e4 = Point(x4, y4);
u = CrossPoint(e1, e2, e3, e4);
circle(srcImage, u, 25, (53, 91, 233), 4, 3);
imshow("result", srcImage);
完成
不足:
1.可以看到一些誤差
理想狀態是隻有兩條線,直接取得中點,但是有時候鐳射太粗了。每條鐳射有2條直線,我都取得最後一條,所以導致結果實際中點在這裡(黑點處)
2.無直線沒有判斷
如果沒有檢測到直線,程式就崩了,想改進可以加一個沒檢測到直線後的操作就ok 如果要改進的畫的精度有很多辦法,比如: 1.找到四個交點,取四個交點的中心 2.或者去多條平行直線的中線再,剩2條直線再做計算
參考部落格:
博主只是選修課,就不繼續費心改進了。 有問題可以評論區交流。 過幾天放程式碼