引用OpenCV 頭文件和庫文件,並且包含vector, 後面要用到。
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <iostream>
#include <stdio.h>
#include <vector>
#include <math.h>
#pragma comment (lib,"opencv_core244d.lib")
#pragma comment (lib,"opencv_highgui244d.lib")
#pragma comment (lib,"opencv_imgproc244d.lib")
using namespace std;
using namespace cv;
加載待處理圖片,為了便於顯示,對圖片進行縮放,其實縮放這個小技巧還可以提高後續的處理速度。然後對圖片進行灰度處理,然後對圖片記性二值化處理,去掉飽和度較低的部分,利用HoughCircles函數,提取輪廓為圓的部分。
註意調整HoughCirles函數的幾個參數,可以抓到不同的結果,要耐心根據實際情況調整。
Mat resized;
resize(src,resized,Size(src.cols/ratio,src.rows/ratio));
int w=resized.size().width;
int h=resized.size().height;
Mat gray;
cvtColor(resized,gray,CV_BGR2GRAY);
blur(gray,gray,Size(3,3));
threshold(gray,gray,160,255,THRESH_BINARY_INV);
blur(gray,gray,Size(3,3));
vector<Vec3f> circles;
HoughCircles(gray,circles,CV_HOUGH_GRADIENT,2,h/4,25,100,h/32,h/8);
vector<Vec3f>::const_iterator it=circles.begin();
while(it!=circles.end())
{
circle(resized,Point((*it)[0],(*it)[1]),2,Scalar(0,0,255),2);
circle(resized,Point((*it)[0],(*it)[1]),(*it)[2],Scalar(0,0,255),2);
++it;
}
namedWindow("src");
imshow("src",resized);
namedWindow("resized");
imshow("resized",gray);
waitKey(0);
代碼解讀:
使用HoughCircles必須註意,傳入的第壹個參數必須是灰度圖,根據需要設置其參數,參數2 :累加器分辨率, 參數3: 兩個圓之間的最小距離,參數4:Canny 高閥值,參數5:最小投票數,參數6,7:最小,最大半徑。
函數抓取的圓保存到向量circles中, Vec3f 是個3個變量的結構體Vec3f[0] ,Vec3f[1] 對應圓心坐標值,Vec3f[2] 對應圓心半徑。
為了顯示結果, 使用circle函數畫出圓心和圓,顏色使用紅色。
但是攝像頭拍照不比電腦作圖,實際拍照會受光照條件和強度的影響,導致抓取結果偏差很大。 如下圖,實際拍攝的圖可能有陰影投射,灰度處理後影響值得抓取。使用上述代碼,卻抓到了7個圓,實際只需要左右2個,所以可以根據坐標將不需要的過濾掉。
實際基於標記的坐標定位也可使用如下的圖形進行實現,該圖解析出來後不但能夠識別坐標,還可判斷方向,實際開發中,下圖會轉化為海明碼進行分析。