緒:
若何檢測和識別圖像中的直線和圓?
一個很是有用的方式就是霍夫變換;
是圖像中識別各類幾何外形的根基算法之一;
本文介紹一下opencv中的霍夫線變換和霍夫圓變換的應用。
 霍夫線變換:
霍夫線變換是一種在圖像中尋找直線的方式;
OpenCV中撐持三種霍夫線變換,別離為尺度霍夫線變換、多標準霍夫線變換、累計概率霍夫線變換。
在OpenCV中可以挪用HoughLines來進行尺度霍夫線變換和多標準霍夫線變換;
挪用HoughLinesP函數進行累積概率霍夫線變換。
 霍夫直線思惟:
我們都知道,
二維坐標軸上暗示一條直線的方程式y = a*x + b,
我們想求出一條直線就得想方設法求出此中的a和b的值。
若是用極坐標來暗示就是:rho=xcos(theta)+ysin(theta);
此中,
theta就是直線與程度線所當作的角度,
而rho就是圓的半徑;
同樣地,這兩個參數也是表征一條直線的主要參數,
確定他們倆了,也就確定一條直線了。
【注】:
OpenCV里,只需挪用HoughLines就可獲得表征一條直線的這兩個參數值!
霍夫直線檢測示例一:HoughLines
#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\features2d\features2d.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat srcImage = imread("0.jpg");
imshow("srcImg", srcImage);
//邊緣檢測
Mat midImage, dstImage;
Canny(srcImage, midImage, 50, 200, 3);
cvtColor(midImage, dstImage, CV_GRAY2BGR);
//界說矢量布局存放檢測出來的直線
vector<Vec2f> lines;
HoughLines(midImage, lines, 1, CV_PI / 180, 150, 0, 0);
//第五個參數表閾值,閾值越年夜檢測越精準速度越快直線越少
//lines是包含rho和theta的,而不包羅直線上的點,
//所以下面需要按照獲得的rho和theta來成立一條直線
//依次畫出每條線段
for (size_t i = 0; i < lines.size(); i++)
{
float rho = lines[i][0]; //就是圓的半徑r
float 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, CV_AA);
imshow("邊緣檢測后的圖", midImage);
imshow("最終結果圖", dstImage);
}
waitKey();
return 0;
}
【問題】:
你會發現,怎么圖中一些很較著的的直線都沒檢測出來啊?
原因是,我們閾值寫的有點高了,只有那些有足夠的把握認為是直線的直線才可能檢測出來。
若是把閾值改為150,直線檢測結果就釀成如許子了。
顯然多了良多直線,把那些“可能是直線”的直線都當做是直線了。
所以,閾值的選擇很主要,就看你是要切確查找仍是恍惚查找了。
【注】:角度theta用的單元不是我們所說的度數(70度、80度),而是數學上的π/2,π/3。
 
 霍夫直線檢測示例二:HoughLinesP
//與HoughLines分歧的是,
//HoughLinesP獲得lines的是含有直線上點的坐標的,
//所以下面進行劃線時就不再需要本身求出兩個點來確定獨一的直線了
#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\features2d\features2d.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat srcImage = imread("2.jpg");
imshow("Src Pic", srcImage);
Mat midImage, dstImage;
Canny(srcImage, midImage, 50, 200, 3);
cvtColor(midImage, dstImage, CV_GRAY2BGR);
vector<Vec4i> lines;
HoughLinesP(midImage, lines, 1, CV_PI / 180, 80, 50, 10);//注重第五個參數,為閾值
//依次畫出每條線段
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);
imshow("邊緣檢測后的圖", midImage);
imshow("最終結果圖", dstImage);
}
waitKey();
return 0;
}
 
 霍夫圓變換:
對直線來說,一條直線由參數極徑極角(rho,theta)暗示;
對圓來說,需要三個參數來暗示一個圓;(center_x,center_y,r);其對應一條三維空間的曲線;
那么與二維的霍夫線變換同樣的事理,
對于多個邊緣點越多這些點對應的三維空間曲線交于一點,那么他們顛末的配合圓上的點就越多,
近似的我們也就可以用同樣的閾值的方式來判定一個圓是否被檢測到, 這就是尺度霍夫圓變換的道理,
但也恰是在三維空間的計較量年夜年夜增添的原因, 尺度霍夫圓轉變很難被應用到現實中;
出于對運算效率的考慮, OpenCV實現的是一個比尺度霍夫圓變換更為矯捷的檢測方式: 霍夫梯度法, 也叫2-1霍夫變換(21HT),
道理:依據是圓心必然是在圓上的每個點的模標的目的量上, 這些圓上點模標的目的量的交點就是圓心, 霍夫梯度法的第一步就是找到這些圓心, 如許三維的累加平面就又轉化為二維累加平面.;
第二步按照所有候選中間的邊緣非0像素對其的撐持水平來確定半徑.;
 霍夫圓變換示例:
#include <opencv2\opencv.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\features2d\features2d.hpp>
#include <opencv2\core\core.hpp>
#include <opencv2\imgproc\imgproc.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat srcImage = imread("test5.jpg");
Mat midImage, dstImage;
imshow("srcImg", srcImage);
cvtColor(srcImage, midImage, CV_BGR2GRAY);
GaussianBlur(midImage, midImage, Size(9, 9), 2, 2);
//霍夫圓變換
vector<Vec3f> circles;
HoughCircles(midImage, circles, CV_HOUGH_GRADIENT, 1.5, 10, 200, 150, 0, 0);
//注重第七的參數為閾值,可以自行調整,值越年夜,檢測的圓更精準
//依次在圖中繪制出圓
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);
}
imshow("【結果圖】", srcImage);
waitKey(0);
return 0;
}
 0 篇文章
如果覺得我的文章對您有用,請隨意打賞。你的支持將鼓勵我繼續創作!