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 相关文章推荐
在Windows8上的搭建Python和Django环境
Jul 03 Python
Web服务器框架 Tornado简介
Jul 16 Python
Python3实现并发检验代理池地址的方法
Sep 18 Python
轻松实现TensorFlow微信跳一跳的AI
Jan 05 Python
python3.4.3下逐行读入txt文本并去重的方法
Apr 29 Python
Python UnboundLocalError和NameError错误根源案例解析
Oct 31 Python
python程序 线程队列queue使用方法解析
Sep 23 Python
Python FTP文件定时自动下载实现过程解析
Nov 12 Python
Python startswith()和endswith() 方法原理解析
Apr 28 Python
用python对excel查重
Dec 07 Python
Django2.1.7 查询数据返回json格式的实现
Dec 29 Python
PYTHON 使用 Pandas 删除某列指定值所在的行
Apr 28 Python
Python语法学习之进程的创建与常用方法详解
基于PyQt5制作一个群发邮件工具
Python&Matlab实现樱花的绘制
Python OpenCV形态学运算示例详解
4种方法python批量修改替换列表中元素
Apr 07 #Python
Python+OpenCV实现图片中的圆形检测
Python中文分词库jieba(结巴分词)详细使用介绍
You might like
建立文件交换功能的脚本(三)
2006/10/09 PHP
PHP缩略图等比例无损压缩,可填充空白区域补充色
2011/06/10 PHP
php smarty truncate UTF8乱码问题解决办法
2014/06/13 PHP
php把时间戳转换成多少时间之前函数的实例
2016/11/16 PHP
jquery 弹出登录窗口实现代码
2009/12/24 Javascript
Javascript学习笔记 delete运算符
2011/09/13 Javascript
六款帮助你实现惊艳视差滚动效果的jQuery插件
2012/09/14 Javascript
JavaScript prototype属性深入介绍
2012/11/27 Javascript
中文路径导致unitpngfix.js不正常的解决方法
2013/06/26 Javascript
基于JQuery实现仿网易邮箱全屏动感滚动插件fullPage
2015/09/20 Javascript
AngularJS应用开发思维之依赖注入3
2016/08/19 Javascript
JavaScript实现横线提示输入验证码随输入验证码输入消失的方法
2016/09/24 Javascript
javascript将url解析为json格式的两种方法
2017/08/18 Javascript
基于Vue2的独立构建与运行时构建的差别(详解)
2017/12/06 Javascript
vue中element 上传功能的实现思路
2018/07/06 Javascript
[04:55]完美世界副总裁蔡玮:DOTA2的自由、公平与信任
2013/12/18 DOTA
Python中列表(list)操作方法汇总
2014/08/18 Python
Python3 处理JSON的实例详解
2017/10/29 Python
机器学习的框架偏向于Python的13个原因
2017/12/07 Python
Python 3.3实现计算两个日期间隔秒数/天数的方法示例
2019/01/07 Python
python实现趣味图片字符化
2019/04/30 Python
Python 3 判断2个字典相同
2019/08/06 Python
From CSV to SQLite3 by python 导入csv到sqlite实例
2020/02/14 Python
python中re模块知识点总结
2021/01/17 Python
CSS3 制作旋转的大风车(充满童年回忆)
2013/01/30 HTML / CSS
HTML 5 标签、属性、事件及浏览器兼容性速查表 附打包下载
2012/10/20 HTML / CSS
html5中为audio标签增加停止按钮动作实现方法
2013/01/04 HTML / CSS
前端实现背景虚化但内容清晰且自适应 的实例代码
2019/08/01 HTML / CSS
Html5导航栏吸顶方案原理与对比实现
2020/06/10 HTML / CSS
大学生预备党员自我评价分享
2013/11/16 职场文书
2014道德模范事迹材料
2014/02/16 职场文书
企业法人代表任命书
2014/06/06 职场文书
个人工作表现自我评价
2015/03/06 职场文书
2015年度校学生会工作总结报告
2015/05/23 职场文书
Linux安装Nginx步骤详解
2021/03/31 Servers
人民币符号
2022/02/17 杂记