二值图像处理轮廓
- 矩
图像的矩可以帮助我们计算图像的质心,面积等。
import cv2
import numpy as np
img = cv2.imread('image.png',0)
ret,thresh = cv2.threshold(img,127,255,0)
im,contours,hierarchy = cv2.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv2.moments(cnt)#计算矩
print (M)
cx = int(M['m10']/M['m00'])#计算重心
cy = int(M['m01']/M['m00'])
print (cx)
print (cy)
{‘m00’: 358.0, ‘m10’: 71958.0, ‘m01’: 37590.0, ‘m20’: 14463677.0, ‘m11’: 7555590.0, ‘m02’: 4902869.666666666, ‘m30’: 2907246915.0, ‘m21’: 1518686085.0, ‘m12’: 985476803.0, ‘m03’: 715544445.0, ‘mu20’: 119.0, ‘mu11’: 0.0, ‘mu02’: 955919.666666666, ‘mu30’: 0.0, ‘mu21’: 0.0, ‘mu12’: 1.1920928955078125e-07, ‘mu03’: 2.384185791015625e-07, ‘nu20’: 0.0009284978621141662, ‘nu11’: 0.0, ‘nu02’: 7.458566108007444, ‘nu30’: 0.0, ‘nu21’: 0.0, ‘nu12’: 4.915894264526992e-14, ‘nu03’: 9.831788529053984e-14}
201
105
- 轮廓面积
轮廓的面积可以使用函数 cv2.contourArea() 计算得到,也可以使用矩(0 阶矩), M[‘m00’]。
area = cv2.contourArea(cnt)#函数计算面积
print(area)
print(M['m00'])#0阶矩
358.0
358.0
- 轮廓周长
也被称为弧长。可以使用函数 cv2.arcLength() 计算得到。这个函数的第二参数可以用来指定对象的形状是闭合的(True),还是打开的(一条曲线)。
perimeter = cv2.arcLength(cnt,True)#计算轮廓周长
361.65685415267944
- 轮廓近似
import cv2
import numpy as np
# 1.先找到轮廓
img = cv2.imread('juxing.png',0)
_, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
image, contours, hierarchy = cv2.findContours(thresh, 3, 2)
cnt = contours[0]
# 2.进行多边形逼近,得到多边形的角点
epsilon = 0.01*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt, epsilon, True)
# 3.画出多边形
image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)
cv2.polylines(image, [approx], True, (0, 255, 0), 2)
# 4.显示图像
cv2.imshow('image',image)#轮廓图
cv2.waitKey(0)
cv2.destroyAllWindows()
其中cv2.approxPolyDP()的参数2(epsilon)是一个距离值,表示多边形的轮廓接近实际轮廓的程度,值越小,越精确;参数3表示是否闭合。
- 凸包
凸包与轮廓近似相似,但不同,虽然有些情况下它们给出的结果是一样的。函数 cv2.convexHull() 可以用来检测一个曲线是否具有凸性缺陷,并能纠正缺陷。一般来说,凸性曲线总是凸出来的,至少是平的。如果有地方凹进去了就被叫做凸性缺陷。例如下图中的手。红色曲线显示了手的凸包,凸性缺陷被双箭头标出来了。
import cv2
import numpy as np
img = cv2.imread('gun.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(img_gray, 127, 255,0)
#图片轮廓
_,contours,hierarchy = cv2.findContours(thresh,2,1)
# 寻找物体的凸包并绘制凸包的轮廓
for cnt in contours:
hull = cv2.convexHull(cnt)
length = len(hull)
# 如果凸包点集中的点个数大于5
if length > 5:
# 绘制图像凸包的轮廓
for i in range(length):
cv2.line(img, tuple(hull[i][0]), tuple(hull[(i+1)%length][0]), (0,0,255), 2)
cv2.imshow('gun', img)
cv2.waitKey()
其中函数cv2.convexHull()有个可选参数returnPoints,默认是True,代表返回角点的x/y坐标;如果为False的话,表示返回轮廓中是凸包角点的索引,比如说:
print(hull[0]) # [[362 184]](坐标)
hull2 = cv2.convexHull(cnt, returnPoints=False)
print(hull2[0]) # [510](cnt中的索引)
print(cnt[510]) # [[362 184]]
当使用cv2.convexityDefects()计算凸包缺陷时,returnPoints需为False
https://www.jianshu.com/p/d53bdfb1051f
函数 cv2.isContourConvex() 可以可以用来检测一个曲线是不是凸的。它只能返回 True 或 False。
k = cv2.isContourConvex(cnt)
- 边界矩形
直边界矩形
一个直矩形(就是没有旋转的矩形)。它不会考虑对象是否旋转。所以边界矩形的面积不是最小的。可以使用函数 cv2.boundingRect() 查找得到。
(x, y)为矩形左上角的坐标,(w, h)是矩形的宽和高。
x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
旋转的边界矩形
这个边界矩形是面积最小的,因为它考虑了对象的旋转。用到的函数为cv2.minAreaRect()。返回的是一个 Box2D 结构,其中包含矩形左上角角点的坐标(x, y),矩形的宽和高(w, h),以及旋转角度。但是要绘制这个矩形需要矩形的 4 个角点,可以通过函数 cv2.boxPoints() 获得。
- 最小外接圆
函数 cv2.minEnclosingCircle() 可以帮我们找到一个对象的外切圆。
它是所有能够包括对象的圆中面积最小的一个。 - 椭圆拟合
使用的函数为 cv2.ellipse(),返回值其实就是旋转边界矩形的内切圆。 - 直线拟合
代码:
import cv2
import numpy as np
im = cv2.imread('image.png')
imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imgray,127,255,cv2.THRESH_BINARY)
_,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_NONE)
cnt = contours[0]
for c in contours:
#直角边界矩形
x,y,w,h = cv2.boundingRect(c)#计算出边框
cv2.rectangle(im,(x,y),(x+w,y+h),(0,255,0),2)#绘制矩形
#最小矩形区域
rect = cv2.minAreaRect(cnt)#计算最小矩形区域
box = cv2.boxPoints(rect)
box = np.int0(box)#浮点型转为整形
cv2.drawContours(im, [box], 0, (0,0,255), 3)
#画圆
(x,y),radius = cv2.minEnclosingCircle(c)
center = (int(x),int(y))
radius = int(radius)
im = cv2.circle(im,center,radius,(255,0,0),2)
#椭圆
ellipse = cv2.fitEllipse(cnt)
im = cv2.ellipse(im,ellipse,(0,255,0),2)
#直线
rows,cols = im.shape[:2]
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
lefty = int((-x*vy/vx) + y)
righty = int(((cols-x)*vy/vx)+y)
im = cv2.line(im,(cols-1,righty),(0,lefty),(0,255,0),2)
cv2.imshow('a',im)
cv2.waitKey(0)
cv2.destroyAllWindows()
不知道是因为开始图片不够大还是什么原因,最小矩形总是整个图形最外界的框。。。
- 点赞
- 收藏
- 关注作者
评论(0)