影象處理(八)——霍夫變換
阿新 • • 發佈:2018-11-11
霍夫變換是一種特徵檢測(feature extraction),被廣泛應用在影象分析(image analysis)、電腦視覺(computer vision)以及數位影像處理(digital image processing)。
霍夫變換是用來辨別找出物件中的特徵,例如:線條。他的演算法流程大致如下,給定一個物件、要辨別的形狀的種類,演算法會在引數空間(parameter space)中執行投票來決定物體的形狀,而這是由累加空間(accumulator space)裡的區域性最大值(local maximum)來決定。
而本次實驗我要做的就是使用霍夫變換進行影象圓的檢測。
霍夫變換的過程可以分為以下幾步:
- 對輸入影象進行邊緣檢測,獲取邊界點,即前景點。
- 假如影象中存在圓形,那麼其輪廓必定屬於前景點(此時請忽略邊緣提取的準確性)。
- 同霍夫變換檢測直線一樣,將圓形的一般性方程換一種方式表示,進行座標變換。由x-y座標系轉換到a-b座標系。寫成如下形式(a-x)²+(b-y)²=r²。那麼x-y座標系中圓形邊界上的一點對應到a-b座標系中即為一個圓。
- 那x-y座標系中一個圓形邊界上有很多個點,對應到a-b座標系中就會有很多個圓。由於原影象中這些點都在同一個圓形上,那麼轉換後a,b必定也滿足a-b座標系下的所有圓形的方程式。直觀表現為這許多點對應的圓都會相交於一個點,那麼這個交點就可能是圓心(a, b)。
- 統計區域性交點處圓的個數,取每一個區域性最大值,就可以獲得原影象中對應的圓形的圓心座標(a,b)。一旦在某一個r下面檢測到圓,那麼r的值也就隨之確定。
在實際實現中,只需要注意輸入的是灰度圖,以及霍夫變換中的引數問題,就可以較好地實現影象中圓的檢測。
結果如下圖:
不過我的實現中還存在一些問題,例如影象如果是不完全連通的,有時候就不能識別。
在這張圖例,第二行第二個圓就沒有識別出來,而且第二行第一個圖識別出了兩個圓。
此外,對於邊緣粗細不一樣的圖形,我的實現中會出現識別出n多個圓的情況。
可能是因為對於不同畫素的位置,而識別出了不同的圓。
程式碼自取:
#include "stdafx.h"
#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
//【1】載入原始圖和Mat變數定義
Mat srcImage = imread("E:/C++/CVE7/1.jpg"); //工程目錄下應該有一張名為1.jpg的素材圖
Mat midImage, dstImage;//臨時變數和目標圖的定義
//【2】顯示原始圖
imshow("【原始圖】", srcImage);
//【3】轉為灰度圖,進行影象平滑
cvtColor(srcImage, midImage, CV_BGR2GRAY);//轉化邊緣檢測後的圖為灰度圖
GaussianBlur(midImage, midImage, Size(9, 9), 2, 2);
//【4】進行霍夫圓變換
vector<Vec3f> circles;
HoughCircles(midImage, circles, CV_HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);
//【5】依次在圖中繪製出圓
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);
}
//【6】顯示效果圖
imshow("【效果圖】", srcImage);
waitKey(0);
return 0;
}