OpenCV-Python实现轮廓拟合


Posted in Python onJune 08, 2021

前言

什么是轮廓?

轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同 的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。

  • 为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理 或者 Canny 边界检测。
  • 查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图 像的话,你应该将原始图像存储到其他变量中。
  • 在 OpenCV 中,查找轮廓就像在黑色背景中超白色物体。你应该记住, 要找的物体应该是白色而背景应该是黑色。

在计算轮廓时,可能并不需要实际的轮廓,而仅需要一个接近于轮廓的近似多边形。比如矩形其实都是差不多的轮廓,都是长宽不相等且平行的四边形,那么只要提供一个近似的轮廓,我们就可以区分形状。

在OpenCV中,它给我们提供了cv2.boundingRect()函数来绘制轮廓的矩形边界,其完整定义如下:

def boundingRect(array):

array:前面已经介绍过,array是一个灰度图像,或者轮廓。

该函数返回3个值时,是矩形边界的左上角顶点的坐标值以及矩形边界的宽与高。返回4个值时,是矩形左上角顶点的x坐标,y坐标,以及宽高。

绘制椭圆的矩形边界

现在,我们还是使用前面的一张椭圆图形,如下图所示:

OpenCV-Python实现轮廓拟合

得到图形之后,我们使用上面的函数,计算该图像轮廓的4值,代码如下:

import cv2

img = cv2.imread("26_1.jpg")

# 转换为灰度图像
gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)

ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
x, y, w, h = cv2.boundingRect(contours[0])
print(x, y, w, h)

运行之后,控制台输出如下内容:

OpenCV-Python实现轮廓拟合

这里我们得到了椭圆的矩形左上角坐标为(53,120),其宽高分别为272与84。

既然我们已经得到了其矩形边界的坐标以及宽高,那么我们可以开始绘制其矩形边界。前面提取轮廓绘制用的是cv2.drawContours()函数,这里同样也是。

代码如下:

import cv2
import numpy as np

img = cv2.imread("26_1.jpg")
cv2.imshow("img1",img)
# 转换为灰度图像
gray= cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
x, y, w, h = cv2.boundingRect(contours[0])
rect=np.array([[[x,y],[x+w,y],[x+w,y+h],[x,y+h]]])#1
cv2.drawContours(img,[rect],-1,(255,255,255),2)#1

cv2.imshow("img2",img)

cv2.waitKey()
cv2.destroyAllWindows()

运行之后,其椭圆的矩形边界就被我们标记出来了,效果如下:

OpenCV-Python实现轮廓拟合

当然,这里我们还可以使用另一个函数cv2.rectangle()来绘制矩形边界,值需要更换上面代码中注释1的两个代码,具体如下所示:

cv2.rectangle(img, (x, y), (x + w, y + h), (255, 255,255),2)

最小包围矩形框

在OpenCV中,它还提供了cv2.minAreaRect()来绘制最小包围矩形框,其完整定义如下:

def minAreaRect(points):

其中points参数是轮廓,返回值为矩形特征信息,包括矩形的中心(x,y),宽高,以及旋转角度。

特别注意,minAreaRect函数的返回值并不能直接代入drawContours()函数中。因此,我们必须将其转换为符合要求的结构才能接着操作。通过cv2.boxPoint()函数就可以转换为符合drawContours()的结构参数。

还是上面那张图,不过我们用旋转后的椭圆原图,代码如下:

import cv2
import numpy as np

img = cv2.imread("26_4.jpg")

cv2.imshow("img1",img)
# 转换为灰度图像
gray= cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
rect= cv2.minAreaRect(contours[0])
print(rect)
points=cv2.boxPoints(rect)
print(points)
points=np.int0(points)
print(points)
cv2.drawContours(img,[points],0,(255,255,255),2)

cv2.imshow("img2",img)

cv2.waitKey()
cv2.destroyAllWindows()

运行之后,图像效果以及控制台的输出信息如下:

OpenCV-Python实现轮廓拟合

OpenCV-Python实现轮廓拟合

这里我们可以清楚的看到minAreaRect()函数返回值的转换过程。先通过boxPoints()函数转换为drawContours()函数能接受的参数格式,然后通过取整转换为具体的像素坐标值。

最小包围圆形框

既然有最小包围矩形框,那么一定就有最小包围圆形框。在OpenCV中,它给我们提供cv2.minEnclosingCircle()函数来绘制最小包围圆形框。

函数的完整定义如下:

def minEnclosingCircle(points):

这里的参数与上面的points参数一致,但是其返回值并不相同,毕竟绘制圆形肯定与绘制矩形的参数肯定不一样。

它有两个返回值,一个是圆形的中心坐标(x,y),一个是圆形的半径r。下面,我们直接来绘制上面椭圆的最小包围圆形框。具体代码如下所示:

import cv2
import numpy as np

img = cv2.imread("26_4.jpg")

cv2.imshow("img1", img)
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
(x, y), r = cv2.minEnclosingCircle(contours[0])
center = (int(x), int(y))
r = int(r)
cv2.circle(img, center, r, (255, 255, 255), 2)

cv2.imshow("img2", img)

cv2.waitKey()
cv2.destroyAllWindows()

运行之后,效果如下所示:

OpenCV-Python实现轮廓拟合

最优拟合椭圆

在OpenCV中,它给我们提供了cv2.fitEllipse()函数绘制最优拟合椭圆。其完整的定义如下:

def fitEllipse(points):

其中points参数与前文一致,而它的返回值是RotatedRect类型,这是因为该函数返回的是拟合椭圆的外接矩形,包括矩形的质心,宽高,旋转角度等信息,这些信息正好与椭圆的中心点,轴长度,旋转角度一致。

下面,我们来使用该函数绘制最优拟合椭圆,这里我们选取如上图所示的一张矩形图。具体代码如下:

import cv2

img = cv2.imread("27.jpg")

cv2.imshow("img1", img)
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
ellipse = cv2.fitEllipse(contours[0])

cv2.ellipse(img, ellipse, (0, 0, 255), 3)

cv2.imshow("img2", img)

cv2.waitKey()
cv2.destroyAllWindows()

运行之后,效果如下所示:

OpenCV-Python实现轮廓拟合

最优拟合直线

在OpenCV中,它还提供了cv2.fitLine()函数绘制最优拟合直线,其完整定义如下:

def fitEllipse(points):

points:与前文一样,是轮廓

distType:距离类型。拟合直线时,要使输入点到拟合直线的距离之和最小。详细参数定义参考开发文档,这里不在赘述。

param:距离参数,与所选距离类型有关。当该参数为0时,自动选择最优值。

reps:用于表示拟合直线所需要的径向精度,通常该值被设定为0.01

aeps:用于表示拟合直线所需要的角度精度,通常该值被设定为0.01

对于二维直线,返回值line为4维,前两维代表拟合出的直线的方向,后两位代表直线上的一点。

下面,我们来直接使用代码绘制最优拟合直线。

import cv2

img = cv2.imread("27.jpg")

cv2.imshow("img1", img)
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
ellipse = cv2.fitEllipse(contours[0])

cv2.ellipse(img, ellipse, (0, 0, 255), 3)

cv2.imshow("img2", img)

cv2.waitKey()
cv2.destroyAllWindows()

运行之后,效果如下所示:

OpenCV-Python实现轮廓拟合

对于绘制直线来说,我们需要获取绘制直线的起点以及终点,这里lefty为起点,righty为终点。

最小外包三角形

在OpenCV,它还提供了cv2.minEnclosingTriangle()函数来绘制最小外包三角形。其完整定义如下:

def minEnclosingTriangle(points, triangle=None):

其中points与前文类似,其返回值triangle为外包三角形的三个顶点集。

下面,我们直接构建最小外包三角形,具体代码如下:

import cv2

img = cv2.imread("27.jpg")

cv2.imshow("img1", img)
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

area, trg1 = cv2.minEnclosingTriangle(contours[0])
print(area)
print(trg1)
for i in range(0, 3):
    cv2.line(img, tuple(trg1[i][0]), tuple(trg1[(i + 1) % 3][0]), (0, 255, 0), 2)

cv2.imshow("img2", img)

cv2.waitKey()
cv2.destroyAllWindows()

运行之后,效果如下:

OpenCV-Python实现轮廓拟合

需要注意的是,在cv2中没有直接绘制三角形的函数,所以我们通过绘制三条直线,绘制三角形,minEnclosingTriangle()函数第一个返回值为三角形面积,第二返回值是三点坐标。

逼近多边形

在OpenCV中,它还提供了cv2.approxPolyDP()函数构建指定边数的逼近多边形。其完整定义如下:

def approxPolyDP(curve, epsilon, closed, approxCurve=None):

curve:轮廓

epsilon:精度,原始轮廓的边界点与逼近多边形边界之间的最大距离

closed:布尔类型。为True时,表示逼近多边形是封闭的。为False时,biao表示毕竟多边形是不封闭的。

approxCurve为该函数的返回值,是逼近多边形的点集。。

下面,我们来实现各类逼近多边形的绘制,代码如下:

import cv2

img = cv2.imread("24.jpg")

list=[0.1,0.09,0.055,0.05,0.02]

cv2.imshow("img", img)
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

for i, val in enumerate(list):
    epsilon = val * cv2.arcLength(contours[0], True)
    approx = cv2.approxPolyDP(contours[0], epsilon, True)
    cv2.drawContours(img, [approx], 0, (0, 255, 0), 2)

    cv2.imshow("img"+str(i), img)

cv2.waitKey()
cv2.destroyAllWindows()

运行之后,效果如下:

OpenCV-Python实现轮廓拟合

cv2.approxPolyDP()函数采用的是Douglas-Peucker算法,该算法的原理是首先从轮廓中找到距离最远的两个点,并将两个点相连。接下来,在轮廓上找到一个离当前直线最远的点,并将该点与原有直线连成一个封闭的多边形,此时得到一个三角形。以此类推四边形,五边形,六边形等。当前多边形的距离都小于函数cv2.approxPolyDP()的参数epsilon的值时,就停止迭代。

到此这篇关于OpenCV-Python实现轮廓拟合的文章就介绍到这了,更多相关OpenCV 轮廓拟合内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python中列表与元组的乘法操作示例
Feb 10 Python
对Python3中的input函数详解
Apr 22 Python
Python实现的读写json文件功能示例
Jun 05 Python
Python实现对字典分别按键(key)和值(value)进行排序的方法分析
Dec 19 Python
Jupyter notebook在mac:linux上的配置和远程访问的方法
Jan 14 Python
Python numpy中矩阵的基本用法汇总
Feb 12 Python
python中如何使用分步式进程计算详解
Mar 22 Python
使用Python函数进行模块化的实现
Nov 15 Python
Python 静态方法和类方法实例分析
Nov 21 Python
django rest framework serializers序列化实例
May 13 Python
如何把外网python虚拟环境迁移到内网
May 18 Python
利用python进行数据加载
Jun 20 Python
python图像处理基本操作总结(PIL库、Matplotlib及Numpy)
Django drf请求模块源码解析
Python中OpenCV实现查找轮廓的实例
python字符串的多行输出的实例详解
Jun 08 #Python
Python机器学习之基于Pytorch实现猫狗分类
Python中json.load()和json.loads()有哪些区别
python 爬取哔哩哔哩up主信息和投稿视频
Jun 07 #Python
You might like
php fsockopen伪造post与get方法的详解
2013/06/14 PHP
destoon实现公司新闻详细页添加评论功能的方法
2014/07/15 PHP
PHP设计模式之装饰器模式实例详解
2018/02/07 PHP
PHP面向对象五大原则之开放-封闭原则(OCP)详解
2018/04/04 PHP
laravel 框架配置404等异常页面
2019/01/07 PHP
用js实现预览待上传的本地图片
2007/03/15 Javascript
运用Windows XP附带的Msicuu.exe、Msizap.exe来彻底卸载顽固程序
2007/04/21 Javascript
JavaScript Sort 表格排序
2009/10/31 Javascript
javascript 验证日期的函数
2010/03/18 Javascript
javascript对talbe进行动态添加、删除、验证实现代码
2012/03/29 Javascript
JavaScript使用setTimeout实现延迟弹出警告框的方法
2015/04/07 Javascript
JS获取鼠标选中的文字
2016/08/10 Javascript
基于JavaScript实现跳转提示页面
2016/09/24 Javascript
javascript 使用正则test( )第一次是 true,第二次是false
2017/02/22 Javascript
vue.js的提示组件
2017/03/02 Javascript
详解Vue2.0之去掉组件click事件的native修饰
2017/04/20 Javascript
vue项目打包后打开页面空白解决办法
2018/06/29 Javascript
vue中Axios的封装与API接口的管理详解
2018/08/09 Javascript
vue实现浏览器全屏展示功能
2019/11/27 Javascript
ES6函数和数组用法实例分析
2020/05/23 Javascript
[40:50]2014 DOTA2国际邀请赛中国区预选赛 5 23 CIS VS LGD第四场
2014/05/24 DOTA
Python开发之快速搭建自动回复微信公众号功能
2016/04/22 Python
Python遍历文件夹和读写文件的实现方法
2017/05/10 Python
python获取程序执行文件路径的方法(推荐)
2018/04/26 Python
Python运维自动化之nginx配置文件对比操作示例
2018/08/29 Python
django中上传图片分页三级联动效果的实现代码
2019/08/30 Python
Python图像处理库PIL的ImageDraw模块介绍详解
2020/02/26 Python
Python 按比例获取样本数据或执行任务的实现代码
2020/12/03 Python
丝芙兰巴西官方商城:SEPHORA巴西
2016/10/31 全球购物
个人求职简历的自我评价范文
2013/10/09 职场文书
精彩的推荐信范文
2013/11/26 职场文书
实习心得体会
2014/01/02 职场文书
开业庆典策划方案
2014/02/18 职场文书
对照四风自我剖析材料
2014/10/07 职场文书
Pytest中conftest.py的用法
2021/06/27 Python
Elasticsearch 聚合查询和排序
2022/04/19 Python