Python OpenCV实现图形检测示例详解


Posted in Python onApril 08, 2022

图形检测在计算机视觉开发中是一项非常重要的操作,算法通过对图像的检测,分析出图像中可能存在哪些形状。除此之外,除了让计算机识别轮廓之外,轮廓也需要让人看到,这就需要再分别读这些轮廓的形状进行描绘。

1. 轮廓识别与描绘

cv2.findContours() & cv2.drawContours() 方法

在Python中OpenCV提供了findContours() 方法来判断图像的轮廓,drawContours()方法来绘制轮廓。

1.1 cv2.findComtours()方法

cv2.findComtours()方法的语法如下

cv2.contours, hierarchy = findContours(image, mode, method)

其中

  • image 即原图像
  • mode 轮廓检索模式,具体参数被总结在了下表中
  • method 使用的方法,具体参数也被总结在了下表中

contours是一个列表,列表的每一个元素都是由某个轮廓的像素的坐标组成的数组。

hierarchy是轮廓与轮廓之间的层次关系。

mode取值表

mode值 描述
cv2.RETR_EXTERNAL 只检测外轮廓
cv2.RETR_LIST 检测所有轮廓,但不建立层次关系
cv2.RETR_CCOMP 检测所有轮廓,并建立两级层次关系
cv2.RETR_TREE 建立所有轮廓,并建立树状结构的层次关系

method取值表

cv2.PATH_APPROX_ 储存轮廓上所有点
cv2.PATH_APPROX_NONE 只保存水平、垂直或对角线轮廓的端点
cv2.PATH_APPROX_SIMPLE Ten-Chinl
cv2.PATH_APPROX_TC89_L1 Ten-Chinl近似算法的一种
cv2.PATH_APPROX_TC89_KCOS Ten-Chinl近似算法的一种

1.2 cv2.drawContours() 方法

cv2.drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)

  • image 目标图像
  • contours findComtours()方法得到的轮廓列表
  • contourldx 轮廓中列表中,绘制轮廓的对象的索引,如果为-1则表示绘制所有
  • color 绘制线条时的颜色,使用BGR格式描述
  • thickness 线条粗细程度,-1表示实心
  • lineType 绘制轮廓时线条的类型(可选参数)
  • hierarchy findComtours()方法得到的层次关系(可选参数)
  • maxLevel 绘制轮廓的层次深度,最深绘制在maxLevel层。(可选参数)
  • offset 偏移量 (可选参数)

drawContours() 方法返回的是一个图像(数组)。

1.3 代码示例

以队此小鸟图操作为例(test1.jpg):

Python OpenCV实现图形检测示例详解

import cv2
img = cv2.imread("test1.jpg")  
# 彩色图像转为变成单通道灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
# 二值化处理
t, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)  
# 检测图像中出现的所有轮廓,记录轮廓的每一个点
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
# 绘制所有轮廓,宽度为5,颜色为红色
cv2.drawContours(img, contours, -1, (0, 0, 255), 5)
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

程序执行结果展示如下,图中所有能够识别出的轮廓被描出:

Python OpenCV实现图形检测示例详解

2. 轮廓拟合

轮廓拟合,即,将凹凸不平的轮廓用平整的几何图形体现出来。这里展示使用矩形和圆形拟合两种方法。

2.1 矩形包围框拟合 - cv2.boundingRect()

在Python中OpenCV提供了cv2.boundingRect()来计算轮廓的最小矩形边界的坐标 ,其语法如下

retval = cv2.boundingRect(array)

其中参数array为轮廓数组。即,cv2.findComtours()方法的执行结果中的contours中的元素。

返回值retval是一个包含着四个整数值的元组,四个值依次是左上角顶点的横坐标,左上角顶点的纵坐标,矩形的宽,矩形的高。

常常也可以写成x,y,w,h = retval = cv2.boundingRect(array)

还以这张小鸟图片(test1.jpg)为例,在上一个部分的示例中,我们找出并绘制出了图中所有的轮廓,经过调试,发现被识别出的轮廓共有94个。

我们要从数组列表中,选择出表示小鸟轮廓的位置的数组。

从上图中可以看出,小鸟的轮廓是所有轮廓中最大的。即该数组的 shape[0] 最大。即我们只用找出 shape[0]最大的即可。

import cv2
img = cv2.imread("test1.jpg") 
# 从彩色图像变成单通道灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
# 将灰度图像进行二值化阈值处理
t, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 获取二值化图像中的轮廓极轮廓层次数据
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 找出小鸟的轮廓
n1 = 1
n2 = 0
index = 0
for arr in contours:
    if len(arr) > n1:
        n1 = len(arr)
        index = n2
    n2 += 1
print(index)

x, y, w, h = cv2.boundingRect(contours[index])
# 绘制红色矩形
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)  
cv2.imshow("img", img) 
cv2.waitKey()
cv2.destroyAllWindows() 

绘制出矩形包围框效果如下:

Python OpenCV实现图形检测示例详解

2.2圆形包围框拟合 - cv2.minEnclosingCircle()

在Python中OpenCV提供了cv2.minEnclosingCircle()来计算轮廓的最小圆形边界的圆心和半径 ,其语法如下

center,radius = minEnclosingCircle(points)

其中

  • points的轮廓数组
  • center最小圆形包围框的圆心的横纵坐标。是元组类型。
  • radius是最小圆形包围款更多半径,浮点类型。

同样的算法,只是这次调用cv2.minEnclosingCircle()方法,其他不变:

import cv2
img = cv2.imread("test1.jpg")  # 读取原图
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 从彩色图像变成单通道灰度图像
# 将灰度图像进行二值化阈值处理
t, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 获取二值化图像中的轮廓极轮廓层次数据
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

n1 = 1
n2 = 0
index = 0
for arr in contours:
    if len(arr) > n1:
        n1 = len(arr)
        index = n2
    n2 += 1


center, radius = cv2.minEnclosingCircle(contours[index])
# 圆心点横坐标转为近似整数
x = int(round(center[0]))
# 圆心点纵坐标转为近似整数  
y = int(round(center[1]))  
cv2.circle(img, (x, y), int(radius), (0, 0, 255), 2)
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

绘制出圆形包围框效果如下(因为尺寸问题,只画出了一部分):

Python OpenCV实现图形检测示例详解

3. 凸包 绘制

使用矩形框和圆形框对图形的贴合程度往往都会较差。为了提高这个贴合程度,我们可以使用“凸包”。

所谓凸包,就是最逼近轮廓的多边形。

在Python中OpenCV提供了 cv2.bonvexHull()方法来计算凸包

cv2.bonvexHull()方法语法如下:

hull = convexHull(points, clockwise=None, returnPoints=None)

其中

  • points 是轮廓数组
  • clockwise 是布尔类型的参数,默认为True,表示凸包中的点按顺时针排序,为False时则按逆时针 排序。
  • returnPoints 是布尔类型的参数,默认为True时返回点坐标。如果为False则返回点索引。

返回值hull是凸包的点阵数组

依然以“test1.jpg为例”,为图中的小鸟绘制凸包:

import cv2

img = cv2.imread("test1.jpg")
# 转为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化阈值处理
ret, binary = cv2.threshold(gray, 127, 225, cv2.THRESH_BINARY)
# 检测图像中出现的所有轮廓
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

n1 = 1
n2 = 0
index = 0
for arr in contours:
    if len(arr) > n1:
        n1 = len(arr)
        index = n2
    n2 += 1

hull = cv2.convexHull(contours[index])
cv2.polylines(img, [hull], True, (0, 0, 255), 2)
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

Python OpenCV实现图形检测示例详解

4. Canny边缘检测 - cv2.Canny()

4.1 cv2.Canny() 用法简介

Canny边缘检测算法是John F.Canny在1986年开发的一个多级边缘检测算法。

Canny边缘检测算法通过像素的梯度变化寻找图像的边缘,最终可以绘制出十分精细的二值边缘图像

edges = cv2.Canny(image, threshold1, threshold2, apertureSize=None, L2gradient=None)

其中

  • image 即原图像
  • threshold1   第一个阈值,一般为最小阈值
  • threshold2   第二个阈值,一般为最大阈值
  • apertureSize  Sobel算子的孔径大小
  • L2gradient 计算图像梯度的标识。默认为False。为True时采用更精准的算法进行计算。

关于这两个阈值怎么用,这涉及到了算法的底层逻辑,还请自行探索。这里一种可以接受的解释是:低于阈值1的像素点,会被认为不构成边缘,而高于阈值2的像素点,会被认为构成边缘。

最后返回值edges是一个二值的灰度图像。

4.2 代码示例

下边对test1.jpg以三组不同的阈值来做Canny边缘检测,根据处理结果感受算法效果:

- 当阈值为 10-50 时

import cv2
img = cv2.imread("test1.jpg")
r1 = cv2.Canny(img, 10, 50)
cv2.imshow("r1", r1)
cv2.waitKey()
cv2.destroyAllWindows()

Python OpenCV实现图形检测示例详解

- 当阈值为100-200时

import cv2
img = cv2.imread("test1.jpg")
r2 = cv2.Canny(img, 100, 200)
cv2.imshow("r2", r2)
cv2.waitKey()
cv2.destroyAllWindows()

Python OpenCV实现图形检测示例详解

- 当阈值为400-600时

import cv2
img = cv2.imread("test1.jpg")
r3 = cv2.Canny(img, 400, 600)

cv2.imshow("r3", r3)
cv2.waitKey()
cv2.destroyAllWindows()

Python OpenCV实现图形检测示例详解

5. 霍夫变换

5.1 概述

霍夫变换是一种特征检测,通过霍夫变换可以检测出图像中存在的特殊的形状。比如,直线,圆等。

霍夫变换检测直线时,算法有两个,

一个是cv2.HoughLines() 方法,用于检测无限延长的直线;

另一个是cv2.HoughLinesP() 方法,用于检测线段。

霍夫变换检测圆,使用的是**cv2.HoughCircles()**方法。

使用这三个方法前,都要先对图像进行降噪处理(使用滤波器),以去除干扰。

5.2 cv2.HoughLines() 检测直线

cv2.HoughLines()语法如下:

lines = cv.HoughLines( image, rho, theta, threshold[,srn][,stn])

其中

  • image 即原图像
  • rho 指的是搜索直线使用的半径步长,其值为1时表示检测所有。(即极坐标中的ρ)
  • theta 指的是搜索直线的角度,值为π/180°时,表示检测所有角度。(即极坐标中的θ)
  • threshold 指的是阈值,点的数量(也称投票数)。因为直线的长度取决于直线上的点的数量。所以如果达不到这个长度,就不会被
  • 判定为直线。同理,当该阈值越小,检测出的直线也就越多。
  • srn 对于多尺度霍夫变换,srn表示对rho的 距离分辨率 的除数
  • stn 对于多尺度霍夫变换,stn表示对theta的 距离分辨率 的除数
  • min_theat 对于标准和多尺度Hough变换,检查线条的最小角度。必须介于0和最大θ之间。
  • max_theat 对于标准和多尺度Hough变换,检查线条的最大角度。必须介于min_theta和CV_PI之间。

返回值lines,是一个数组,shape为(n, 1, 2),n表示检测出的所有线段数目,每个线段用极坐标(ρ, θ)表示。

以此跨海大桥图(test2.jpg)为例,对其使用cv2.HoughLines()方法,并绘制直线:

Python OpenCV实现图形检测示例详解

import cv2
import numpy as np

img = cv2.imread("test2.jpg")
o = img.copy()
# 使用中值滤波进行降噪
o = cv2.medianBlur(o, 5)
# 从彩色图像变成单通道灰度图像
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)
# 绘制边缘图像
binary = cv2.Canny(o, 50, 150)

# 检测直线 不限步长,不限角度,至少50个点确定一条线
lines = cv2.HoughLines(binary, 1, np.pi / 180, 50)
# print(lines)
# print(lines.shape)

for line in lines:
    rho, theta = line[0]
    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), (0, 0, 255), 2)
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

识别效果如下,可以自行调节参数进行改良,并在这个过程中具体感受每个参数的作用。

当选择至少50个点确定一条线时,一共检测出168根直线:

Python OpenCV实现图形检测示例详解

当选择至少100个点确定一条线时,一共检测出35根直线:

Python OpenCV实现图形检测示例详解

当选择至少300个点确定一条直线时,符合要求的直线有3根:

Python OpenCV实现图形检测示例详解

当选择至少380个点确定一条直线时,这样的直线还剩一根:

Python OpenCV实现图形检测示例详解

相比检测直线,检测线段的cv2.HoughLinesP()相对要更常用些。

5.3 cv2.HoughLinesP() 检测线段

lines = cv2.HoughLinesP(image, rho, theta, threshold, minLineLength=None, maxLineGap=None)

检测线段

  • image 原图
  • rho 检测直线使用的半径步长,值为1时表示所有可能的半径步长
  • theta 搜索直线的角度
  • threshold 阈值,该值越小,检测出的直线越多。
  • minLineLength表示线段的最小长度,小于该长度的线段不会被记录在结果中。值越大线段越少。
  • maxLineGap 表示允许将同一行的点连接起来的最大距离。 值越大线段越多。

返回值lines,是一个数组,shape为(n, 1, 4),n表示检测出的所有线段数目,4指的是每个线段的两端端点的笛卡尔坐标(x, y) 坐标的四个点。

其中minLineLength(最小线段长度)和maxLineGap(最小线段距离)两个参数,都是越大,识别的线段越少。

import cv2
import numpy as np

img = cv2.imread("test2.jpg")
o = img.copy()
# 使用中值滤波进行降噪
o = cv2.medianBlur(o, 5)
# 从彩色图像变成单通道灰度图像
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)
# 绘制边缘图像
binary = cv2.Canny(o, 50, 150)

# 检测线段,不限步长,不限角度,至少100个点确定一条线。最大将距离为200的线段连城一条线。
lines = cv2.HoughLinesP(binary, 1, np.pi / 180, 50, minLineLength=100, maxLineGap=200)
print(lines.shape)
for line in lines:
    x1, y1, x2, y2 = line[0]
    cv2.line(img, (x1, y1), (x2, y2), (0, 0, 255), 2)
cv2.imshow("canny", binary)
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

二值化边缘图案效果:

Python OpenCV实现图形检测示例详解

描绘线段效果(minLineLength=100)至少100个点确定一条线段(上边代码),最大将距离为200的线段连接起来
共描绘了23条线:

Python OpenCV实现图形检测示例详解

描绘线段效果(minLineLength=500)至少500个点确定一条线段,最大将距离为200的线段连接起来
共描绘了6条线段:

Python OpenCV实现图形检测示例详解

描绘线段效果(minLineLength=720)至少720个点确定一条线段,最大将距离为200的线段连接起来
共描绘了一条线:

Python OpenCV实现图形检测示例详解

5.4 cv2.检测圆 - HoughCircles()

circles = HoughCircles(image, method, dp, minDist, circles=None, param1=None, param2=None, minRadius=None, maxRadius=None)

其中

  • image 原图像(降噪、灰度处理后的)
  • method 检测方法。
  • dp 累加器分辨率与原图分辨率之比的倒数。值为1时累加器与原图像有着相同的分辨率。通常选择1作为参数。(值为2时则累加器的分辨率是原图像的一半)
  • minDist 圆心之间的最小距离
  • param1 参数1,表示Canny边缘检测的最大阈值。是可选参数。
  • param2 参数2,表示检测结果投票数。即至少多少个点确定一个圆。值越大,识别的圆越少,约精准。是可选参数。
  • minRadius 圆环的最小半径(可选参数)
  • maxRadius 圆环的最大半径(可选参数)

返回值circles是一个数组,数组内是所有检测出的圆环,shape为(n,1,3)。其中3表示圆心的x坐标,圆心的y坐标和半径长度三个指标。

了解完语法,

接下来我们来检测下图(test3.jpg)中的客家土楼中的圆形。

Python OpenCV实现图形检测示例详解

import cv2
import numpy as np

img = cv2.imread("test3.jpg")
# 使用中值滤波进行降噪
o = cv2.medianBlur(img, 11) 
# 从彩色图像变成单通道灰度图像
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)  
# 展示灰度图像
cv2.imshow('gray', gray)
# 检测圆环,圆心最小间距为50,Canny最大阈值为40,投票数超过63。最小半径为10,最大半径为50
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 50, param1=40, param2=63, minRadius=10, maxRadius=100)
# 将数组元素四舍五入成整数
circles = np.uint(np.around(circles))
# 遍历圆环结果
for c in circles[0]:
    # 圆心横坐标、纵坐标和圆半径
    x, y, r = c
    # 绘制圆环
    cv2.circle(img, (x, y), r, (0, 0, 255), 3)
    # 绘制圆心
    cv2.circle(img, (x, y), 2, (0, 0, 255), 3)
cv2.imshow("img", img)
cv2.waitKey()
cv2.destroyAllWindows()

降过噪的灰度图像如下:

Python OpenCV实现图形检测示例详解

识别结果呈现如下,如图成功识别出了图中所有土楼的圆形:

Python OpenCV实现图形检测示例详解

以上就是Python OpenCV实现图形检测示例详解的详细内容,更多关于Python OpenCV图形检测的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
Python采用socket模拟TCP通讯的实现方法
Nov 19 Python
python实现从字典中删除元素的方法
May 04 Python
Python爬虫beautifulsoup4常用的解析方法总结
Feb 25 Python
Python  Django 母版和继承解析
Aug 09 Python
感知器基础原理及python实现过程详解
Sep 30 Python
快速查找Python安装路径方法
Feb 06 Python
在python中求分布函数相关的包实例
Apr 15 Python
浅析python 通⽤爬⾍和聚焦爬⾍
Sep 28 Python
Python实现对word文档添加密码去除密码的示例代码
Dec 29 Python
详解修改Anaconda中的Jupyter Notebook默认工作路径的三种方式
Jan 24 Python
Python3利用openpyxl读写Excel文件的方法实例
Feb 03 Python
有趣的二维码:使用MyQR和qrcode来制作二维码
May 10 Python
Python语法学习之进程的创建与常用方法详解
基于PyQt5制作一个群发邮件工具
Python&Matlab实现樱花的绘制
Python OpenCV形态学运算示例详解
4种方法python批量修改替换列表中元素
Apr 07 #Python
Python+OpenCV实现图片中的圆形检测
Python中文分词库jieba(结巴分词)详细使用介绍
You might like
PHP获取windows登录用户名的方法
2014/06/24 PHP
yii2中LinkPager增加总页数和总记录数的实例
2017/08/28 PHP
php判断文件上传图片格式的实例详解
2017/09/30 PHP
动态加载图片路径 保持JavaScript控件的相对独立性
2010/09/03 Javascript
jQuery find和children方法使用
2011/01/31 Javascript
基于jquery的图片的切换(以数字的形式)
2011/02/14 Javascript
json字符串之间的相互转换示例代码
2014/08/21 Javascript
一款由jquery实现的整屏切换特效
2014/09/15 Javascript
zepto与jquery的区别及zepto的不同使用8条小结
2016/07/28 Javascript
AngularJS中的包含详细介绍及实现示例
2016/07/28 Javascript
js中遍历Map对象的简单实例
2016/08/08 Javascript
BootStrap 可编辑表Table格
2016/11/24 Javascript
如何防止INPUT按回车自动提交表单FORM
2016/12/06 Javascript
微信小程序 标签传入数据
2017/05/08 Javascript
Angular中$state.go页面跳转并传递参数的方法
2017/05/09 Javascript
js如何编写简单的ajax方法库
2017/08/02 Javascript
JS+CSS实现滚动数字时钟效果
2017/12/25 Javascript
浅谈vue中关于checkbox数据绑定v-model指令的个人理解
2018/11/14 Javascript
jquery树形插件zTree高级使用详解
2019/08/16 jQuery
解决vue-cli 打包后自定义动画未执行的问题
2019/11/12 Javascript
nodeJS与MySQL实现分页数据以及倒序数据
2020/06/05 NodeJs
jquery实现图片放大镜效果
2020/12/23 jQuery
python获取豆瓣电影简介代码分享
2014/01/16 Python
Python实现的桶排序算法示例
2017/11/29 Python
详谈Numpy中数组重塑、合并与拆分方法
2018/04/17 Python
Python读取txt文件数据的方法(用于接口自动化参数化数据)
2018/06/27 Python
python3爬虫获取html内容及各属性值的方法
2018/12/17 Python
Pytorch 图像变换函数集合小结
2021/02/01 Python
Ellesse英国官网:意大利高级运动品牌
2019/07/23 全球购物
Groupon比利时官方网站:特卖和网上购物高达-70%
2019/08/09 全球购物
学生自我评价范文
2014/02/02 职场文书
国贸专业的职业规划书
2014/03/15 职场文书
文明旅游倡议书
2015/04/28 职场文书
亮剑精神观后感
2015/06/05 职场文书
学生会副主席竞选稿
2015/11/19 职场文书
JS setTimeout与setInterval的区别
2022/04/20 Javascript