图像处理:变换——霍夫圆变换 OpenCV v4.8.0

上一个教程霍夫线变换

下一个教程使用广义巴拉德和 Guil Hough 变换检测物体

原作者Ana Huamán
兼容性OpenCV >= 3.0

目标

在本教程中,您将学习如何

理论

Hough 圆变换

  • Hough Circle 变换的工作原理与上一教程中介绍的 Hough Line 变换大致相同。
  • 在线段检测中,线段由两个参数(r,θ)定义。在圆的情况下,我们需要三个参数来定义一个圆:

C :( x c e n t e r , y c e n t e r , r ) C:(x_{center},y_{center},r) C:(xcenter,ycenter,r

其中,(xcenter,ycenter) 定义中心位置(绿点),r 是半径,这样我们就可以完全定义一个圆,如下所示:

在这里插入图片描述

  • 为了提高效率,OpenCV 实现了一种比标准 Hough 变换稍难的检测方法: Hough 梯度法由两个主要阶段组成。第一阶段涉及边缘检测和寻找可能的圆心,第二阶段为每个候选圆心寻找最佳半径。更多详情,请查阅《学习 OpenCV》一书或您最喜欢的《计算机视觉》参考书目。

这个程序要做什么?

  • 加载图像并对其进行模糊处理以减少噪点
  • 对模糊图像应用 Hough 圆变换。
  • 在窗口中显示检测到的圆。

代码

更高级的版本(显示用于更改阈值的轨迹条)可在此处找到。

C++
我们将讲解的示例代码可从此处下载。


#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
 const char* filename = argc >=2 ? argv[1] : "smarties.png";
 // 加载图像
 Mat src = imread( samples::findFile( filename ), IMREAD_COLOR )// 检查图片加载是否正常
 if(src.empty()){
 printf(" Error opening image\n");
 printf(" Program Arguments: [image_name -- default %s] \n", filename);
 return EXIT_FAILURE;
 }
 Mat gray;
 cvtColor(src, gray, COLOR_BGR2GRAY);
 medianBlur(gray, gray, 5);
 vector<Vec3f> circles;
 HoughCircles(gray, circles, HOUGH_GRADIENT, 1,
 gray.rows/16, // 改变该值可检测出彼此距离不同的圆
 100, 30, 1, 30 // 更改最后两个参数
 // (min_radius & max_radius) 来检测更大的圆
 );
 for( size_t i = 0; i < circles.size(); i++ )
 {
 Vec3i c = circles[i];
 Point center = Point(c[0], c[1]);
 // 圆心
 circle( src, center, 1, Scalar(0,100,100), 3, LINE_AA)// 圆形轮廓
 int radius = c[2];
 circle( src, center, radius, Scalar(255,0,255), 3, LINE_AA);
 }
 imshow("detected circles", src);
 waitKey();
 return EXIT_SUCCESS;
}

Java
我们将讲解的示例代码可从此处下载。

package sample;
import org.opencv.core.*;
import org.opencv.core.Point;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
class HoughCirclesRun {
 public void run(String[] args) {
 String default_file = "../../../../data/smarties.png";
 String filename = ((args.length > 0) ? args[0] : default_file);
 // 加载图像
 Mat src = Imgcodecs.imread(filename, Imgcodecs.IMREAD_COLOR)// 检查图片加载是否正常
 if( src.empty() ) {
 System.out.println("Error opening image!")System.out.println("Program Arguments: [image_name -- 默认 "
 + default_file +"] \n");
 System.exit(-1)}
 Mat gray = new Mat()Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY)Imgproc.medianBlur(gray, gray, 5)Mat circles = new Mat()Imgproc.HoughCircles(gray, circles, Imgproc.HOUGH_GRADIENT, 1.0(double)gray.rows()/16, // 改变该值可检测出彼此距离不同的圆
 100.0, 30.0, 1, 30); // 更改最后两个参数
 // (min_radius & max_radius) 来检测更大的圆
 for (int x = 0; x < circles.cols(); x++) {
 double[] c = circles.get(0, x)Point center = new Point(Math.round(c[0]), Math.round(c[1]))// 圆心
 Imgproc.circle(src, center, 1, new Scalar(0,100,100), 3, 8, 0 )// 圆形轮廓
 int radius = (int) Math.round(c[2])Imgproc.circle(src, center, radius, new Scalar(255,0,255), 3, 8, 0 )}
 HighGui.imshow("detected circles", src)HighGui.waitKey()System.exit(0)}
}
public class HoughCircles {
 public static void main(String[] args) { // Load the native library.
 // 加载本地库。
 System.loadLibrary(Core.NATIVE_LIBRARY_NAME)new HoughCirclesRun().run(args)}
}

Python
我们将讲解的示例代码可从此处下载。

import sys
import cv2 as cv
import numpy as np
def main(argv):
 
 default_file = 'smarties.png'
 filename = argv[0] if len(argv) > 0 else default_file
 # 加载图像
 src = cv.imread(cv.samples.findFile(filename), cv.IMREAD_COLOR)
 # 检查图像是否加载成功
 if src is None:
 print ('Error opening image!')
 print ('Usage: hough_circle.py [image_name -- default ' + default_file + '] \n')
 return -1
 
 
 gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
 
 
 gray = cv.medianBlur(gray, 5)
 
 
 rows = gray.shape[0]
 circles = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, rows / 8,
 param1=100, param2=30,
 minRadius=1, maxRadius=30)
 
 
 if circles is not None:
 circles = np.uint16(np.around(circles))
 for i in circles[0, :]:
 center = (i[0], i[1])
 # 圆心
 cv.circle(src, center, 1, (0, 100, 100), 3)
 # 圆的轮廓
 radius = i[2]
 cv.circle(src, center, radius, (255, 0, 255), 3)
 
 
 cv.imshow("detected circles", src)
 cv.waitKey(0)
 
 return 0
if __name__ == "__main__":
 main(sys.argv[1:])

说明

我们使用的图片可在此处找到

加载图片

C++

 const char* filename = argc >=2 ? argv[1] : "smarties.png";
 // Loads an image
 Mat src = imread( samples::findFile( filename ), IMREAD_COLOR );
 // Check if image is loaded fine
 if(src.empty()){
 printf(" Error opening image\n");
 printf(" Program Arguments: [image_name -- default %s] \n", filename);
 return EXIT_FAILURE;
 }

Java

 String default_file = "../../../../data/smarties.png";
 String filename = ((args.length > 0) ? args[0] : default_file);
 // Load an image
 Mat src = Imgcodecs.imread(filename, Imgcodecs.IMREAD_COLOR);
 // Check if image is loaded fine
 if( src.empty() ) {
 System.out.println("Error opening image!");
 System.out.println("Program Arguments: [image_name -- default "
 + default_file +"] \n");
 System.exit(-1);
 }

Python

 default_file = 'smarties.png'
 filename = argv[0] if len(argv) > 0 else default_file
 # Loads an image
 src = cv.imread(cv.samples.findFile(filename), cv.IMREAD_COLOR)
 # Check if image is loaded fine
 if src is None:
 print ('Error opening image!')
 print ('Usage: hough_circle.py [image_name -- default ' + default_file + '] \n')
 return -1

转换为灰度图像:

C++

 Mat gray;
 cvtColor(src, gray, COLOR_BGR2GRAY);

Java

 Mat gray = new Mat();
 Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);

Python

 # Convert it to gray
 gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)

应用中值模糊以减少噪点并避免错误的圆检测:

C++

 medianBlur(gray, gray, 5);

Java

 Imgproc.medianBlur(gray, gray, 5);

Python

 # Reduce the noise to avoid false circle detection
 gray = cv.medianBlur(gray, 5)

继续应用 Hough 圆变换:

C++

 vector<Vec3f> circles;
 HoughCircles(gray, circles, HOUGH_GRADIENT, 1,
 gray.rows/16, // change this value to detect circles with different distances to each other
 100, 30, 1, 30 // change the last two parameters
 // (min_radius & max_radius) to detect larger circles
 );

Java

 Mat circles = new Mat();
 Imgproc.HoughCircles(gray, circles, Imgproc.HOUGH_GRADIENT, 1.0,
 (double)gray.rows()/16, // change this value to detect circles with different distances to each other
 100.0, 30.0, 1, 30); // change the last two parameters
 // (min_radius & max_radius) to detect larger circles

Python

 rows = gray.shape[0]
 circles = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, 1, rows / 8,
 param1=100, param2=30,
 minRadius=1, maxRadius=30)
  • 参数:
    • gray: 输入图像(灰度)。
    • circles: 一个向量,存储每个检测到的圆的 3 个值集:xc、yc、r。
    • hough_gradient:梯度: 定义检测方法。目前这是 OpenCV 中唯一可用的方法。
    • dp = 1:分辨率的反比。
    • min_dist = gray.rows/16:检测到的圆心之间的最小距离。
    • param_1 = 200:内部 Canny 边缘检测器的上阈值。
    • param_2 = 100*: 中心检测的阈值。
    • min_radius = 0:检测到的最小半径。如果未知,默认为 0。
    • max_radius = 0:检测的最大半径。如果未知,默认为 0。

绘制检测到的圆:

C++

 for( size_t i = 0; i < circles.size(); i++ )
 {
 Vec3i c = circles[i];
 Point center = Point(c[0], c[1]);
 // circle center
 circle( src, center, 1, Scalar(0,100,100), 3, LINE_AA);
 // circle outline
 int radius = c[2];
 circle( src, center, radius, Scalar(255,0,255), 3, LINE_AA);
 }

Java

 for (int x = 0; x < circles.cols(); x++) {
 double[] c = circles.get(0, x);
 Point center = new Point(Math.round(c[0]), Math.round(c[1]));
 // circle center
 Imgproc.circle(src, center, 1, new Scalar(0,100,100), 3, 8, 0 );
 // circle outline
 int radius = (int) Math.round(c[2]);
 Imgproc.circle(src, center, radius, new Scalar(255,0,255), 3, 8, 0 );
 }

Python

 if circles is not None:
 circles = np.uint16(np.around(circles))
 for i in circles[0, :]:
 center = (i[0], i[1])
 # circle center
 cv.circle(src, center, 1, (0, 100, 100), 3)
 # circle outline
 radius = i[2]
 cv.circle(src, center, radius, (255, 0, 255), 3)

您可以看到,我们将用红色绘制圆,用绿色小圆点绘制圆心。

显示检测到的圆,等待用户退出程序:

C++

 imshow("detected circles", src);
 waitKey();

Java

 HighGui.imshow("detected circles", src);
 HighGui.waitKey();

Python

 cv.imshow("detected circles", src)
 cv.waitKey(0)

结果

使用测试图像运行上述代码的结果如下所示:

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值