天天看點

20 OpenCV霍夫圓變換HoughCircles一、霍夫圓檢測原理二、霍夫梯度法三、HoughCircles四、示例

一、霍夫圓檢測原理

  • 對直線來說, 一條直線能由參數極徑極角 (r,θ) 表示.

    而對圓來說, 從平面坐标到極坐标轉換需要三個參數, 也就是: ( xcenter , ycenter, r )。其中xcenter , ycenter 表示圓心,r 表示圓的半徑。這就意味着需要大量的記憶體而且執行效率會很低,速度會很慢。

    20 OpenCV霍夫圓變換HoughCircles一、霍夫圓檢測原理二、霍夫梯度法三、HoughCircles四、示例
  • 霍夫圓檢測對噪聲比較敏感,是以首先要對圖像做中值濾波
  • 為了提高效率,OpenCV實作了一種比标準Hough變換稍微複雜的檢測方法:Hough梯度方法,它由兩個主要階段組成。

    第一階段:檢測邊緣,發現可能的圓心

    第二階段:基于第一步的基礎上從候選圓心開始計算最佳半徑大小

二、霍夫梯度法

  • 原理

【1】首先對圖像應用邊緣檢測,比如用canny邊緣檢測。

【2】然後,對邊緣圖像中的每一個非零點,考慮其局部梯度,即用Sobel()函數計算x和y方向的Sobel一階導數得到梯度。

【3】利用得到的梯度,由斜率指定的直線上的每一個點都在累加器中被累加,這裡的斜率是從一個指定的最小值到指定的最大值的距離。

【4】同時,标記邊緣圖像中每一個非0像素的位置。

【5】然後從二維累加器中這些點中選擇候選的中心,這些中心都大于給定門檻值并且大于其所有近鄰。這些候選的中心按照累加值降序排列,以便于最支援像素的中心首先出現。

【6】接下來對每一個中心,考慮所有的非0像素。

【7】這些像素按照其與中心的距離排序。從到最大半徑的最小距離算起,選擇非0像素最支援的一條半徑。

【8】如果一個中心收到邊緣圖像非0像素最充分的支援,并且到前期被選擇的中心有足夠的距離,那麼它就會被保留下來。

這個實作可以使算法執行起來更高效,或許更加重要的是,能夠幫助解決三維累加器中會産生許多噪聲并且使得結果不穩定的稀疏分布問題。

  • 缺點

<1>在霍夫梯度法中,我們使用Sobel導數來計算局部梯度,那麼随之而來的假設是,其可以視作等同于一條局部切線,并這個不是一個數值穩定的做法。在大多數情況下,這樣做會得到正确的結果,但或許會在輸出中産生一些噪聲。

<2>在邊緣圖像中的整個非0像素集被看做每個中心的候選部分。是以,如果把累加器的門檻值設定偏低,算法将要消耗比較長的時間。第三,因為每一個中心隻選擇一個圓,如果有同心圓,就隻能選擇其中的一個。

<3>因為中心是按照其關聯的累加器值的升序排列的,并且如果新的中心過于接近之前已經接受的中心的話,就不會被保留下來。且當有許多同心圓或者是近似的同心圓時,霍夫梯度法的傾向是保留最大的一個圓。可以說這是一種比較極端的做法,因為在這裡預設Sobel導數會産生噪聲,若是對于無窮分辨率的平滑圖像而言的話,這才是必須的。

三、HoughCircles

void cv::HoughCircles   (   InputArray      image,
        OutputArray     circles,
        int     method,
        double      dp,
        double      minDist,
        double      param1 = 100,
        double      param2 = 100,
        int     minRadius = 0,
        int     maxRadius = 0 
    )   
           
  • image: 輸入圖像為8位單通道灰階圖
  • circles: 檢測到圓的輸出矢量,每個矢量都是三個浮點元素構成(x,y,radius)
  • method: 檢測方法,可以檢視HoughModes檢視具體細節,但目前隻有HOUGH_GRADIENT(霍夫梯度)一種方法可以使用。
  • dp: 用來檢測圓心的累加器圖像的分辨率與輸入圖像之比的倒數,且此參數允許建立一個比輸入圖像分辨率低的累加器。例如,如果dp=1,累加器和輸入圖像具有相同的分辨率,如果dp=2累加器便有輸入圖像一半那麼大的寬度和高度。
  • minDist: 霍夫檢測到的圓的圓心之間的最小距離,即讓算法能明顯區分的兩個不同圓之間的最小距離。這個參數如果太小的話,多個相鄰的圓可能被錯誤的檢測成了一個重合的圓。反之這個參數設定太大,某些圓就不能被檢測出來了。也就是超過這個距離就是兩個圓,否則是一個圓
  • param1: 指定檢測方法的第一個參數,目前可用方法是HOUGH_GRADIENT,它表示傳遞給Canny邊緣檢測算子的高門檻值(低門檻值是高門檻值的一半),有預設值100
  • param2: 指定檢測方法的第二個參數,對于HOUGH_GRADIENT方法,它表示在檢測階段圓心的累加器門檻值。它越小就越可以檢測到更多根本不存在的圓,而它越大的話能通過檢測的圓就更加接近完美的圓形了。有預設值100
  • minRadius: 圓的最小半徑
  • maxRadius: 圓的最大半徑

四、示例

#include<opencv2/opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;

int main(int argc, char** argv)
{
	//1. 讀取圖像
	Mat src, midBlur, gray_src, dst;
	src = imread("images/13.png");
	imshow("src", src);

	//2. 中值濾波,去除噪聲影響,不去噪的話,霍夫圓檢測的結果會不準确
	medianBlur(src, midBlur, 3);
	imshow("midBlur", midBlur);
	//3. 轉成灰階圖像
	cvtColor(midBlur, gray_src, CV_BGR2GRAY);//将二值圖轉換為RGB圖顔色空間,這裡重新建立一張空Mat也行

	//4. 霍夫變換檢測
	vector<Vec3f> circles;//存放檢測出的圓資訊,每個元素 Vec3f 的三個值表示,圓心x,y,圓半徑,類型必須是Vec3f
	HoughCircles(gray_src, circles, CV_HOUGH_GRADIENT, 1, 10, 100, 30, 5, 50);//霍夫圓檢測
	// 繪制圓
	src.copyTo(dst); // cvtColor(gray_src,dst,CV_GRAY2BGR);
	for (int i = 0; i < circles.size(); i++)
	{
		Vec3f cc = circles[i];
		circle(dst, Point(cc[0], cc[1]), cc[2], Scalar(0, 0, 255), 2, LINE_AA);//在原圖上畫出圓
		circle(dst, Point(cc[0], cc[1]), 2, Scalar(198, 23, 155), 2, LINE_AA);//在原圖上畫出圓心
	}

	imshow("Circle Test", dst);

	waitKey(0);
	return 0;
}


           
20 OpenCV霍夫圓變換HoughCircles一、霍夫圓檢測原理二、霍夫梯度法三、HoughCircles四、示例

繼續閱讀