当前位置:   article > 正文

图像轮廓

图像轮廓

·边缘检测的结果是不连续的,它检测到的边缘不是一个整体。而图像轮廓是指将边缘连接起来形成一个整体,用于后续计算。

一:查找并绘制轮廓

opencv中,函数cv2.findContours()用于查找图像轮廓,并根据参数返回特定方式的轮廓曲线。而cv2.drawContours()能够将查找的轮廓绘制到图像上。
1、查找图像轮廓

在opencv中,都是黑色背景中查找白色对象,因此,对象必须为白色,背景必须为黑色

image,contours,hierarchy=cv2.findContours(image, mode, method)

输入:
image:原始图像,8位单通道图像,所有非零值被处理为1,所有零值保留。即二值图
mode:轮廓检索模式,有以下四种:
	A、cv2.RETR_EXTERNAL:只检测外轮廓
	B、cv2.RETR_LIST:对检测到的轮廓不建立等级关系
	C、cv2.RETR_CCOMP:检索所有轮廓,并将它们组织成两级层次结构
	D、cv2.RETR_TREE:建立一个等级树结构的轮廓
method:轮廓的近似方式,有一下四种:
	A、cv2.CHAIN_APPROX_NONE:存储所有轮廓点,相邻两个像素点位置差不超过1
	B、cv2.CHAIN_APPROX_SIMPLE:压缩水平,垂直,对角线方向的元素,只保留该方向的终点坐标。
	C、cv2.CHAIN_APPROX_TC89_L1:使用teh-Chinl chain近似算法的一致风格
	D、cv2.CHAIN_APPROX_TC89_KCOS:使用teh-Chinl chain近似算法的一致风格   

返回值:
image:与输入image一致,即原二值图,从版本opencv 4.X开始,该返回值被取消。
contours:返回一组轮廓信息,每个轮廓信息都是由若干个点构成。
hierarchy:返回4个元素,用于说明当前轮廓的层次关系。其形式为:【next,previous,first_child,parent】,
若对应的关系为空时,则该参数对应的位置为0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

2、绘制图像轮廓
image=cv2.drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)

image:待绘制的图像,它会在图像image上直接绘制,绘制完成后,image不再是原图,它已经包含了轮廓
contours:需要绘制的轮廓,与cv2.findContours()输出的contours相同,都是List类型
contourIdx:需要绘制边缘的索引,若为负数(一般为-1),则表示绘制全部轮廓,否则绘制对应索引号的轮廓
color:颜色,RGB格式表示
thickness:可选,绘制时所用画笔的粗细,若为“-1”,则表示要绘制实心轮廓
lineType:可选,线型号
hierarchy:对应cv2.findContours()输出的层次信息,一般默认
maxLevel:控制所绘制轮廓层次的深度,一般默认
offset:偏移参数,该参数时轮廓偏移到不同的位置展现出来,一般默认
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

#################轮廓绘制实例##################

import cv2
import numpy as np

img = cv2.resize(cv2.imread("F:/my_project/opencv/img/10.jpg",0), (400, 400))  # 图10.jpg本身就是二值图,在此没另作二值化处理
image, contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cv2.imshow("img", img)
# contour_image = cv2.drawContours(img, contours, -1, (125, 125, 125), 5)

#逐层绘制
n=len(contours)
contoursImg=[]
for i in range(n):
    temp=np.zeros(img.shape,np.uint8)
    contoursImg.append(temp)
    contoursImg[i]=cv2.drawContours(contoursImg[i],contours,i,(125,125,125),5)
    cv2.imshow("contours["+str(i)+"]", contoursImg[i])

#全部绘制
contour_image = cv2.drawContours(img, contours, -1, (125, 125, 125), 5)
cv2.imshow("contour_image", contour_image)
cv2.waitKey()
cv2.destroyAllWindows()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

在这里插入图片描述

二:矩特征

比较两个轮廓的最简单的方法就是比较它们的轮廓矩,轮廓据代表了一个轮廓、一幅图像、一组点集的全局特征。矩信息包含了对象的几何特征,包括大小、位置、角度、形状等。常用于模式识别和图像识别。

1、矩的计算

在opencv中,函数retval=cv2.moments()可以获取图像的轮廓矩:
retval=cv2.moments(array, binaryImage=None)
retval:特征矩,包含空间矩、中心矩、归一化中心矩。(具体含义自己查,其中空间矩中的零阶矩反应的是轮廓面积)
array:点集(轮廓),或者灰度图像或者二值图像
binaryImage:仅在array为图像时有效,当他为True时,array内所有值被处理为1。
  • 1
  • 2
  • 3
  • 4
  • 5

2、计算轮廓的面积:cv2.contourArea()函数

retval=cv2.contourArea(contour, oriented=None)
retval:轮廓面积值
contour:轮廓
 oriented:布尔值,当它为True时,返回值有正负号,表示轮廓时顺时针还是逆时针。默认为False(绝对值)
  • 1
  • 2
  • 3
  • 4

#############计算面积并显示轮廓图#############

import cv2
import numpy as np
img=cv2.resize(cv2.imread(r"F:\my_project\opencv\img\10.jpg",0),(400,400))

dst,retval=cv2.threshold(img,127,255,cv2.THRESH_BINARY)
image,contours,hierarchy=cv2.findContours(retval,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)#传入的图必须为8位单通道图像
n=len(contours)
contoursImg=[]
for i in range(n):
    print("contours["+str(i)+"]面积=",cv2.contourArea(contours[i]))
    temp=np.zeros(img.shape,np.uint8)
    contoursImg.append(temp)
    contoursImg[i]=cv2.drawContours(contoursImg[i],contours,i,(255,0,0),3)
    cv2.imshow("contours["+str(i)+"]",contoursImg[i])
cv2.imshow("image",retval)
cv2.waitKey()
cv2.destroyAllWindows()

=>contours[0]面积= 24707.5
=>contours[1]面积= 17026.5
=>contours[2]面积= 57899.0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在这里插入图片描述
3、计算轮廓的长度:arclength函数

retval=cv2.arcLength(curve, closed)
retval:轮廓的周长
curve:轮廓
 closed:布尔型值,表示轮廓是否封闭,为True时,表示封闭
  • 1
  • 2
  • 3
  • 4

与上面面积计算类似,在此不展示效果图

三:Hu矩

1、Hu矩函数

Hu矩是归一化中心矩的线性组合,Hu矩在图像旋转、缩放、平移等操作后,仍能保持矩的不变性。经常用它来识别图像的特征。

通过函数retval=cv2.HuMoments(m)可以得到Hu矩,参数m是由函数cv2.moments()计算得到的矩特征值。   
  • 1

在此做了解即可,若需了解详情,请自行查阅相关资料

2、形状匹配
通过上述Hu矩来判断两个对象的一致性比较抽象,为了更加直观方便比较Hu矩的值,可以使用函数cv2.matchShapes()

retval=cv2.matchShapes(contour1, contour2, method, parameter)
contour1:第一个轮廓或者灰度图像 
contour2:第二个轮廓或者灰度图像
method:比较两个对象Hu矩的方法,可选0,1,2三种模式(每种模式具体含义自己查)
parameter:应用于method的特定参数,该参数为扩展参数,暂不支持该参数,因此将其设置为0。
  • 1
  • 2
  • 3
  • 4
  • 5

########计算不同图像的匹配度##############

import cv2
import numpy as np

#3.jpg与4.jpg在此均为二值图,无需再做阈值处理
img1=cv2.resize(cv2.imread("F:/my_project/opencv/img/3.jpg",0),(400,400))
img2=cv2.resize(cv2.imread("F:/my_project/opencv/img/4.jpg",0),(400,400))
M=cv2.getRotationMatrix2D((200,200),45,0.6)
img3=cv2.warpAffine(img1,M,(400,400))
cv2.imshow("img1",img1)
cv2.imshow("img2",img2)
cv2.imshow("img3",img3)

image_1,contours_1,hierarchy_1=cv2.findContours(img1,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
image_2,contours_2,hierarchy_2=cv2.findContours(img2,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
image_3,contours_3,hierarchy_3=cv2.findContours(img3,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

cnt1=contours_1[0]
cnt2=contours_2[0]
cnt3=contours_3[0]

ret_1=cv2.matchShapes(cnt1,cnt1,2,0)
ret_2=cv2.matchShapes(cnt1,cnt2,2,0)
ret_3=cv2.matchShapes(cnt1,cnt3,2,0)
print("相同图像:",ret_1)
print("不同图像:",ret_2)
print("旋转变换后的图像:",ret_3)

cv2.waitKey()
cv2.destroyAllWindows()

=》相同图像: 0.0
=》不同图像: 9.479639295761899e-12
=》旋转变换后的图像: 0.0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

在这里插入图片描述
由上图可知,旋转,缩放,平移不会改变Hu值,同时图像越相似,cv2.matchShapes值越小。

四:轮廓拟合

1、矩形包围框

函数cv2.boundingRect()能够绘制轮廓的矩形边框

retval=cv2.boundingRect(array)
retval:返回矩形边框的左上角顶点坐标和矩形边界的宽高。
array:灰度图像或者轮廓图
  • 1
  • 2
  • 3

2、最小包围矩形框

retval=cv2.minAreaRect(points)
retval:返回矩形特征信息(最小外接矩形的中心(x,y),(宽度,高度),旋转角度)
points为轮廓
  • 1
  • 2
  • 3

注:返回值的结构不符合cv2.drawContours()的参数结构要求,因此,必须将其转换为符合要求的结构,函数cv2.boxPoints()能够将上述返回值retval转换为符合要求的结构。

points=cv2.boxPoints(box
返回值points是能够用于函数cv2.drawContours()参数的轮廓点
参数box是函数cv2.minAreaRect()返回值的类型的值

import cv2
import numpy as np

img=cv2.resize(cv2.imread("img/9.jpg"),(400,400))
cv2.imshow("img",img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
image,contours,hierarchy=cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

rect=cv2.minAreaRect(contours[-1])
print("rect",rect)
points=cv2.boxPoints(rect)
print("points",points)
points=np.int0(points)#取整
cv2.drawContours(img,[points],0,255,2)
cv2.imshow("result",img)
cv2.waitKey()
cv2.destroyAllWindows()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

=》rect ((197.0, 268.0), (222.0, 262.0), 0.0)
=》points [[ 86. 399.]
[ 86. 137.]
[308. 137.]
[308. 399.]]

在这里插入图片描述
若对象是倾斜的,则最小包围矩形框也是随之倾斜的,这就是与1中的矩形包围框的差别

3、最小包围圆形

函数cv2.minEnclosingCircle()可以通过构造一个对象的面积最小包围圆形

center,radius=cv2.minEnclosingCircle(points)
返回值center为最小包围圆形的中心
返回值radius是最小包围圆形的半径
points为轮廓
  • 1
  • 2
  • 3
  • 4

##################如下所示############

import cv2
import numpy as np

img=cv2.resize(cv2.imread("img/9.jpg"),(400,400))
cv2.imshow("img",img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
image,contours,hierarchy=cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

(x,y),radius=cv2.minEnclosingCircle(contours[-1])
center=(int(x),int(y))
radius=int(radius)
cv2.circle(img,center,radius,255,2)
cv2.imshow("result",img)
cv2.waitKey()
cv2.destroyAllWindows()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

在这里插入图片描述

4、最优拟合椭圆

retval=cv2.fitEllipse(points)
返回值retval是RotatedRect类型的值,这是因为该函数返回的是拟合椭圆的外接矩形,包含外接矩形的质
心、宽高、旋转角度等信息,它们正好对应椭圆的中心、轴长度、旋转角度等
points为轮廓
  • 1
  • 2
  • 3
  • 4

################如下所示################

import cv2
import numpy as np

img=cv2.resize(cv2.imread("img/9.jpg"),(400,400))
cv2.imshow("img",img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
image,contours,hierarchy=cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

ellipse=cv2.fitEllipse(contours[-1])
print("ellipse",ellipse)
cv2.ellipse(img,ellipse,255,2)
cv2.imshow("ellipse",img)
cv2.waitKey()
cv2.destroyAllWindows()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

在这里插入图片描述

5、最优拟合直线

line=cv2.fitLine(points, distType, param, reps, aeps, line=None)
返回值line是最优拟合直线参数
points为轮廓
distType:距离类型,拟合直线时,要使输入点到拟合直线的距离之和最小。具体类型可查阅相关资料
param:距离参数,与所选的距离类型有关,当其被设置为0时,函数会自动选择最优值
reps:用于表示拟合直线所需要的径向精度,通常被设为0.01
aeps:用于表示拟合直线所需要的j角度精度,通常被设为0.01
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

6、最小外包三角形

retval,triangle=cv2.minEnclosingTriangle(points, triangle=None)
retval:最小外包三角形的面积
triangle:最小外包三角形的三个顶点集
points:轮廓
  • 1
  • 2
  • 3
  • 4

7、逼近多边形

approxCurve=cv2.approxPolyDP(curve, epsilon, closed, approxCurve=None)
返回值approxCurve为逼近多边形的点集
curve:轮廓
epsilon:精度,原始轮廓边界点与逼近多边形边界点之间的最大距离
closed:布尔值,该值为True时,逼近多边形是封闭的,否则,逼近多边形是不封闭的
  • 1
  • 2
  • 3
  • 4
  • 5

####################如下所示##################

import cv2
import numpy as np

img=cv2.resize(cv2.imread("img/9.jpg"),(400,400))
cv2.imshow("img",img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
image,contours,hierarchy=cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

#精度,最大距离为轮廓长度的0.02倍
epsilon=0.02*cv2.arcLength(contours[-1],True)
approx=cv2.approxPolyDP(contours[-1],epsilon,True)
cv2.drawContours(img,[approx],0,255,2)
cv2.imshow("approx",img)

cv2.waitKey()
cv2.destroyAllWindows()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述

五:凸包

逼近多边形是轮廓的高度相似,但有时候,我们希望用多边形的凸包来简化它,凸包与逼近多边形相似,但它是物体最外层的“凸“多边形,指的是完全包含原有轮廓,并仅由轮廓上的点所构成的多边形,凸包的每一处都是凸的,即在凸包内连接任意两点的直线都在凸包的内部。

1、获取凸包

hull=cv2.convexHull(points, hull=None, clockwise=None, returnPoints=None)
返回值hull为凸包角点
points:轮廓
clockwise:布尔值,该值为True时。凸包角点按顺时针排列,否则逆时针排列
returnPoints:布尔值。默认为True,函数返回凸包角点的x/y轴坐标,否则,返回轮廓中凸包角点的索引。 
  • 1
  • 2
  • 3
  • 4
  • 5

################如下所示###################

import cv2
import numpy as np

img=cv2.resize(cv2.imread("img/3.jpg"),(400,400))
cv2.imshow("img",img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary=cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
image,contours,hierarchy=cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

#得到凸包角点
hull=cv2.convexHull(contours[-1])
#绘制凸包
cv2.polylines(img,[hull],True,255,2)
cv2.imshow("result",img)

cv2.waitKey()
cv2.destroyAllWindows()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

在这里插入图片描述

2、凸缺陷

凸包与轮廓之间的部分被称之为凸缺陷。

convexityDefects=cv2.convexityDefects(contour, convexhull, convexityDefects=None)
返回值convexityDefects为凸缺陷点集,为一个数组,每一行包含的值为[起点、终点、轮廓上距离凸包最远的点、最远点到凸包的近似距离],其中前三个值为轮廓点的索引,需要到轮廓点中去找它们。
contour:轮廓
convexhull:凸包(需要将获取凸包的函数cv2.convexHull中的 returnPoints设置为False,以便获取索引值)· 
  • 1
  • 2
  • 3
  • 4

3、几何学测试

(1)测试轮廓是否为凸形的

	retval=cv2.isContourConvex(contour)
    retval:布尔值,该值为True时,表示轮廓为凸形,否则不是凸形
    contour:参与判断的轮廓
  • 1
  • 2
  • 3

(2)点到轮廓的距离

retval=retval=cv2.pointPolygonTest(contour, pt, measureDist)
retval:点到轮廓的距离,与参数measureDist有关
contour:轮廓
pt:待判断的点
measureDist:布尔值,表示距离的判定方式,为True时,表示计算点到轮廓的距离,该值为负时,表示点在轮廓外,为正时,
	点在内部,为0时,点在轮廓上。当其为False时,不计算距离,只返回“-1,0,1”中的一个,外返-1,内返1,轮廓上返0
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

六:利用形状场景算法比较轮廓

从opencv3开始,用专有模块shape中的形状场景算法能相对矩比较更有效的比较形状。

1、计算形状场景距离
opencv提供了使用“距离”作为形状比较的度量标准,这是因为形状之间的差异值和距离有相似之处,比如两者都只能是零或者正值,比如当两个形状一模一样时距离值和差值都是等于0.

retval=cv2.createShapeContextDistanceExtractor(nAngularBins=None, nRadialBins=None, innerRadius=None, outerRadius=None, iterations=None, comparer=None, transformer=None)
  • 1

上述结果可以通过函数cv2.ShapeDistanceExtractor.computeDistance()计算两个不同形状之间的距离

retval=cv2.ShapeDistanceExtractor.computeDistance(contour1, contour2)

该部分不做过多介绍,若需要,请查阅相关资料。
  • 1
  • 2
  • 3

2、计算Hausdorff距离

Hausdorff距离计算的方式
(1)针对图像A内的每一个点,寻找其距离图像B的最短距离,将这个最短距离作为Hausdorff直接距离D1
(2)针对图像B内的每一个点,寻找其距离图像A的最短距离,将这个最短距离作为Hausdorff直接距离D2
(3)将上述D1、D2中的较大者作为Hausdorff距离

retval=cv2.createHausdorffDistanceExtractor(distanceFlag=None, rankProp=None)
distanceFlag:距离标记,可选参数
rankProp:比例值,范围在0,1之间,为可选参数
  • 1
  • 2
  • 3

七:轮廓的特征值

轮廓自身的一些属性特征及轮廓所包围对象的特征对于描述图像具有重要意义

1、宽高比:如矩形轮廓的宽高比
2、Extent:轮廓面积与矩形边界(矩形包围框、矩形轮廓)面积之比
3、Solidity:轮廓面积与凸包面积之比
4、等效直径:与轮廓面积相等的圆形的直径,即:d=((4*s)/pi)^(1/2),s为轮廓面积,pi为圆周率
5、方向:函数cv2.fitEllipse()构造最优拟合椭圆时,会返回椭圆中心点、长短轴长度,以及旋转角度(方向)

(x,y),(a,b),angle=cv2.fitEllipse(cnt)
(x,y):椭圆中心点
(a,b):椭圆水平方向轴和垂直方向轴长度
(angle):旋转角度
  • 1
  • 2
  • 3
  • 4

#################以下为实例展示###############

import cv2
import numpy as np

img=cv2.resize(cv2.imread("img/8.png"),(400,400))
cv2.imshow("img",img)
img1=img.copy()
img2=img.copy()
img3=img.copy()
img4=img.copy()
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary=cv2.threshold(gray,127,155,cv2.THRESH_BINARY)

image,contours,hierarchy=cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

(x,y,w,h)=cv2.boundingRect(contours[-1])
cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,255),3)
#矩形边界
cv2.imshow("result",img)
#宽高比
aspectRatio=float(w/h)
print("aspectRatio",aspectRatio)
#外轮廓
cv2.drawContours(img1,contours[-1],-1,255,2)
cv2.imshow("img1",img1)
#extend
rectArea=w*h
cntArea=cv2.contourArea(contours[-1])
extend=float(cntArea/rectArea)
print("extend",extend)

#Solidity
hull=cv2.convexHull(contours[-1])
hullarea=cv2.contourArea(hull)
cv2.polylines(img2,[hull],True,255,2)
solidity=float(cntArea/hullarea)
print("solidity",solidity)
#凸包
cv2.imshow("img2",img2)

#等效直径
equiDiameter=np.sqrt(4*cntArea/np.pi)
print("equiDiameter",equiDiameter)
cv2.circle(img3,(100,100),int(equiDiameter/2),255,3)
cv2.imshow("img3",img3)

#方向
ellipse=cv2.fitEllipse(contours[-1])
print("ellipse",ellipse)
cv2.ellipse(img4,ellipse,255,2)
#最优拟合椭圆
cv2.imshow("img4",img4)
cv2.waitKey()
cv2.destroyAllWindows()

aspectRatio: 0.5303030303030303
extend: 0.6812229437229437
solidity: 0.8851778934045844
equiDiameter: 89.52321662192149
ellipse: ((189.48306274414062, 163.74679565429688), (66.91047668457031, 124.29612731933594), 179.7550506591797)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

在这里插入图片描述

6、掩模和像素点

(1)使用numpy函数获取轮廓像素点
numpy.nonzero()函数能够找出数组内非零元素的位置,但其返回的行、列是分开的,使用函数numpy.transpose()能够将其处理为(x,y)形式的坐标。

import cv2
import numpy as np

img=cv2.resize(cv2.imread("img/8.png",0),(400,400))
cv2.imshow("img",img)
#为了方便绘制,在此设置method=cv2.RETR_EXTERNAL,只返回外轮廓
image,contours,hierarchy=cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnt=contours[0]
#绘制空心轮廓
mask1=np.zeros(img.shape,np.uint8)
#cv2.drawContours的返回值即是传入的image,在此为mask1,但一般不写
cv2.drawContours(mask1,[cnt],0,255,2)
#pixelpointsl为轮廓边界值的索引,可以打印查看
pixelpointsl=np.transpose(np.nonzero(mask1))
cv2.imshow("mask1",mask1)

#绘制实心轮廓
mask2=np.zeros(img.shape,np.uint8)
cv2.drawContours(mask2,[cnt],0,255,-1)#thickness为绘制轮廓的线宽,若为-1,表示绘制实线轮廓
pixelpoints2=np.transpose(np.nonzero(mask2))
cv2.imshow("mask2",mask2)
cv2.waitKey()
cv2.destroyAllWindows()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

在这里插入图片描述
(2)使用opencv函数获取轮廓点

idx=cv2.findNonZero(src)
idx:非零元素的索引位置,在返回的索引值中,每个元素对应的是(列号,行号)的格式
src:要查找非零元素的图像

import cv2
import numpy as np

array=np.zeros((3,3),np.uint8)
for idx in range(4):
    i=np.random.randint(0,3)
    j = np.random.randint(0, 3)
    array[i,j]=1
print("原数组:",array)
arr=cv2.findNonZero(array)
#先列再行索引
print("非零元素索引",arr)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

在这里插入图片描述
7、最大值和最小值及它们的位置

min_val,max_val,min_loc,max_loc=cv2.minMaxLoc(imgray,mask=mask)
min_val,max_val,min_loc,max_loc分别为最小值、最大值、最小值位置、最大值位置
imgray:单通道图像(若为彩色图像,需要在各个通道上进行分别处理)
mask:掩模,通过使用掩模,可以得到掩模指定区域的最值信息
  • 1
  • 2
  • 3
  • 4

8、平均颜色及平均灰度

mean_val=cv2.mean(img,mask=mask)
  • 1

########################计算各个通道的灰度

import cv2
import numpy as np

img=cv2.resize(cv2.imread("img/5.jpg"),(400,400))
cv2.imshow("img",img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary=cv2.threshold(gray,195,255,cv2.THRESH_BINARY)

#为了方便绘制,在此设置method=cv2.RETR_EXTERNAL,只返回外轮廓
image,contours,hierarchy=cv2.findContours(binary,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnt=contours[-1]
mask=np.zeros(gray.shape,np.uint8)
#cv2.drawContours的返回值即是传入的image,在此为mask1,但一般不写
cv2.drawContours(mask,[cnt],0,255,-1)
meanVal=cv2.mean(img,mask)
print("meanval=\n",meanVal)
cv2.imshow("mask",mask)
cv2.waitKey()
cv2.destroyAllWindows()

=>meanval=(223.81084419366837, 229.30970377076446, 236.50342126871172, 0.0)#RGBA4个通道的均值
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

在这里插入图片描述

9、极点

获取某个对象内的极值点,如最左端、最右端、最上端、最下端:

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])
  • 1
  • 2
  • 3
  • 4

#########绘制极点####################

import cv2
import numpy as np

img=cv2.resize(cv2.imread("img/8.png",0),(400,400))

cv2.imshow("img",img)
#为了方便绘制,在此设置method=cv2.RETR_EXTERNAL,只返回外轮廓
image,contours,hierarchy=cv2.findContours(img,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
cnt=contours[-1]
mask=np.zeros(img.shape,np.uint8)
#cv2.drawContours的返回值即是传入的image,在此为mask1,但一般不写
cv2.drawContours(mask,[cnt],0,255,-1)
cv2.imshow("mask",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])
print(leftmost,rightmost,topmost,bottommost)

font=cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(img,"A",leftmost,font,1,255,2)
cv2.putText(img,"B",rightmost,font,1,255,2)
cv2.putText(img,"C",topmost,font,1,255,2)
cv2.putText(img,"D",bottommost,font,1,255,2)

cv2.imshow("result",img)
cv2.waitKey()
cv2.destroyAllWindows()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

=》(152, 161) (223, 173) (193, 99) (179, 230)

在这里插入图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/79087
推荐阅读
相关标签
  

闽ICP备14008679号