OpenCV-Python官方教程-13-图像轮廓(轮廓绘制,轮廓特征(面积,周长,重心,边界框))、轮廓性质

  • 1.什么是轮廓?
    轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。
    为了更加准确,要使用二值化图像。在寻找轮廓之前,要进行阈值化处理或者 Canny 边界检测。
  • 函数 cv2.fifindContours() 有三个参数,第一个是输入图像,第二个是轮廓检索模式,第三个是轮廓近似方法。
  • 函数 cv2.drawContours() 可以被用来绘制轮廓。它可以根据你提供的边界点绘制任何形状。它的第一个参数是原始图像,第二个参数是轮廓,一个 Python 列表。第三个参数是轮廓的索引(在绘制独立轮廓是很有用,当设置为 -1 时绘制所有轮廓)。接下来的参数是轮廓的颜色和厚度等。
import cv2
img = cv2.imread('opencv.jpg')
imggray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imggray,0,255,cv2.THRESH_OTSU)
#cv2.CHAIN_APPROX_NONE,所有的边界点都会被存储
#cv2.CHAIN_APPROX_SIMPLE只存储端点
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
# -1代表绘制所有轮廓
img1 = cv2.drawContours(img,contours,-1,(0,0,0),3)
cv2.imshow('img1',img1)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

  • 2.轮廓特征:

  • 2.1 矩

#轮廓重心
cnt = contours[0]
M = cv2.moments(cnt)
print(M)
cx = int(M['m10']/M['m00'])
cy = int(M['m01']/M['m00'])
print (cx,cy)

{‘m00’: 165073.0, ‘m10’: 35573231.5, ‘m01’: 31611479.5, ‘m20’: 10221375184.333332, ‘m11’: 6812273832.25, ‘m02’: 8071464432.333333, ‘m30’: 3304059528335.75, ‘m21’: 1957393347799.8333, ‘m12’: 1739400585167.8333, ‘m03’: 2318528158187.75, ‘mu20’: 2555343796.083332, ‘mu11’: 0.0, ‘mu02’: 2017866108.083333, ‘mu30’: 0.0009765625, ‘mu21’: 0.00018310546875, ‘mu12’: 0.0, ‘mu03’: 0.0, ‘nu20’: 0.0937771975630983, ‘nu11’: 0.0, ‘nu02’: 0.07405259087393658, ‘nu30’: 8.82083976632943e-17, ‘nu21’: 1.653907456186768e-17, ‘nu12’: 0.0, ‘nu03’: 0.0}
215 191

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

165073.0

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

1628.0

  • 2.4 轮廓近似
    将轮廓形状近似到另外一种由更少点组成的轮廓形状,新轮廓的点的数目由我们设定的准确度来决定。使用的Douglas-Peucker算法。
    为了帮助理解,假设我们要在一幅图像中查找一个矩形,但是由于图像的种种原因,我们不能得到一个完美的矩形,而是一个“坏形状”(如下图所示)。现在你就可以使用这个函数来近似这个形状()了。这个函数的第二个参数叫epsilon,它是从原始轮廓到近似轮廓的最大距离。它是一个准确度参数。选择一个好的 epsilon 对于得到满意结果非常重要。
#轮廓近似
img = cv2.imread('giao.jpg')
imggray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imggray,0,255,cv2.THRESH_OTSU)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[0]
epsilon = 0.1*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)
cv2.polylines(img,[approx],True,(0,0,255),2)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

下边,第二幅图中的绿线是当 epsilon = 10% 时得到的近似轮廓,第三幅图是当 epsilon = 1% 时得到的近似轮廓。第三个参数设定弧线是否闭合。
在这里插入图片描述

  • 2.5 凸包
    凸包与轮廓近似相似,但不同,虽然有些情况下它们给出的结果是一样的。函数 cv2.convexHull() 可以用来检测一个曲线是否具有凸性缺陷,并能纠正缺陷。
#凸包img = cv2.imread('giao.jpg')
img2 = cv2.imread('giao.jpg')
imggray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imggray,0,255,cv2.THRESH_OTSU)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[0]
hull = cv2.convexHull(cnt)
cv2.polylines(img2,[hull],True,(0,0,255),2)
cv2.imshow('img',img2)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述
对此可以参考链接:https://segmentfault.com/a/1190000015663722

  • 2.6 凸性检测
#凸性检测
k = cv2.isContourConvex(cnt)
print (k)

False

  • 2.7 直边界矩形
#边界矩形,直边矩形
img3 = cv2.imread('str.jpg')
imggray = cv2.cvtColor(img3,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imggray,0,255,cv2.THRESH_OTSU)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[1]
#(x,y)为矩形左上角的坐标,(w,h)是矩形的宽和高。
x,y,w,h = cv2.boundingRect(cnt)
img4 = cv2.rectangle(img3,(x,y),(x+w,y+h),(0,255,0),2)
cv2.imshow('img',img4)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

  • 2.8 最小外接矩形
    这个边界矩形是面积最小的,因为它考虑了对象的旋转。用到的函数为cv2.minAreaRect()。返回的是一个 Box2D 构,其中包含矩形左上角角点的坐标(x,y),矩形的宽和高(w,h),以及旋转角度。但是要绘制这个矩形需要矩形的 4 个角点,可以通过函数 cv2.boxPoints() 获得。
#最小外接矩形
import numpy as np
img3 = cv2.imread('str.jpg')
imggray = cv2.cvtColor(img3,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imggray,0,255,cv2.THRESH_OTSU)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[1]
rect = cv2.minAreaRect(cnt)
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.fillPoly(img3,[box],(0,0,255))
cv2.imshow('img',img3)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

  • 2.9 最小外接圆
#最小外接圆
img3 = cv2.imread('str.jpg')
imggray = cv2.cvtColor(img3,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imggray,0,255,cv2.THRESH_OTSU)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[1]
(x,y),radius = cv2.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
img4 = cv2.circle(img3,center,radius,(0,255,0),2)
cv2.imshow('img',img4)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

  • 2.10 椭圆拟合
#椭圆拟合
img3 = cv2.imread('str.jpg')
imggray = cv2.cvtColor(img3,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imggray,0,255,cv2.THRESH_OTSU)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[1]
ellipse = cv2.fitEllipse(cnt)
im = cv2.ellipse(img3,ellipse,(0,255,0),2)
cv2.imshow('img',im)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

  • 2.11 直线拟合
#直线拟合
img3 = cv2.imread('str.jpg')
rows,cols = img3.shape[:2]
imggray = cv2.cvtColor(img3,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(imggray,0,255,cv2.THRESH_OTSU)
contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[1]
[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)
img = cv2.line(img3,(cols-1,righty),(0,lefty),(0,255,0),2)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

  • 3.轮廓性质
  • 3.1 宽高比
#宽高比
x,y,w,h = cv2.boundingRect(cnt)
aspect_ratio = float(w)/h
print (aspect_ratio)
  • 3.2 轮廓面积与边界矩形面积的比
area = cv2.contourArea(cnt)
x,y,w,h = cv2.boundingRect(cnt)
rect_area = w*h
extent = float(area)/rect_area
print (extent)
  • 3.3 轮廓面积与凸包面积的比
area = cv2.contourArea(cnt)
hull = cv2.convexHull(cnt)
hull_area = cv2.contourArea(hull)
solidity = float(area)/hull_area
print (solidity)
  • 3.4 与轮廓面积相等的圆形直径
area = cv2.contourArea(cnt)
equi_diameter = np.sqrt(4*area/np.pi)
print (equi_diameter)
  • 3.5 方向
(x,y),(MA,ma),angle = cv2.fitEllipse(cnt)
print ((x,y),(MA,ma),angle)
  • 3.6 轮廓的掩膜与像素点
img = cv2.imread('str.jpg',0)
mask = np.zeros(img.shape,np.uint8)
mask = cv2.drawContours(mask,[cnt],0,255,-1)
cv2.imshow('mask',mask)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

  • 3.7 最大值和最小值及它们的位置
min_val,max_val,min_loc,max_loc = cv2.minMaxLoc(img,mask=mask)
print (min_val,max_val,min_loc,max_loc)
  • 3.8 平均颜色及平均灰度
mean_val = cv2.mean(img,mask=mask)
print (mean_val)
  • 3.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])
print (leftmost,rightmost,topmost,bottommost)
  • 3.10 凸缺陷
    前面我们已经学习了轮廓的凸包,对象上的任何凹陷都被成为凸缺陷。OpenCV 中有一个函数 cv.convexityDefect() 可以帮助我们找到凸缺陷。如果要查找凸缺陷,在使用函数 cv2.convexHull 找凸包时,参数returnPoints 一定要是 False。它会返回一个数组,其中每一行包含的值是 [起点,终点,最远的点,到最远点的近似距离。
#凸缺陷
import cv2 
import numpy as np
img = cv2.imread('fb.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(img_gray,0,255,cv2.THRESH_OTSU)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt = contours[6]
hull = cv2.convexHull(cnt,returnPoints=False)
defects = cv2.convexityDefects(cnt,hull)
for i in range(defects.shape[0]):
    s,e,f,d = defects[i,0]
    start = tuple(cnt[s][0])
    end = tuple(cnt[e][0])
    far = tuple(cnt[f][0])
    cv2.line(img,start,end,[0,255,0],2)
    cv2.circle(img,far,5,[0,0,255],-1)   
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

在这里插入图片描述

  • 3.11 Point Polygon Test
    求解图像中的一个点到一个对象轮廓的最短距离。如果点在轮廓的外部,返回值为负。如果在轮廓上,返回值为 0。如果在轮廓内部,返回值为正。此函数的第三个参数是measureDist如果设置为True,就会计算最短距离。如果是 False,只会判断这个点与轮廓之间的位置关系(返回值为
    +1,-1,0)。
# Point Polygon Test
dist = cv2.pointPolygonTest(cnt,(50,50),True)
print (dist)
  • 3.12 形状匹配
    函数 cv2.matchShape() 可以帮我们比较两个形状或轮廓的相似度。如果返回值越小,匹配越好。它是根据 Hu 矩来计算的。
# 形状匹配
import cv2
import numpy as np
img = cv2.imread('fb.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(img_gray,0,255,cv2.THRESH_OTSU)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt1 = contours[6]
img2 = cv2.imread('2.jpg',0)
ret, thresh2 = cv2.threshold(img2, 127, 255,0)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt2 = contours[0]
ret1 = cv2.matchShapes(cnt1,cnt2,1,0.0)
ret2 = cv2.matchShapes(cnt1,cnt1,1,0.0)
print (ret1,ret2)

0.3493676665950478 0.0
在这里插入图片描述

### 回答1: OpenCV提供了一个函数cv::findContours(),可以用于从二值图像中提取轮廓。 具体步骤如下: 1. 将彩色图像转化为灰度图像。 2. 对灰度图像进行二值化处理,得到二值图像。 3. 使用cv::findContours()函数提取轮廓。 4. 绘制轮廓。 下面是一个示例代码: ```python import cv2 import numpy as np # 读入图像 img = cv2.imread('image.jpg') # 转化为灰度图像 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化处理 ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY) # 提取轮廓 contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 绘制轮廓 cv2.drawContours(img, contours, -1, (0, 0, 255), 2) # 显示图像 cv2.imshow("image", img) cv2.waitKey(0) cv2.destroyAllWindows() ``` 其中,cv2.findContours()函数的参数说明如下: - 第一个参数:二值图像。 - 第二个参数:轮廓检索模式。有以下四种模式: - cv2.RETR_EXTERNAL:只检测外轮廓。 - cv2.RETR_LIST:检测所有轮廓,不建立轮廓之间的层级关系。 - cv2.RETR_CCOMP:检测所有轮廓,并将轮廓分为两级,即外层轮廓和内层轮廓。 - cv2.RETR_TREE:检测所有轮廓,并建立轮廓之间的层级关系。 - 第三个参数:轮廓逼近方法。有以下三种方法: - cv2.CHAIN_APPROX_NONE:存储所有的轮廓点。 - cv2.CHAIN_APPROX_SIMPLE:压缩水平、垂直、对角线方向上的像素点,只保留端点。 - cv2.CHAIN_APPROX_TC89_L1、cv2.CHAIN_APPROX_TC89_KCOS:使用Teh-Chin链逼近算法。 返回值: - contours:检测到的轮廓,每个轮廓是一个Numpy数组。 - hierarchy:检测到的轮廓之间的层级关系,每个轮廓有四个值:[next, previous, child, parent]。其中,next表示下一个轮廓的索引,previous表示前一个轮廓的索引,child表示第一个子轮廓的索引,parent表示父轮廓的索引。如果当前轮廓没有子轮廓,则child=-1;如果当前轮廓没有父轮廓,则parent=-1。 ### 回答2: 在OpenCV中,图像轮廓提取是一种常用的图像处理技术,它可以帮助我们找到图像中对象的边界轮廓提取可以用于许多应用,如形状识别、物体检测和图像分割等。 在OpenCV中,图像轮廓提取的主要步骤如下: 1. 将图像转换为灰度图像,这有助于减少噪声并简化处理。 2. 对图像进行阈值处理,将图像转换为二值图像。这样可以将对象与背景分离。 3. 对二值图像进行形态学操作,如腐蚀和膨胀,可以去除噪声并平滑边界。 4. 使用cv2.findContours()函数找到图像中的轮廓。该函数将返回一个包含所有轮廓的列表。 5. 可选地,可以使用cv2.drawContours()函数在原始图像绘制轮廓。这可以帮助我们可视化轮廓提取的结果。 在进行图像轮廓提取时,还可以使用一些参数来调整轮廓提取的效果。例如,可以通过调整阈值值和形态学操作来控制轮廓的数量和精度。 总的来说,OpenCV提供了简单且强大的图像轮廓提取工具,它可以帮助我们提取图像中的对象边界,进而实现各种应用。学习和掌握轮廓提取技术对于图像处理和计算机视觉相关领域的研究和应用非常重要。 ### 回答3: OpenCV是一个强大的计算机视觉库,具有丰富的图像处理功能,其中包括图像轮廓提取。 图像轮廓是指图像中连接相同颜色或强度的连续曲线的图像特征。在OpenCV中,图像轮廓提取是通过以下几个步骤实现的: 首先,我们需要将图像转换为灰度图像。这是因为灰度图像只有一个通道,更容易处理。可以使用cvtColor()函数将彩色图像转换为灰度图像。 然后,我们可以使用阈值函数将图像二值化。通过设定适当的阈值,我们可以将图像分为目标和背景两部分。可以使用threshold()函数设置阈值,并根据需要选择不同的阈值类型。 接下来,使用findContours()函数可以检测图像中的轮廓。该函数将按大小排序返回一系列轮廓,并存储为一系列点的集合。可以选择提取所有的轮廓,或者只提取特定大小的轮廓。还可以使用其他参数来调整轮廓的检测精度和准确性。 提取轮廓后,可以使用drawContours()函数将轮廓绘制在原始图像上。该函数可以选择绘制所有的轮廓或单独绘制其中的一个轮廓。 如果需要进一步处理轮廓,可以使用一些附加函数,如计算轮廓面积周长边界等。还可以对轮廓进行操作,例如填充、裁剪或平滑处理。 最后,通过使用imshow()函数可以将处理后的图像显示出来。 总之,OpenCV提供了一套完整且易于使用的函数,可以方便地从图像中提取轮廓。通过适当的处理和调整参数,我们可以根据实际需求获取准确的轮廓信息。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值