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实现支持目录FTP上传下载文件的方法
Jun 03 Python
Django验证码的生成与使用示例
May 20 Python
在Python web中实现验证码图片代码分享
Nov 09 Python
python调用java的jar包方法
Dec 15 Python
PyQt5实现类似别踩白块游戏
Jan 24 Python
Python List cmp()知识点总结
Feb 18 Python
基于django传递数据到后端的例子
Aug 16 Python
python获取全国城市pm2.5、臭氧等空气质量过程解析
Oct 12 Python
python两种注释用法的示例
Oct 09 Python
python opencv旋转图片的使用方法
Jun 04 Python
Python中第三方库Faker的使用详解
Apr 02 Python
Python使用永中文档转换服务
May 06 Python
Python语法学习之进程的创建与常用方法详解
基于PyQt5制作一个群发邮件工具
Python&Matlab实现樱花的绘制
Python OpenCV形态学运算示例详解
4种方法python批量修改替换列表中元素
Apr 07 #Python
Python+OpenCV实现图片中的圆形检测
Python中文分词库jieba(结巴分词)详细使用介绍
You might like
(PHP实现)只使用++运算实现加法,减法,乘法,除法
2013/06/27 PHP
php实现设计模式中的单例模式详解
2014/10/11 PHP
jQuery获取json后使用zy_tmpl生成下拉菜单
2015/03/27 PHP
PHP结合jQuery实现找回密码
2015/07/22 PHP
PHP实现的mysql读写分离操作示例
2018/05/22 PHP
浅谈PHP array_search 和 in_array 函数效率问题
2019/10/15 PHP
Javascript 不能释放内存.
2006/09/07 Javascript
Javascript MD4
2006/12/20 Javascript
jQuery 学习6 操纵元素显示效果的函数
2010/02/07 Javascript
比较新旧两个数组值得增加和删除的JS代码
2013/10/30 Javascript
2014 HTML5/CSS3热门动画特效TOP10
2014/12/07 Javascript
TinyMCE提交AjaxForm获取不到数据的解决方法
2015/03/05 Javascript
基于jquery实现表格无刷新分页
2016/01/07 Javascript
一道常被人轻视的web前端常见面试题(JS)
2016/02/15 Javascript
javascript实现起伏的水波背景效果
2016/05/16 Javascript
完美解决js传递参数中加号和&号自动改变的方法
2016/10/11 Javascript
基于touch.js手势库+zepto.js插件开发图片查看器(滑动、缩放、双击缩放)
2016/11/17 Javascript
JS实现图片切换效果
2018/11/17 Javascript
微信小程序实现列表滚动头部吸顶的示例代码
2020/07/12 Javascript
深入理解 ES6中的 Reflect用法
2020/07/18 Javascript
关于Js中new操作符的作用详解
2021/02/21 Javascript
python中Genarator函数用法分析
2015/04/08 Python
Python命令行参数解析模块getopt使用实例
2015/04/13 Python
在Python3 numpy中mean和average的区别详解
2019/08/24 Python
keras模型可视化,层可视化及kernel可视化实例
2020/01/24 Python
python爬虫中采集中遇到的问题整理
2020/11/27 Python
解决PyCharm无法使用lxml库的问题(图解)
2020/12/22 Python
使用CSS3滤镜的filter:blur属性制作毛玻璃模糊效果的方法
2016/07/08 HTML / CSS
HTML5资源预加载(Link prefetch)详细介绍(给你的网页加速)
2014/05/07 HTML / CSS
柒牌官方商城:中国男装优秀品牌
2017/06/30 全球购物
JustFab加拿大:女鞋、靴子、手袋和服装在线
2018/05/18 全球购物
俄罗斯外国汽车和国产汽车配件网上商店:Движком
2020/04/19 全球购物
机关门卫岗位职责
2013/12/30 职场文书
2014年教学工作总结
2014/11/13 职场文书
宿舍卫生管理制度
2015/08/05 职场文书
如何才能写好调研报告?
2019/07/03 职场文书