下载欧博真人客户端:Python 图像处置 OpenCV (15):图像轮廓

admin/2020-07-28/ 分类:科技/阅读:

前文传送门:

「Python 图像处置 OpenCV (1):入门」

「Python 图像处置 OpenCV (2):像素处置与 Numpy 操作以及 Matplotlib 显示图像」

「Python 图像处置 OpenCV (3):图像属性、图像感兴趣 ROI 区域及通道处置」

「Python 图像处置 OpenCV (4):图像算数运算以及修改颜色空间」

「Python 图像处置 OpenCV (5):图像的几何变换」

「Python 图像处置 OpenCV (6):图像的阈值处置」

「Python 图像处置 OpenCV (7):图像平滑(滤波)处置」

「Python 图像处置 OpenCV (8):图像侵蚀与图像膨胀」

「Python 图像处置 OpenCV (9):图像处置形态学开运算、闭运算以及梯度运算」

「Python 图像处置 OpenCV (10):图像处置形态学之顶帽运算与黑帽运算」

「Python 图像处置 OpenCV (11):Canny 算子边缘检测手艺」

「Python 图像处置 OpenCV (12): Roberts 算子、 Prewitt 算子、 Sobel 算子和 Laplacian 算子边缘检测手艺」

「Python 图像处置 OpenCV (13): Scharr 算子和 LOG 算子边缘检测手艺」

「Python 图像处置 OpenCV (14):图像金字塔」

弁言

实在蛮不好意思的,适才翻了翻自己的博客,上次写 OpenCV 的文章已经靠近半个月以前了,我用 3 秒钟的时间回想了下最近两星期时间都花在哪了。

每次思索这种问题总会下意识甩锅给事情,最近事情忙的一批,emmmmmmmmmmmm。。。。。。。。。

这么骗自己是纰谬的!

实际上是美剧真香,最近把「还击」从第一季到第六季看了一遍,还不错,喜欢看动作类的同砚可以实验下。

本篇文章是关于图像处置轮廓方面的,下面最先正文,希望能帮到列位。

Q:什么是轮廓?

A:轮廓是一系列相连的点组成的曲线,代表了物体的基本形状,相对于边缘,轮廓是延续的,边缘并不所有延续。

寻找轮廓

寻找轮廓 OpenCV 为我们提供了一个现成的函数 findContours()

在 OpenCV 中,轮廓提取函数 findContours() 实现的是 1985 年由一名叫做 Satoshi Suzuki 的人揭晓的一篇论文中的算法,如下:

Satoshi Suzuki and others. Topological structural analysis of digitized binary images by border following. Computer Vision, Graphics, and Image Processing, 30(1):32–46, 1985.

对原理感兴趣的同砚可以去搜搜看,不是很难明白。

先看一个示例代码:

import cv2 as cv img = cv.imread("black.png") gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 降噪 ret, thresh = cv.threshold(gray_img, 127, 255, 0) # 寻找轮廓 contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_NONE) print(len(contours[0])) 

这段代码先用 threshold() 对图像举行降噪处置,它的原型函数如下:

retval, dst = cv.threshold(src, thresh, maxval, type[, dst] ) 
  • dst:效果图像。
  • src:原图像。
  • thresh:当前阈值。
  • maxVal:最大阈值,一样平常为255。
  • type:阈值类型,可选值如下:
enum ThresholdTypes { THRESH_BINARY = 0, # 大于阈值的部门被置为 255 ,小于部门被置为 0 THRESH_BINARY_INV = 1, # 大于阈值部门被置为 0 ,小于部门被置为 255 THRESH_TRUNC = 2, # 大于阈值部门被置为 threshold ,小于部门保持原样 THRESH_TOZERO = 3, # 小于阈值部门被置为 0 ,大于部门保持稳定 THRESH_TOZERO_INV = 4, # 大于阈值部门被置为 0 ,小于部门保持稳定 THRESH_OTSU = 8, # 自动处置,图像自适应二值化,常用区间 [0,255] }; 

查找轮廓使用的函数为 findContours() ,它的原型函数如下:

cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])   
  • image:源图像。
  • mode:示意轮廓检索模式。
cv2.RETR_EXTERNAL 示意只检测外轮廓。 cv2.RETR_LIST 检测的轮廓不确立品级关系。 cv2.RETR_CCOMP 确立两个品级的轮廓,上面的一层为外界限,内里的一层为内孔的界限信息。若是内孔内另有一个连通物体,这个物体的界限也在顶层。 cv2.RETR_TREE 确立一个品级树结构的轮廓。 
  • method:示意轮廓近似方式。
cv2.CHAIN_APPROX_NONE 存储所有的轮廓点。 cv2.CHAIN_APPROX_SIMPLE 压缩水平偏向,垂直偏向,对角线偏向的元素,只保留该偏向的终点坐标,例如一个矩形轮廓只需4个点来保留轮廓信息。 

这里可以使用 print(len(contours[0])) 函数将包罗的点的数目打印出来,好比在上面的示例中,使用参数 cv2.CHAIN_APPROX_NONE 轮廓点有 1382 个,而使用参数 cv2.CHAIN_APPROX_SIMPLE 则轮廓点只有 4 个。

绘制轮廓

绘制轮廓使用到的 OpenCV 为我们提供的 drawContours() 这个函数,下面是它的三个简朴的例子:

# To draw all the contours in an image: cv2.drawContours(img, contours, -1, (0,255,0), 3) # To draw an individual contour, say 4th contour: cv2.drawContours(img, contours, 3, (0,255,0), 3) # But most of the time, below method will be useful: cnt = contours[4] cv2.drawContours(img, [cnt], 0, (0,255,0), 3) 

drawContours() 函数中有五个参数:

  • 第一个参数是源图像。
  • 第二个参数是应该包罗轮廓的列表。
  • 第三个参数是列表索引,用来选摘要绘制的轮廓,为-1时示意绘制所有轮廓。
  • 第四个参数是轮廓颜色。
  • 第五个参数是轮廓线的宽度,为 -1 时示意填充。

我们接着前面的示例把使用 findContours() 找出来的轮廓绘制出来:

import cv2 as cv img = cv.imread("black.png") gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY) cv.imshow("img", img) # 降噪 ret, thresh = cv.threshold(gray_img, 127, 255, 0) # 寻找轮廓 contours, hierarchy = cv.findContours(gray_img, cv.RETR_TREE, cv.CHAIN_APPROX_NONE) print(len(contours[0])) # 绘制绿色轮廓 cv.drawContours(img, contours, -1, (0,255,0), 3) cv.imshow("draw", img) cv.waitKey(0) cv.destroyAllWindows() 

特征矩

特征矩可以辅助我们盘算一些图像的特征,例如物体的质心,物体的面积等,使用的函数为 moments()

moments() 函数会将盘算获得的矩以字典形式返回。

import cv2 as cv img = cv.imread("number.png") gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 降噪 ret, thresh = cv.threshold(gray_img, 127, 255, 0) # 寻找轮廓 contours, hierarchy = cv.findContours(gray_img, cv.RETR_TREE, cv.CHAIN_APPROX_NONE) cnt = contours[0] # 获取图像矩 M = cv.moments(cnt) print(M) # 质心 cx = int(M['m10'] / M['m00']) cy = int(M['m01'] / M['m00']) print(f'质心为:[{cx}, {cy}]') 

这时,我们取得了这个图像的矩,矩 M 中包罗了许多轮廓的特征信息,除了示例中展示的质心的盘算,另有如 M['m00'] 示意轮廓面积。

轮廓面积

area = cv.contourArea(cnt) print(f'轮廓面积为:{area}') 

这里取到的轮廓面积和上面 M['m00'] 保持一致。

轮廓周长

perimeter = cv.arcLength(cnt, True) print(f'轮廓周长为:{perimeter}') 

参数 True 示意轮廓是否封锁,我们这里的轮廓是封锁的,以是这里写 True

轮廓外接矩形

轮廓外接矩形分为正矩形和最小矩形。使用 cv2.boundingRect(cnt) 来获取轮廓的外接正矩形,它不思量物体的旋转,以是该矩形的面积一样平常不会最小;使用 cv.minAreaRect(cnt) 可以获取轮廓的外接最小矩形。

两者的区别如上图,绿线代表的是外接正矩形,红线代表的是外接最小矩形,代码如下:

import cv2 as cv import numpy as np img = cv.imread("number.png") gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 降噪 ret, thresh = cv.threshold(gray_img, 127, 255, 0) # 寻找轮廓 contours, hierarchy = cv.findContours(gray_img, cv.RETR_TREE, cv.CHAIN_APPROX_NONE) cnt = contours[0] # 外接正矩形 x, y, w, h = cv.boundingRect(cnt) cv.rectangle(img, (x, y), (x w, y h), (0, 255, 0), 2) # 外接最小矩形 min_rect = cv.minAreaRect(cnt) print(min_rect) box = cv.boxPoints(min_rect) box = np.int0(box) cv.drawContours(img, [box], 0, (0, 0, 255), 2) cv.imshow("draw", img) cv.waitKey(0) cv.destroyAllWindows() 

boundingRect() 函数的返回值包罗四个值,矩形框左上角的坐标 (x, y) 、宽度 w 和高度 h 。

minAreaRect() 函数的返回值中还包罗旋转信息,返回值信息为包罗中心点坐标 (x,y) ,宽高 (w, h) 和旋转角度。

轮廓近似

凭据我们指定的精度,它可以将轮廓形状近似为极点数目较少的其他形状。它是由 Douglas-Peucker 算法实现的。

OpenCV 提供的函数是 approxPolyDP(cnt, epsilon, True) ,第二个参数 epsilon 用于轮廓近似的精度,示意原始轮廓与其近似轮廓的最大距离,值越小,近似轮廓越拟合原轮廓。第三个参数指定近似轮廓是否是闭合的。详细用法如下:

import cv2 as cv img = cv.imread("number.png") gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 降噪 ret, thresh = cv.threshold(gray_img, 127, 255, 0) # 寻找轮廓 contours, hierarchy = cv.findContours(gray_img, cv.RETR_TREE, cv.CHAIN_APPROX_NONE) cnt = contours[0] # 盘算 epsilon ,根据周长百分比举行盘算,划分取周长 1% 和 10% epsilon_1 = 0.1 * cv.arcLength(cnt, True) epsilon_2 = 0.01 * cv.arcLength(cnt, True) # 举行多边形迫近 approx_1 = cv.approxPolyDP(cnt, epsilon_1, True) approx_2 = cv.approxPolyDP(cnt, epsilon_2, True) # 画出多边形 image_1 = cv.cvtColor(gray_img, cv.COLOR_GRAY2BGR) image_2 = cv.cvtColor(gray_img, cv.COLOR_GRAY2BGR) cv.polylines(image_1, [approx_1], True, (0, 0, 255), 2) cv.polylines(image_2, [approx_2], True, (0, 0, 255), 2) cv.imshow("image_1", image_1) cv.imshow("image_2", image_2) cv.waitKey(0) cv.destroyAllWindows() 

第一张图是 epsilon 为原始轮廓周长的 10% 时的近似轮廓,第二张图中绿线就是 epsilon 为原始轮廓周长的 1% 时的近似轮廓。

轮廓凸包

凸包外观看起来与轮廓迫近相似,只不过它是物体最外层的「凸」多边形。

如下图,红色的部门为手掌的凸包,双箭头部门示意凸缺陷(Convexity Defects),凸缺陷常用来举行手势识别等。

import cv2 as cv img = cv.imread("number.png") gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 降噪 ret, thresh = cv.threshold(gray_img, 127, 255, 0) # 寻找轮廓 contours, hierarchy = cv.findContours(gray_img, cv.RETR_TREE, cv.CHAIN_APPROX_NONE) cnt = contours[0] # 绘制轮廓 image = cv.cvtColor(gray_img, cv.COLOR_GRAY2BGR) cv.drawContours(image, contours, -1, (0, 0 , 255), 2) # 寻找凸包,获得凸包的角点 hull = cv.convexHull(cnt) # 绘制凸包 cv.polylines(image, [hull], True, (0, 255, 0), 2) cv.imshow("image", image) cv.waitKey(0) cv.destroyAllWindows() 

另有一个函数,是可以用来判断图形是否凸形的:

print(cv.isContourConvex(hull)) # True 

它的返回值是 True 或者 False 。

最小闭合圈

接下来,使用函数 cv.minEnclosingCircle() 查找工具的圆周。它是一个以最小面积完全笼罩物体的圆。

import cv2 as cv img = cv.imread("number.png") gray_img = cv.cvtColor(img, cv.COLOR_BGR2GRAY) # 降噪 ret, thresh = cv.threshold(gray_img, 127, 255, 0) # 寻找轮廓 contours, hierarchy = cv.findContours(gray_img, cv.RETR_TREE, cv.CHAIN_APPROX_NONE) cnt = contours[0] # 绘制最小外接圆 (x, y), radius = cv.minEnclosingCircle(cnt) center = (int(x), int(y)) radius = int(radius) cv.circle(img, center, radius, (0, 255, 0), 2) cv.imshow("img", img) cv.waitKey(0) cv.destroyAllWindows() 

下一个是把一个椭圆拟合到一个物体上。它返回内接椭圆的旋转矩形。

ellipse = cv.fitEllipse(cnt) cv.ellipse(img, ellipse, (0, 255, 0), 2) 

参考

https://zhuanlan.zhihu.com/p/61328775

https://zhuanlan.zhihu.com/p/77783347

,

欧博APP

欢迎进入欧博APP(Allbet Game):www.aLLbetgame.us,欧博官网是欧博集团的官方网站。欧博官网开放Allbet注册、Allbe代理、Allbet电脑客户端、Allbet手机版下载等业务。

TAG:
阅读:
广告 330*360
广告 330*360
Sunbet_进入申博sunbet官网
微信二维码扫一扫
关注微信公众号
新闻自媒体 Copyright © 2002-2019 Sunbet 版权所有
二维码
意见反馈 二维码