二值图像处理轮廓

举报
Gere 发表于 2022/08/07 19:24:34 2022/08/07
【摘要】 矩图像的矩可以帮助我们计算图像的质心,面积等。import cv2import numpy as npimg = 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 =...

  1. 图像的矩可以帮助我们计算图像的质心,面积等。
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

  1. 轮廓面积
    轮廓的面积可以使用函数 cv2.contourArea() 计算得到,也可以使用矩(0 阶矩), M[‘m00’]。
area = cv2.contourArea(cnt)#函数计算面积
print(area)
print(M['m00'])#0阶矩

358.0
358.0

  1. 轮廓周长
    也被称为弧长。可以使用函数 cv2.arcLength() 计算得到。这个函数的第二参数可以用来指定对象的形状是闭合的(True),还是打开的(一条曲线)。
perimeter = cv2.arcLength(cnt,True)#计算轮廓周长

361.65685415267944

  1. 轮廓近似
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表示是否闭合。

在这里插入图片描述

  1. 凸包
    凸包与轮廓近似相似,但不同,虽然有些情况下它们给出的结果是一样的。函数 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)
  1. 边界矩形

直边界矩形
一个直矩形(就是没有旋转的矩形)。它不会考虑对象是否旋转。所以边界矩形的面积不是最小的。可以使用函数 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() 获得。

  1. 最小外接圆
    函数 cv2.minEnclosingCircle() 可以帮我们找到一个对象的外切圆。
    它是所有能够包括对象的圆中面积最小的一个。
  2. 椭圆拟合
    使用的函数为 cv2.ellipse(),返回值其实就是旋转边界矩形的内切圆。
  3. 直线拟合

代码:

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()

在这里插入图片描述


不知道是因为开始图片不够大还是什么原因,最小矩形总是整个图形最外界的框。。。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。