iT邦幫忙

2023 iThome 鐵人賽

DAY 27
0
Software Development

圖解C++影像處理與OpenCV應用:從基礎到高階,深入學習超硬核技術!系列 第 27

【Day27】使用OpenCV進行霍夫圓轉換(Hough Circle Transform)

  • 分享至 

  • xImage
  •  

一、介紹

上一個章節我們透過霍夫線轉換來找到影像上的線,接下來我們要使用霍夫圓轉換找到影像上圓的資訊,包含圓心座標和半徑。

二、原理

1.霍夫圓轉換 (Hough Circle Transform)

從高中/高職的數學,我們應該學過圓的方程式,其中,r為圓半徑C(a,b)為圓心座標

https://ithelp.ithome.com.tw/upload/images/20230927/20161732Z77FbLimVs.png

https://ithelp.ithome.com.tw/upload/images/20230927/201617322P7frrx4HL.png

霍夫圓檢測的的核心觀念是在每個輪廓點上畫一個半徑為r的圓,重疊次數最多的交點即為圓心,而檢測出圓的半徑為r,很簡單對吧。

然而理想很美好,現實總是很骨感,可以看到下圖右邊,當我們並不知道圓的半徑為多少,必須透過窮舉的方式求出r值,而大多數的在應用上我們無法預先知道在影像上的圓形半徑多少。好在我們可以透過霍夫梯度方法解決上述的問題,但因為牽扯到過多的數學,這邊就不多做講解。

https://ithelp.ithome.com.tw/upload/images/20230927/20161732JUteeX8mAk.png

三、程式碼

1. 逐行解釋

1) 使用OpenCV實現霍夫圓轉換

使用OpenCV中的霍夫轉換方法 cv::HoughCircles 來檢測影像中的圓形。

cv::HoughCircles(grayImage, circles, cv::HOUGH_GRADIENT, 1,200, 100, 30,min_r); // 使用霍夫轉換來檢測圓
  • grayImage:這是輸入的灰階影像,也就是待檢測的圓形可能存在的影像。
  • circles:這是一個向量(vector),用於存儲檢測到的圓形的參數。每個檢測到的圓形都由三個值表示,分別是圓心的 (x, y) 座標半徑
  • cv::HOUGH_GRADIENT:這是霍夫轉換的方法,指定了使用基於梯度的方法來檢測圓形。
  • 1:這是霍夫轉換的解析度,表示圓心之間的像素距離。在這裡,設定為1,表示每個像素都參與檢測。
  • 200:檢測到的圓的中心之間的最小距離。如果參數太小,除了一個真實的圓之外,還可能會誤檢測到多個附近的圓。如果太大,可能會遺漏一些圓。
  • 100:這是Canny邊緣檢測的閾值,用於檢測影像中的邊緣。
  • 30:這是霍夫轉換的投票閾值,表示檢測一個圓所需的最小投票數。當某個圓形的投票數超過這個閾值時,才被視為有效的圓形。
  • min_r:這是用於篩選圓形的參數,表示最小圓半徑。只有半徑大於 min_r 的才會被保留。

2. 完整程式碼

  1. 建立視窗命名為"Circle",並調整大小。
  2. 使用Canny邊緣檢測算法對grayImage進行邊緣檢測。
  3. 當"Min R"滑動條的值發生變化時,調整值最小半徑,並進行霍夫轉換來檢測圓,然後在"Circle"視窗中化出檢測到的圓。
#include <iostream>
#include "opencv2/opencv.hpp"
#include "opencv2/core/utils/logger.hpp"

using namespace std;

void on_circle_change(int position, void*);
int min_r;
// 存儲灰階影像的變數
cv::Mat grayImage; 
vector<cv::Vec2f> lines;

int main()
{
	cv::utils::logging::setLogLevel(cv::utils::logging::LOG_LEVEL_SILENT); 
	grayImage = cv::imread("C:\\Users\\vince\\Downloads\\test_image6.jpg", cv::IMREAD_GRAYSCALE); // 讀取灰階影像

    cv::namedWindow("Circle", cv::WindowFlags::WINDOW_NORMAL); // 建立一個視窗用於顯示圓檢測結果
    cv::resizeWindow("Circle", 512.0f * ((float)grayImage.cols / grayImage.rows), 512);

	cv::createTrackbar("Min R", "Circle", &min_r, 1000, on_circle_change); // 建立一個滑動條用於調整最小半徑
	cv::waitKey(0); 
	return 0;
}

// 當滑動條"Min R"的值發生變化時調用的函數
void on_circle_change(int position, void*) {
	if (min_r == 0)
		return;
	cv::Mat output;
	cv::cvtColor(grayImage, output, cv::COLOR_GRAY2BGR);

	vector<cv::Vec3f> circles;
	cv::HoughCircles(grayImage, circles, cv::HOUGH_GRADIENT, 1,200, 100, 30,min_r); // 使用霍夫轉換來檢測圓

	 for( size_t i = 0; i < circles.size(); i++ )
	 {
		 cv::Vec3i c = circles[i];
		 cv::Point center = cv::Point(c[0], c[1]);
		 cv::circle( output, center,5, cv::Scalar(0,0,255),-1, cv::LINE_AA);
		 int radius = c[2];
		 cv::circle(output, center, radius, cv::Scalar(255, 0, 255), 3, cv::LINE_AA);
	 }
	cv::imshow("Circle", output);
}

四、測試結果

1) 測試圖

https://ithelp.ithome.com.tw/upload/images/20231009/20161732OT0Oelhs9k.jpg

https://ithelp.ithome.com.tw/upload/images/20230927/20161732STPm6qDSEA.png

五、參考資料


上一篇
【Day26】使用OpenCV進行霍夫線轉換(Hough Line Transform)
下一篇
【Day28】影像離散傅立葉轉換(Discrete Fourier Transform)
系列文
圖解C++影像處理與OpenCV應用:從基礎到高階,深入學習超硬核技術!30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
philipshen
iT邦新手 5 級 ‧ 2023-10-09 23:59:13

Vincent大,
再打擾你一下,

如下圖,調整數值後,都會多個小圓,不知道是什麼原因造成的呢?
68_hough_circle_transform2.jpg

感謝指導。

上方程式碼有誤,霍夫圓變換不需要進行邊緣檢測,把cv::Canny刪掉即可。

我把霍夫轉換的投票閾值,設成35後,就只認到2個圓圈了。

感謝

我要留言

立即登入留言