0
点赞
收藏
分享

微信扫一扫

[OpenCV实战]33 使用OpenCV进行Hough变换

1 什么是霍夫变换

霍夫变换是用于检测图像中的简单形状(诸如圆形,线条等)的特征提取方法。“简单”形状是可以仅由几个参数表示的形状。例如,一条线可以用两个参数(斜率,截距)表示,一个圆有三个参数:中心坐标和半径(x,y,r)。霍夫变换在图像中找到这样的形状方面做得很好。使用Hough变换的主要优点是它对遮挡不敏感。让我们通过一个例子来看看霍夫变换是如何工作的。

1.1 应用霍夫变换以检测图像中的线条

极坐标中的线条方程如下:

https://file.cfanz.cn/uploads/png/2022/05/07/10/94L4812E02.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

这里

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

表示线与原点的垂直距离(以像素为单位),

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

是以弧度为单位测量的角度,如下图所示。

https://file.cfanz.cn/uploads/jpeg/2022/05/07/10/01P17WE5dB.jpeg?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

您可能会想问我们为什么不使用下面给出的熟悉的等式:

https://file.cfanz.cn/uploads/png/2022/05/07/10/FFTY1541cK.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

原因是斜率m可以取-

https://file.cfanz.cn/uploads/png/2022/05/07/10/8C3H47SJ38.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

到+

https://file.cfanz.cn/uploads/png/2022/05/07/10/8C3H47SJ38.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

之间的值。对于Hough变换,参数需要有界限。您可能还有一个后续问题。在

https://file.cfanz.cn/uploads/png/2022/05/07/10/a2T8L2a62R.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

形式上,

https://file.cfanz.cn/uploads/png/2022/05/07/10/U13BM269c2.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

是有界的,但是

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

能取0到+

https://file.cfanz.cn/uploads/png/2022/05/07/10/8C3H47SJ38.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

之间的值吗?这在理论上可能是正确的,但在实践中,

https://file.cfanz.cn/uploads/png/2022/05/07/10/8C3H47SJ38.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

也是有限的,因为图像本身是有限的。

1.2 累加器

当我们说二维空间中的一条线用参数化

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

https://file.cfanz.cn/uploads/png/2022/05/07/10/a2T8L2a62R.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

表达时,意味着如果我们选择一个

https://file.cfanz.cn/uploads/png/2022/05/07/10/a2T8L2a62R.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

,它就对应一条线。想象一个二维数组, 想象一个二维数组,其中x轴具有所有可能的

https://file.cfanz.cn/uploads/png/2022/05/07/10/8C3H47SJ38.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

值,y轴具有所有可能的

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

值。该2D阵列中的任何点坐标对应于一条线。

https://file.cfanz.cn/uploads/png/2022/05/07/10/DeQGB0EfaJ.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

这个2D数组称为累加器,因为我们将使用此数组的bin来收集有关图像中存在哪些线条的信息。左上角的单元格对应于(-R,0),右下角对应于(R,

https://file.cfanz.cn/uploads/png/2022/05/07/10/P16F3YaU34.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

)。稍后我们将看到bin(

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

https://file.cfanz.cn/uploads/png/2022/05/07/10/U13BM269c2.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

)内的值随着参数

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

https://file.cfanz.cn/uploads/png/2022/05/07/10/U13BM269c2.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

而改变。

1.3 线条检测

执行以下步骤以检测图像中的线。

  1. 首先,我们需要创建一个累加器数组。您选择的单元格数量是一个设计决策。假设您选择了10×10累加器。这意味着和获取10个不同的值。因此您将能够检测100种完全不同的线条。累加器的大小也取决于图像的分辨率。但如果你刚刚开始,不要担心完全正确。选择一个20×20的数字,看看你得到了什么结果。

    https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

    https://file.cfanz.cn/uploads/png/2022/05/07/10/U13BM269c2.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

  2. 检测边缘

现在我们已经设置了累加器,我们希望收集累加器的每个单元的信息,因为累加器的每个单元对应于一行。我们如何通过获取单元的信息,如果图像中有一条可见的线,边缘检测器应该在这条线的边界检测到边缘像素点。这些边缘像素为线条的存在提供了证据。边缘检测的输出是边缘像素的阵列

https://file.cfanz.cn/uploads/png/2022/05/07/10/eB59ea2V71.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

  1. 边缘像素投票

对于上述数组中的每个边缘像素(x,y),我们改变

https://file.cfanz.cn/uploads/png/2022/05/07/10/U13BM269c2.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

从0到

https://file.cfanz.cn/uploads/png/2022/05/07/10/P16F3YaU34.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

的值,并根据线条极坐标公式计算

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

。我们改变三个像素点的

https://file.cfanz.cn/uploads/png/2022/05/07/10/U13BM269c2.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

(由三条彩色曲线表示),并获得对应

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

的值。如下图所示。下图中三条线代表三个像素点不同

https://file.cfanz.cn/uploads/png/2022/05/07/10/U13BM269c2.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

的取值,其中横坐标为

https://file.cfanz.cn/uploads/png/2022/05/07/10/U13BM269c2.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

值,纵坐标为

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

值(r值)。如果三个点在一条直线上,那么三个点的

https://file.cfanz.cn/uploads/png/2022/05/07/10/U13BM269c2.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

曲线就会相交于一点。

https://file.cfanz.cn/uploads/png/2022/05/07/10/5E37MLb5I3.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

通常,我们有数百个边缘像素,越多的曲线交于一点就意味着这个交点表示的直线由更多的点组成,通过累加器统计交于一点的曲线数,并设定阈值来决定是否检测到一条直线。

更多霍夫曼变换说明见:

在OpenCV中,使用Hough变换的线检测在函数HoughLines和HoughLinesP中实现。此函数采用以下参数: -

edge

:边缘检测器的输出(灰度图)。-

lines

:用于存储行开头和结尾坐标的向量。-

rho:图像单位

分辨率参数,

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

以像素为单位。我们选择2像素点-

theta

https://file.cfanz.cn/uploads/png/2022/05/07/10/U13BM269c2.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

以弧度表示的参数单位分辨率。我们选择2度-

阈值

:检测线的最小交叉点数。 下面我们展示了使用霍夫变换进行线检测的结果。请记住,检测到的线条的质量在很大程度上取决于边缘图的质量。因此,在现实世界中,当您可以控制环境并因此获得一致的边缘图时,或者当您可以为您正在寻找的特定类型的边缘训练边缘检测器时,使用Hough变换。

https://file.cfanz.cn/uploads/jpeg/2022/05/07/10/U61L4674V6.jpeg?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

1.4 圆环的检测

在线Hough变换的情况下,我们需要两个参数,(

https://file.cfanz.cn/uploads/png/2022/05/07/10/U13BM269c2.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

https://file.cfanz.cn/uploads/png/2022/05/07/10/7HJ2JV55X7.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

)但是为了检测圆,我们需要三个参数 -

https://file.cfanz.cn/uploads/png/2022/05/07/10/V511d98TO1.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

圆心的坐标。- 半径。 可以想象,圆形探测器需要一个3D累加器,每个参数一个。

圆的方程由下式给出:

https://file.cfanz.cn/uploads/png/2022/05/07/10/E03612P3bY.png?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

按照以下步骤检测图像中的圆圈:

1.借助边缘检测器(Canny)找到给定图像中的边缘。

2.为了检测图像中的圆,我们设置半径的最大值和最小值的阈值。

3.信息收集在3D累加器阵列中,以确定是否存在具有不同中心和半径的圆。

在OpenCV中使用HoughCircles函数来检测图像中的圆圈。它需要以下参数:

image:输入图像。

methods:检测方法。

dp:累加器分辨率和图像分辨率的反比。

mindst:检测到圆圈的中心之间的最小距离。

param_1和param_2:这些是特定于方法的参数。

min_Radius:要检测的圆的最小半径(以像素为单位)。

max_Radius:要检测的最大半径(以像素为单位)。

使用Hough变换的圆检测结果如下所示。结果的质量在很大程度上取决于您可以找到的边缘质量,以及您对要检测的圆的大小有多少先验知识。

https://file.cfanz.cn/uploads/jpeg/2022/05/07/10/89MD22BK4N.jpeg?x-oss-process=image/watermark,size_14,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_20,type_ZmFuZ3poZW5naGVpdGk=

2 代码

所有代码见:

线条检测:

C++:

#include "pch.h"
#include opencv2/opencv.hpp
#include stdio.h
#include iostream

using namespace cv;
using namespace std;

// variables to store images
Mat dst, cimg, gray, img, edges;

int initThresh;
const int maxThresh = 1000;
double th1, th2;

// create a vector to store points of line
vectorVec4i lines;

void onTrackbarChange(int, void*)
{
//复制目标图像
cimg = img.clone();
//结果图像
dst = img.clone();

th1 = initThresh;
th2 = th1 * 0.4;
//canny边缘检测
Canny(img, edges, th1, th2);

// apply hough line transform 霍夫曼变换
HoughLinesP(edges, lines, 2, CV_PI / 180, 50, 10, 100);

// draw lines on the detected points 画线
for (size_t i = 0; i lines.size(); i++)
{
//提取线条坐标点
Vec4i l = lines[i];
line(dst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 1, LINE_AA);
}

// show the resultant image
imshow("Result Image", dst);
imshow("Edges", edges);
}

int main()
{
// Read image (color mode) 读图
img = imread("./image/lanes.jpg", 1);
dst = img.clone();

if (img.empty())
{
cout "Error in reading image" endl;
return -1;
}

// Convert to gray-scale 转换为灰度图像
cvtColor(img, gray, COLOR_BGR2GRAY);

// Detect edges using Canny Edge Detector
// Canny(gray, dst, 50, 200, 3);

// Make a copy of original image
// cimg = img.clone();

// Will hold the results of the detection
namedWindow("Edges", 1);
namedWindow("Result Image", 1);

// Declare thresh to vary the max_radius of circles to be detected in hough transform
// 霍夫曼变换阈值
initThresh = 500;

// Create trackbar to change threshold values
//滑动条
createTrackbar("threshold", "Result Image", initThresh, maxThresh, onTrackbarChange);
onTrackbarChange(initThresh, 0);

while (true)
{
int key;
key = waitKey(1);
if ((char)key == 27)
{
break;
}
}
destroyAllWindows();
return 0;
}

Python:

import cv2
import numpy as np

def onTrackbarChange(max_slider):
global img
global dst
global gray

dst = np.copy(img)

th1 = max_slider
th2 = th1 * 0.4
edges = cv2.Canny(img, th1, th2)

# Apply probabilistic hough line transform
lines = cv2.HoughLinesP(edges, 2, np.pi/180.0, 50, minLineLength=10, maxLineGap=100)

# Draw lines on the detected points
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(dst, (x1, y1), (x2, y2), (0,0,255), 1)

cv2.imshow("Result Image", dst)
cv2.imshow("Edges",edges)

if __name__ == "__main__":

# Read image
img = cv2.imread('./image/lanes.jpg')

# Create a copy for later usage
dst = np.copy(img)

# Convert image to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Create display windows
cv2.namedWindow("Edges")
cv2.namedWindow("Result Image")

# Initialize threshold value
initThresh = 500

# Maximum threshold value
maxThresh = 1000

cv2.createTrackbar("threshold", "Result Image", initThresh, maxThresh, onTrackbarChange)
onTrackbarChange(initThresh)

while True:
key = cv2.waitKey(1)
if key == 27:
break

cv2.destroyAllWindows()

圆环检测:

C++:

#include "pch.h"
#include opencv2/opencv.hpp
#include stdio.h
#include iostream
#include string

using namespace cv;
using namespace std;

// Declare variables to store images
Mat gray, cimg, img, edges;

int initThresh;
const int maxThresh = 200;
double p1, p2;

// Vector to store circle points
vectorVec3f circles;

void onTrackbarChange(int, void*)
{
cimg = img.clone();

p1 = initThresh;
p2 = initThresh * 0.4;

// Detect circles using HoughCircles transform 霍夫曼变换
HoughCircles(gray, circles, HOUGH_GRADIENT, 1, cimg.rows / 64, p1, p2, 25, 50);

//画圆
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]);
// Draw the outer circle
circle(cimg, center, radius, Scalar(0, 255, 0), 2);
// Draw the center of the circle
circle(cimg, center, 2, Scalar(0, 0, 255), 3);
}

// Display output image
imshow("Image", cimg);

// Edge image for debugging
Canny(gray, edges, p1, p2);
imshow("Edges", edges);
}

int main()
{
//读图
img = imread("./image/brown-eyes.jpg", IMREAD_COLOR);

if (img.empty())
{
cout "Error reading image" endl;
return -1;
}

// Convert to gray-scale 转换为灰度图
cvtColor(img, gray, COLOR_BGR2GRAY);

// Will hold the results of the detection
namedWindow("Edges", 1);
namedWindow("Image", 1);

//初始阈值
initThresh = 105;
//滑动条
createTrackbar("Threshold", "Image", initThresh, maxThresh, onTrackbarChange);
onTrackbarChange(initThresh, 0);

imshow("Image", img);
while (true)
{
int key;
key = waitKey(0);
if ((char)key == 27)
{
break;
}
}

destroyAllWindows();
return 0;
}

Python:

import cv2
import numpy as np
import sys

def onTrackbarChange(max_slider):
cimg = np.copy(img)

p1 = max_slider
p2 = max_slider * 0.4

# Detect circles using HoughCircles transform
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, cimg.shape[0]/64, param1=p1, param2=p2, minRadius=25, maxRadius=50)

# If at least 1 circle is detected
if circles is not None:
cir_len = circles.shape[1] # store length of circles found
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
# Draw the outer circle
cv2.circle(cimg, (i[0], i[1]), i[2], (0, 255, 0), 2)
# Draw the center of the circle
cv2.circle(cimg, (i[0], i[1]), 2, (0, 0, 255), 3)
else:
cir_len = 0 # no circles detected

# Display output image
cv2.imshow('Image', cimg)

# Edge image for debugging
edges = cv2.Canny(gray, p1, p2)
cv2.imshow('Edges', edges)

if __name__ == "__main__":
# Read image
img = cv2.imread("./image/brown-eyes.jpg")

# Convert to gray-scale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Create display windows
cv2.namedWindow("Edges")
cv2.namedWindow("Image")

# Trackbar will be used for changing threshold for edge
initThresh = 105
maxThresh = 200

# Create trackbar
cv2.createTrackbar("Threshold", "Image", initThresh, maxThresh, onTrackbarChange)
onTrackbarChange(initThresh)

while True:
key = cv2.waitKey(1)
if key == 27:
break

cv2.destroyAllWindows()
举报

相关推荐

0 条评论