Python学习日志(二)OpenCV图像处理三


前言

本文主要记录OpenCV学习中的图像的轮廓部分相关基础知识:
*了解什么是轮廓
*学习找轮廓,绘制轮廓等
*找到轮廓的不同特征,如面积,周长,质心,边界框等
*学习提取一些常用的对象属性,如Solidity,Equivalent Diameter,Mask image,Mean Intensity等。
*凸性缺陷以及如何找到它们。
*寻找从点到多边形的最短距离
*匹配不同的形状
*了解了轮廓的层次结构,即Contours中的父子关系。
*你会看到这些函数:cv.findContours(),cv.drawContours()


一、什么是轮廓?

轮廓可以简单地解释为连接所有具有相同的颜色或强度的连续点(沿着边界)的曲线。轮廓是形状分析和物体检测和识别的很有用的工具。

  • 为了更好的准确性,使用二进制图像,因此,在找到轮廓之前,应用阈值或canny边缘检测。
  • 值得注意的是,从OpenCV 3.2开始,findContours()不再修改源图像,而是将修改后的图像作为三个返回参数中的第一个返回。
  • 在OpenCV中,找到轮廓就像从黑色背景中找到白色物体。所以请记住,要找到的对象应该是白色,背景应该是黑色。

1.找到并绘制轮廓

代码如下(示例):

import numpy as np
import cv2 as cv

im = cv.imread('test.jpg')
imgray = cv.cvtColor(im, cv.COLOR_BGR2GRAY)
# 阈值处理成灰度图像
ret, thresh = cv.threshold(imgray, 127, 255, 0)
# 三个参数,第一个是源图像,第二个是轮廓检索模式,第三个是轮廓的近似方法。它输出修改后的图像,显示出轮廓和层次结构。
im2, contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
# 绘制轮廓
# 输入四个轮廓点
cnt = contours[4]
# 第三个参数为-1时绘制所有轮廓,其余参数是颜色,厚度等等
cv.drawContours(img, [cnt], 0, (0,255,0), 3)
# drawContours的第一个参数是源图像,第二个参数是应该作为Python列表传递的轮廓

2.轮廓特征


  1. 图像矩可帮助你计算某些特征,如对象的质心,对象的区域等。具体定义可以查看图像矩的具体定义

函数cv.moments()给出了计算的所有矩值的字典。见下文:

import numpy as np
import cv2 as cv

img = cv.imread('star.jpg',0)
ret,thresh = cv.threshold(img,127,255,0)
# hierarchy是层次结构,在后面介绍
im2,contours,hierarchy = cv.findContours(thresh, 1, 2)

cnt = contours[0]
M = cv.moments(cnt)
print( M )

从这一刻起,你可以提取有用的数据,如面积,质心等。质心由关系给出。这可以按如下方式完成:

cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
  1. 其他基本特征
# 轮廓区域
area = cv.contourArea(cnt)

# 轮廓周长
perimeter = cv.arcLength(cnt,True)

# 轮廓近似,epsilon是从轮廓到近似轮廓的最大距离,即准确度参数
epsilon = 0.1*cv.arcLength(cnt,True)
approx = cv.approxPolyDP(cnt,epsilon,True)

# 凸包
hull = cv.convexHull(points[, hull[, clockwise[, returnPoints]]
 - points:是我们传入的轮廓。
 - hull:是输出,通常我们忽略它。
 - clocwise:方向标志。如果为True,则输出凸包顺时针方向。否则,它逆时针方向。
 - returnPoints:默认为True。然后它返回凸包点的坐标。如果为False,则返回与凸包点对应的轮廓点的索引。
# 简单用法只需输入轮廓即可检查凸性

# 检查凸性
hull = cv.convexHull(cnt)

# 边界矩形(直角边)
x,y,w,h = cv.boundingRect(cnt)
cv.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)

# 旋转矩形
rect = cv.minAreaRect(cnt)
box = cv.boxPoints(rect)
box = np.int0(box)
cv.drawContours(img,[box],0,(0,0,255),2)

# 最小外接圈,找到一个恰好完全覆盖物体的圆圈
(x,y),radius = cv.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv.circle(img,center,radius,(0,255,0),2

# 椭圆拟合
ellipse = cv.fitEllipse(cnt)
cv.ellipse(img,ellipse,(0,255,0),2)

# 拟合一条线
rows,cols = img.shape[:2]
[vx,vy,x,y] = cv.fitLine(cnt, cv.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
cv.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)

3.轮廓属性

# Solidity(密实比)轮廓区域与其凸包区域的比率。
area = cv.contourArea(cnt)
hull = cv.convexHull(cnt)
hull_area = cv.contourArea(hull)
solidity = float(area)/hull_area

# Mask & Pixel Points(掩模和像素点)
mask = np.zeros(imgray.shape,np.uint8)
cv.drawContours(mask,[cnt],0,255,-1)
# Numpy函数以**(行,列)格式给出坐标
pixelpoints=np.transpose(np.nonzero(mask))
# OpenCV以(行,列)**格式给出坐标
pixelpoints = cv.findNonZero(mask)

# 极点,对象的最顶部,最底部,最右侧和最左侧
leftmost = tuple(cnt[cnt[:,:,0].argmin()][0])
rightmost = tuple(cnt[cnt[:,:,0].argmax()][0])
topmost = tuple(cnt[cnt[:,:,1].argmin()][0])
bottommost = tuple(cnt[cnt[:,:,1].argmax()][0])

4.其他功能

  1. 凸缺陷
    物体与该凸包的任何偏差都可以被认为是凸缺陷。
    OpenCV附带了一个现成的函数来查找它,cv.convexityDefects()。基本函数调用如下所示:
# 必须在找到凸包时传递returnPoints = False,以便找到凸缺陷。
hull = cv.convexHull(cnt,returnPoints = False)
defects = cv.convexityDefects(cnt,hull)
  1. 点多边形测试
    此功能可查找图像中的点与轮廓之间的最短距离。当点在轮廓外时返回负值,当点在内部时返回正值,如果点在轮廓上则返回零。
# 第三个参数是measureDist。如果为True,则查找距离。如果为False,则查找该点是在内部还是外部或在轮廓上(它分别返回+1-10)。
dist = cv.pointPolygonTest(cnt,(50,50),True)
  1. 匹配形状
    OpenCV附带了一个函数cv.matchShapes(),它使我们能够比较两个形状或两个轮廓,并返回一个显示相似性的度量。结果越小,匹配就越好
ret = cv.matchShapes(cnt1,cnt2,1,0.0)

5.层次结构

当我们使用cv.findContours()函数在图像中找到轮廓时,我们已经传递了一个参数Contour Retrieval Mode,通常传递cv.RETR_LIST或cv.RETR_TREE可达到较好的效果。

什么是层次结构?

在某些情况下,某些形状在其他形状内,在这种情况下,我们将外部一个称为父项,将内部
项称为子项,这种关系的表示称为层次结构。

OpenCV中的层次结构表示

OpenCV中表示为四个值的数组:[Next,Previous,First_Child,Parent]

  • “Next表示同一层级的下一个轮廓。”
  • “Previous表示同一层级的先前轮廓。”
  • “First_Child表示其第一个子轮廓。”
  • “Parent表示其父轮廓的索引。”
    注意:如果没有子项或父项,则该字段将被视为-1

轮廓检索模式

  • RETR_LIST
    检索所有轮廓,但不创建任何父子关系

  • RETR_EXTERNAL
    使用此标志,则仅返回极端外部标志。所有child轮廓都被忽略

  • RETR_CCOMP
    此标志检索所有轮廓并将它们排列为***2级***层次结构。即对象的外部轮廓(即其边界)放置在层次结构-1中。对象内部的孔的轮廓(如果有的话)放在层次结构-2中。
    如果其中有任何对象,则其轮廓仅再次放置在层次结构-1中。它在层次结构-2中的孔等等。
    在这里插入图片描述

  • RETR_TREE
    可以说是所谓的Mr.Perfect(bushi)-_-。它检索所有轮廓并创建完整的族层次结构列表。它甚至告诉,谁是爷爷,父,子,孙子,甚至超越… 😃。
    在这里插入图片描述

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

野生稚晖君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值