Python+Opencv实现多种形状的检测

15 篇文章 7 订阅

一、Hough变换是什么?

  Hough变换是由 P.V.C.Hough提出的一种算法,这种算法可以快速、准确的检测出图片中的直线、圆和椭圆等多种形状。在计算机视觉领域中得到了广泛的使用。

二、Hough变换原理简介

  Hough变换是一种特征提取算法,它已经被广泛的应用在机器视觉、图像分析和影像处理等多个方面。Hough变换的主要用途包括寻找图像中直线、圆或椭圆等在图像中的具体位置,其主要的原理是将图像转换到Hough变换空间中,将直角坐标系中的点转换到极坐标系中,通过数学关系的推导,我们可以得到直角坐标系中的直线对应到极坐标系中就是多条曲线的交点,即图像空间中的直线检测问题转化到Hough空间就成了检测曲线的汇集点点的问题。
  Hough变换的基本思想是基于点和线的对偶关系,图像空间XY中,所有通过点(x,y)的点所表示的方程为: y = p x + q \mathrm{y}=p x+q y=px+q;其中P表示的是直线的斜率,q表示直线的截距,也可以表示为 q = − p x + y q=-p x+y q=px+y;如下图所示,图像空间中过 ( x i , y j ) \left(x_{i}, y_{j}\right) (xi,yj)点的直线方程可以表示成 y i = p x i + q y_{i}=p x_{i}+q yi=pxi+q;也可以在参数空间中表示为 q = − p x i + y i q=-p x_{i}+y_{i} q=pxi+yi
在这里插入图片描述
  通过上图我们可以得出图像空间中共线的点和参数空间中的相交的线具有一一对应的关系;参数空间中相交于同一点的所有直线和图像空间中贡献的点相互对应,这就是所谓的点和线之间的对偶关系。Hough变换就是按照这种关系来将图像空间中的检测问题转变成参数空间中寻找交叉点,然后在参数空间中执行简单的累计统计来完成直线的检测任务。当直线接近于竖直方向时,此时我们用极坐标方程来表示该直线。具体的方程可以表示为 λ = x cos ⁡ θ + y sin ⁡ θ \lambda=x \cos \theta+y \sin \theta λ=xcosθ+ysinθ;根据上式,我们可以得出对于极坐标系中的任意一组点 ( λ , θ ) (\lambda, \theta) (λ,θ)都对应这一条直线,即这里将点和线的对偶关系转变成了点和正弦曲线的对偶关系。如下图所示,图a表示的是图像空间中的5个坐标点,它们和图b中的5条曲线相互对应, θ ∈ [ − 90 , + 90 ] , λ ∈ [ − 2 N 2 , + 2 N 2 ] \theta \in[-90,+90], \quad \lambda \in\left[-\frac{\sqrt{2} N}{2},+\frac{\sqrt{2} N}{2}\right] θ[90,+90],λ[22 N,+22 N],其中N表示图像的宽度。即图像空间中的的点和参数空间中的曲线相互对应,图b中的曲线1、3、5这3条曲线都经过K点,对应到图像空间中表示1、3、5处于同一条直线上面;图a中的2、3、4这3个点处于同一条直线上,对应于参数空间中表示它们所对应的曲线2、3、4都通过同一点L。
在这里插入图片描述

三、Hough变换实现步骤

  • 步骤1-首先建立一个二维数组,其对应的参数空间为,这个数组其实就相当于一个累加器;
  • 步骤2-然后使用顺序搜索的方式在图像中的所有目标像素中进行快速的搜索,针对图像中的每一个像素而言,在参数空间中根据式 λ = x cos ⁡ θ + y sin ⁡ θ \lambda=x \cos \theta+y \sin \theta λ=xcosθ+ysinθ计算出一个对应的位置,在累加器对应的位置上执行一次加1操作;
  • 步骤3-然后求出累加器中的最大值,也就是参数空间中的最大值,其对应的位置为 ( λ ′ , θ ′ ) \left(\lambda^{\prime}, \theta^{\prime}\right) (λ,θ)
  • 步骤4-最后将获得的参数空间位置 ( λ ′ , θ ′ ) \left(\lambda^{\prime}, \theta^{\prime}\right) (λ,θ)输入到式 λ = x cos ⁡ θ + y sin ⁡ θ \lambda=x \cos \theta+y \sin \theta λ=xcosθ+ysinθ中,从而找到该空间所对应的图像空间中的直线参数,即我们需要检测的结果。

四、Hough变换直线检测代码实现及效果展示

# coding=utf-8

# 导入python库
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 读取图片
img = cv2.imread('test3.jpg') 
# 彩色图片灰度化
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# 执行边缘检测
edges = cv2.Canny(gray,100,200)
# 显示原始结果

cv2.imwrite('edges.png',edges)
cv2.imshow('edge', edges)
# plt.subplot(121)
# plt.imshow(edges)

# 执行Hough直线检测
lines = cv2.HoughLines(edges,1,np.pi/180,160)
lines1 = lines[:,0,:]
for rho,theta in lines1:
    a = np.cos(theta)
    b = np.sin(theta)
    x0 = a*rho
    y0 = b*rho
    x1 = int(x0 + 1000*(-b))
    y1 = int(y0 + 1000*(a))
    x2 = int(x0 - 1000*(-b))
    y2 = int(y0 - 1000*(a)) 
    cv2.line(img,(x1,y1),(x2,y2),(255,0,0),1)

cv2.imwrite('line.png',img)
cv2.imshow('line', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# plt.subplot(122)
# plt.imshow(img)

在这里插入图片描述
  上图展示了Hough变换直线检测的结果。第1列表示的是原始的输入图片;第2列表示的是边缘检测的结果;第3列表示Hough直线检测结果。我们可以发现Hough变换准确的检测到图片中的所有直线。需要主要的是用户需要根据自己的需要对边缘检测的参数进行调节。

五、Hough变换圆形检测代码实现及效果展示

# coding=utf-8
# 导入python包
import numpy as np
import argparse
import cv2

# 构建并解析参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", required = True, help = "Path to the image")
args = vars(ap.parse_args())

# 读取彩色图片
image = cv2.imread(args["image"])
output = image.copy()
# 将其转换为灰度图片
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 应用hough变换进行圆检测
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1.2, 100)

# 确保至少发现一个圆
if circles is not None:
	# 进行取整操作
	circles = np.round(circles[0, :]).astype("int")

	# 循环遍历所有的坐标和半径
	for (x, y, r) in circles:
		# 绘制结果
		cv2.circle(output, (x, y), r, (0, 255, 0), 4)
		cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1)

	# 显示结果
	cv2.imshow("output", np.hstack([image, output]))
	cv2.waitKey(0)

在这里插入图片描述
  上图展示了Hough变换圆形检测的结果。每一行表示一个测试图片,第1列表示的是原始的输入图片,第2列表示的是Hough检测的结果。通过上图我们可以获得一些信息,即Hough变换不仅能够处理简单的情况,也能很好的处理复杂的情况。需要注意的是用户需要根据自己的输入图片去调节cv2.HoughCircles函数中的一些关键参数。

六、基于Hough的椭圆检测代码实现及效果展示

# coding=utf-8

import matplotlib.pyplot as plt
from skimage import data,draw,color,transform,feature

#加载图片,转换成灰度图并检测边缘
image_rgb = data.coffee()[0:220, 160:420] #裁剪原图像,不然速度非常慢
image_gray = color.rgb2gray(image_rgb)
edges = feature.canny(image_gray, sigma=2.0, low_threshold=0.55, high_threshold=0.8)

#执行椭圆变换
result =transform.hough_ellipse(edges, accuracy=20, threshold=250,min_size=100, max_size=120)
result.sort(order='accumulator') #根据累加器排序

#估计椭圆参数
best = list(result[-1])  #排完序后取最后一个
yc, xc, a, b = [int(round(x)) for x in best[1:5]]
orientation = best[5]

#在原图上画出椭圆
cy, cx =draw.ellipse_perimeter(yc, xc, a, b, orientation)
image_rgb[cy, cx] = (0, 0, 255) #在原图中用蓝色表示检测出的椭圆

# #分别用白色表示canny边缘,用红色表示检测出的椭圆,进行对比
# edges = color.gray2rgb(edges)
# edges[cy, cx] = (250, 0, 0) 

fig2, (ax1, ax2) = plt.subplots(ncols=2, nrows=1, figsize=(8, 4))

ax1.set_title('Original picture')
ax1.imshow(image_rgb)

ax2.set_title('Detect result')
ax2.imshow(edges)

plt.show()

在这里插入图片描述
  上图展示了Hough变换椭圆检测的结果。第1列表示的是原始的输入图片,图中的蓝线表示检测的结果;第2列表示检测的结果,并将其绘制在一张存在的图片中。图中可以看出Hough变换可以很好的检测出图片中的椭圆。

七、轮廓检测不同形状代码实现及效果展示

# coding=utf-8
# 导入python包
import cv2

# 读取彩色图片
img = cv2.imread('rect1.png')
# 转换为灰度图片
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 进行二值化处理
ret,binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

# 寻找轮廓
_,contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 绘制不同的轮廓
draw_img0 = cv2.drawContours(img.copy(),contours,0,(0,255,255),3)
draw_img1 = cv2.drawContours(img.copy(),contours,1,(255,0,255),3)
draw_img2 = cv2.drawContours(img.copy(),contours,2,(255,255,0),3)
draw_img3 = cv2.drawContours(img.copy(), contours, -1, (0, 0, 255), 3)

# 打印结果
print ("contours:类型:",type(contours))
print ("第0 个contours:",type(contours[0]))
print ("contours 数量:",len(contours))

print ("contours[0]点的个数:",len(contours[0]))
print ("contours[1]点的个数:",len(contours[1]))

# 显示并保存结果
cv2.imshow("img", img)
cv2.imshow("draw_img0", draw_img0)
cv2.imshow("draw_img1", draw_img1)
cv2.imshow("draw_img2", draw_img2)
cv2.imwrite("rect_result.png", draw_img3)
cv2.imshow("draw_img3", draw_img3)

cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述
  上图展示了利用轮廓检测不同形状的结果。每一行展示了一个测试图片,第1列展示的是输入图片,第2类展示的是输出结果。通过上图我们可以看到轮廓检测算法可以准确的检测到图中的所有轮廓并准确的将他们绘制出来。这在现实场景中具有很广泛的应用价值。

八、获取图像中的黑色形状块

# coding=utf-8
# 导入python包
import numpy as np
import argparse
import imutils
import cv2

# 构建并解析参数
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--image", help = "path to the image file")
args = vars(ap.parse_args())

# 读取图片
image = cv2.imread(args["image"])

# 寻找到图片中的黑色形状块
lower = np.array([0, 0, 0])
upper = np.array([15, 15, 15])
shapeMask = cv2.inRange(image, lower, upper)

# 在mask中寻找轮廓
cnts = cv2.findContours(shapeMask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
print("I found {} black shapes".format(len(cnts)))
cv2.imwrite("Mask.png", shapeMask)
cv2.imshow("Mask", shapeMask)

# 循环遍历所有的轮廓
for c in cnts:
	# draw the contour and show it
	cv2.drawContours(image, [c], -1, (0, 255, 0), 2)
cv2.imwrite("shape1.png", image)
cv2.imshow("Image", image)
cv2.waitKey(0)

在这里插入图片描述
  上图展示了使用python+opencv自动检测到图像中的黑色形状块,第1列表示的是原始的输入图片,和代码中的image对应;第2列表示的是获取到的掩模,对应于代码中的shapeMask;第3列表示的是检测的结果,对应于代码中的image。通过上图我们可以发现该算法能够准确的检测出这些不同的形状块。

九、移除图中的圆和椭圆

# coding=utf-8
# 导入python包
import numpy as np
import imutils
import cv2

def is_contour_bad(c):
	# 近似轮廓
	peri = cv2.arcLength(c, True)
	approx = cv2.approxPolyDP(c, 0.02 * peri, True)

	# 判断当前的轮廓是不是矩形
	return not len(approx) == 4

# 首先读取图片;然后进行颜色转换;最后进行边缘检测
image = cv2.imread("remove.png")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
edged = cv2.Canny(gray, 50, 100)
cv2.imshow("Original", image)

# 寻找图中的轮廓并设置mask
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
mask = np.ones(image.shape[:2], dtype="uint8") * 255

# 循环遍历所有的轮廓
for c in cnts:
	# 检测该轮廓的类型,在新的mask中绘制结果
	if is_contour_bad(c):
		cv2.drawContours(mask, [c], -1, 0, -1)

# 移除不满足条件的轮廓并显示结果
image = cv2.bitwise_and(image, image, mask=mask)
cv2.imwrite("Mask.png", mask)
cv2.imshow("Mask", mask)
cv2.imwrite("result.png", image)
cv2.imshow("After", image)
cv2.waitKey(0)

在这里插入图片描述

十、思维扩展

  在现实场景中,我们经常会遇到检测图片中具有不同形状的目标的任务。本文主要关注的是直线、圆、椭圆、三角形等,对于那些不规则的形状而言,其实Opencv中已经内嵌了其它的函数,聪明的你一定可以找到这个函数完成一些更加复杂的形状检测任务。

参考资料

[1] 参考链接

注意事项

[1] 如果您对AI、自动驾驶、AR、ChatGPT等技术感兴趣,欢迎关注我的微信公众号“AI产品汇”,有问题可以在公众号中私聊我!
[2] 该博客是本人原创博客,如果您对该博客感兴趣,想要转载该博客,请与我联系(qq邮箱:1575262785@qq.com),我会在第一时间回复大家,谢谢大家的关注.
[3] 由于个人能力有限,该博客可能存在很多的问题,希望大家能够提出改进意见。
[4] 如果您在阅读本博客时遇到不理解的地方,希望您可以联系我,我会及时的回复您,和您交流想法和意见,谢谢。
[5] 本文测试的图片可以通过关注微信公众号AI产品汇之后找我索取!
[6] 本人业余时间承接各种本科毕设设计和各种小项目,包括图像处理(数据挖掘、机器学习、深度学习等)、matlab仿真、python算法及仿真等,有需要的请加QQ:1575262785详聊!!!

  • 36
    点赞
  • 361
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: Python OpenCV可以使用多种方法进行矩形检测,其中最常用的方法是使用轮廓检测。具体步骤如下: 1. 读取图像并将其转换为灰度图像。 2. 对图像进行二值化处理,使得矩形区域变为白色,背景变为黑色。 3. 使用findContours函数查找图像中的轮廓。 4. 对每个轮廓进行逐一处理,使用approxPolyDP函数将其近似为一个多边形。 5. 判断多边形是否为矩形,如果是则将其绘制出来。 需要注意的是,矩形检测的精度和效率都受到图像质量和算法参数的影响,因此需要根据具体情况进行调整。 ### 回答2: Python OpenCV 是一种常用的计算机视觉库,它可以用于图像处理、计算机视觉、机器学习等领域。其中,矩形检测OpenCV 库中的一个重要功能,它能够在输入图像中自动检测出所有的矩形,并给出矩形的顶点坐标,以便后续处理。 在 Python OpenCV 中进行矩形检测,需要使用 cv2.rectangle() 函数。该函数的语法格式如下: cv2.rectangle(img, pt1, pt2, color, thickness) 其中,img 表示输入图像,pt1 和 pt2 表示矩形的对角顶点坐标(pt1 为左上角,pt2 为右下角),color 表示矩形线条颜色,可以用 RGB 值表示,thickness 表示矩形线条宽度。例如,下面的代码可以在输入图像中绘制一个红色的矩形: import cv2 img = cv2.imread('test.jpg') pt1 = (100, 100) pt2 = (200, 200) color = (0, 0, 255) thickness = 2 cv2.rectangle(img, pt1, pt2, color, thickness) cv2.imshow('image', img) cv2.waitKey(0) 此外,Python OpenCV 还提供了一些用于矩形检测的函数,例如 cv2.findContours()、cv2.boundingRect() 等函数,这些函数能够检测出输入图像中的所有轮廓,并根据轮廓的形状、大小等信息,计算出能够包含轮廓的最小矩形。这些最小矩形也可以用 cv2.rectangle() 函数绘制出来,从而实现矩形检测的功能。 总之,Python OpenCV 提供了多种方法实现矩形检测,开发者可以根据自己的需求和场景选择合适的方法。在使用过程中,需要注意输入图像的质量和清晰度,以及矩形检测的精度和效率等问题,这些因素都会影响矩形检测的效果和性能。 ### 回答3: 矩形检测是图像处理领域的一项重要技术,主要用于在图像中自动或半自动地识别出矩形,并对其进行分类、统计等处理。而PythonOpenCV是这个领域中应用最广泛和效果最好的两种工具,下面就介绍一下Python Opencv矩形检测实现方法。 矩形检测的基本原理是在图像中找到边缘,并将其转化为矩形。这个过程涉及到一系列图像处理操作,包括边缘检测、二值化、形态学变换、轮廓检测、过滤、排序等。 首先,需要将图像转换为灰度图像或二值图像,以便于后续的处理操作。这可以通过使用OpenCV中的cv2.cvtColor()函数和cv2.threshold()函数来实现。 然后,使用形态学变换操作,如膨胀、腐蚀、开运算和闭运算等,来去除噪声和平滑图像。这可以使用OpenCV中的cv2.morphologyEx()函数等函数来实现。 之后,使用边缘检测算法,如Canny算法或Sobel算法等,来提取图像中的边缘信息。这可以使用OpenCV中的cv2.Canny()函数或cv2.Sobel()函数等函数来实现。 接下来,使用轮廓检测算法,如cv2.findContours()函数来检测图像中的轮廓,并通过外接矩形求解矩形信息。在求解矩形信息时,可以通过使用cv2.boundingRect()函数来获取矩形的位置和大小。 最后,可以使用过滤和排序算法来筛选和排序检测出的所有矩形。可以通过计算矩形面积、宽高比、方向等特征来进行筛选和排序,也可以通过使用cv2.contourArea()函数、cv2.minAreaRect()函数等函数来实现。 综上所述,Python Opencv矩形检测是一项非常实用的图像处理技术,可以应用于识别和分类图像中的矩形,并广泛应用于计算机视觉、目标识别、自动驾驶等领域。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值