霍夫圓檢測HoughCircles()、先模糊降噪轉灰度再圓檢測、畫圓

1.21.1 霍夫圓檢測原理

霍夫圓變換:的基本原理和上個教程中提到的霍夫線變換類似, 只是點對應的二維極徑極角空間被三維的圓心點x, y還有半徑r空間取代。

原理:從平面坐標圓上的點到極坐標轉換的三個參數C(x0,y0,r)其中x0,y0是圓心,r 取一固定值時theta掃描360度,x y 跟著變化, 若多個邊緣點對應的三維空間曲線交於一點,則他們在共同圓上,在圓心處有累積最大值,也可以用同樣的閾值的方法來判斷一個圓是否被檢測到。

1.21.2 相關API - HoughCircles

因為霍夫圓檢測對雜訊比較敏感,所以首先要對圖像做濾波(模糊降噪)。(比如椒鹽雜訊用中值濾波,其他的也可以用高斯模糊)

基於效率考慮,Opencv中實現的霍夫變換圓檢測是基於圖像梯度(霍夫梯度法, 也叫2-1霍夫變換(21HT))的實現,分為兩步(已封裝到HoughCircles):

1) Canny檢測邊緣,發現可能的圓心。圓心一定是在圓上的每個點的模向量上, 這些圓上點模向量的交點就是圓心, 霍夫梯度法的第一步就是找到這些圓心, 這樣三維的累加平面就又轉化為二維累加平面。

2)基於第一步的基礎上從候選圓心開始計算最佳半徑大小。第二步根據所有候選中心的邊緣非0像素對其的支持程度來確定半徑。

HoughCircles(

InputArray image, // 輸入圖像 ,必須是8位的單通道灰度圖像,8位可以有4個通道,每個通道是8位,可以使RGB。

OutputArray circles, // 輸出結果,發現的圓信息(數組)

Int method, // 選梯度方法 - HOUGH_GRADIENT

Double dp, // dp = 1,原圖尺度(2的話比原圖小一半來尋找,速度快了)

Double mindist, // 10 半徑最短距離-可以分辨是兩個圓的,否則認為是半徑不同的同心圓- src_gray.rows/8

Double param1, // canny邊緣檢測的低閾值canny edge detection low threshold

Double param2, // 中心點累加器閾值 – 候選圓心

Int minradius, // 圓最小半徑

Int maxradius//圓最大半徑(範圍越大,速度越慢)

)

/*霍夫圓檢測*/

cvtColor(blur_src, blur_src, CV_BGR2GRAY); //轉灰度

vector<Vec3f> pcircles; //數組

HoughCircles(blur_src, pcircles, CV_HOUGH_GRADIENT, 1, 10, 150, 30, 5, 50); //霍夫圓檢測,8位輸入,三維數組輸出,霍夫梯度,尺度,半徑最短間隔,canny低閾值,圓心累加閾值,最短半徑,最長半徑

應用步驟:

1)中值濾波去雜訊 - medianBlur()

medianBlur(src, blur_src, 3);//中值濾波

2)轉灰度 - cvtColor()

cvtColor(blur_src, blur_src, CV_BGR2GRAY); //轉灰度

3)霍夫圓檢測 - HoughCircles()

vector<Vec3f> pcircles; //數組

HoughCircles(blur_src, pcircles, CV_HOUGH_GRADIENT, 1, 10, 150, 30, 5, 50); //霍夫圓檢測,8位輸入,三維數組輸出,霍夫梯度,尺度,半徑最短間隔,canny低閾值,圓心累加閾值,最短半徑,最長半徑

4)畫圓 - circle()

circle(dst, Point(cc[0], cc[1]), cc[2], Scalar(0, 255, 0), 2, LINE_AA); //在原圖上畫圓周,原圖,圓心,半徑長度,線顏色,線寬,線類型

circle(dst, Point(cc[0], cc[1]), 2, Scalar(0, 0, 255), 2, LINE_AA); //在原圖上畫圓心


完整程序:

/*1.21 霍夫圓變換*/
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace cv;
using namespace std;
Mat src, dst, blur_src;

int main(int argc, char** argv) {
src = imread("E:/OpenCV/testimage/circle.jpg");
if (src.empty()) {
printf("could not load image...
");
return -1;
}
char input_title[] = "input image";
namedWindow(input_title, CV_WINDOW_AUTOSIZE);
imshow(input_title, src);

/*中值濾波*/
medianBlur(src, blur_src, 3);//中值濾波

/*轉灰度*/
cvtColor(blur_src, blur_src, CV_BGR2GRAY); //轉灰度

/*霍夫圓檢測*/
vector<Vec3f> pcircles; //數組
HoughCircles(blur_src, pcircles, CV_HOUGH_GRADIENT, 1, 10, 150, 30, 5, 50); //霍夫圓檢測,8位輸入,三維數組輸出,霍夫梯度,尺度,半徑最短間隔,canny低閾值,圓心累加閾值,最短半徑,最長半徑

/*畫圓*/
src.copyTo(dst); //完全拷貝
for (size_t i = 0; i < pcircles.size(); i++) {
Vec3f cc = pcircles[i];
circle(dst, Point(cc[0], cc[1]), cc[2], Scalar(0, 255, 0), 2, LINE_AA); //在原圖上畫圓周,原圖,圓心,半徑長度,線顏色,線寬,線類型
circle(dst, Point(cc[0], cc[1]), 2, Scalar(0, 0, 255), 2, LINE_AA); //在原圖上畫圓心
}
imshow("output_title", dst);

waitKey(0);
return 0;
}

運行結果:

推薦閱讀:

相关文章