1.21【OpenCV圖像處理】霍夫圓變換
霍夫圓檢測HoughCircles()、先模糊降噪轉灰度再圓檢測、畫圓
1.21.1 霍夫圓檢測原理
霍夫圓變換:的基本原理和上個教程中提到的霍夫線變換類似, 只是點對應的二維極徑極角空間被三維的圓心點x, y還有半徑r空間取代。
原理:從平面坐標圓上的點到極坐標轉換的三個參數,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//圓最大半徑(範圍越大,速度越慢)
)
/*霍夫圓檢測*/ncvtColor(blur_src, blur_src, CV_BGR2GRAY); //轉灰度nvector<Vec3f> pcircles; //數組nHoughCircles(blur_src, pcircles, CV_HOUGH_GRADIENT, 1, 10, 150, 30, 5, 50); //霍夫圓檢測,8位輸入,三維數組輸出,霍夫梯度,尺度,半徑最短間隔,canny低閾值,圓心累加閾值,最短半徑,最長半徑n
應用步驟:
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 霍夫圓變換*/n#include <opencv2/opencv.hpp>n#include <iostream> n#include <math.h>nusing namespace cv;nusing namespace std;nMat src, dst, blur_src;nnint main(int argc, char** argv) {n src = imread("E:/OpenCV/testimage/circle.jpg");nif (src.empty()) {n printf("could not load image...n");nreturn -1;n }nchar input_title[] = "input image";n namedWindow(input_title, CV_WINDOW_AUTOSIZE);n imshow(input_title, src);nn/*中值濾波*/n medianBlur(src, blur_src, 3);//中值濾波nn/*轉灰度*/n cvtColor(blur_src, blur_src, CV_BGR2GRAY); //轉灰度nn/*霍夫圓檢測*/ nvector<Vec3f> pcircles; //數組n HoughCircles(blur_src, pcircles, CV_HOUGH_GRADIENT, 1, 10, 150, 30, 5, 50); //霍夫圓檢測,8位輸入,三維數組輸出,霍夫梯度,尺度,半徑最短間隔,canny低閾值,圓心累加閾值,最短半徑,最長半徑nn/*畫圓*/n src.copyTo(dst); //完全拷貝nfor (size_t i = 0; i < pcircles.size(); i++) {nVec3f cc = pcircles[i];n circle(dst, Point(cc[0], cc[1]), cc[2], Scalar(0, 255, 0), 2, LINE_AA); //在原圖上畫圓周,原圖,圓心,半徑長度,線顏色,線寬,線類型n circle(dst, Point(cc[0], cc[1]), 2, Scalar(0, 0, 255), 2, LINE_AA); //在原圖上畫圓心n }n imshow("output_title", dst);nn waitKey(0);nreturn 0;n}n
運行結果:
推薦閱讀:
※level set (水平集)演算法是什麼?
※NUFFT的計算難點在哪裡?
※運算量很大的圖像處理演算法有什麼意義呢?
※清晰度、對比度和銳度之間有什麼區別?
※《Conditional Generative Adversarial Nets》閱讀筆記