教程3_图像的轮廓

目录

目标

[1. 特征矩](#1. 特征矩)

2、轮廓质心

[3. 轮廓面积](#3. 轮廓面积)

[4. 轮廓周长](#4. 轮廓周长)

[5. 轮廓近似](#5. 轮廓近似)

[6. 轮廓凸包](#6. 轮廓凸包)

[7. 边界矩形](#7. 边界矩形)

7.1.直角矩形

[7.2. 旋转矩形](#7.2. 旋转矩形)

[8. 最小闭合圈](#8. 最小闭合圈)

[9. 拟合一个椭圆](#9. 拟合一个椭圆)

[10. 拟合直线](#10. 拟合直线)


目标

在本文中,我们将学习 - 如何找到轮廓的不同特征,例如面积,周长,质心,边界框等。 - 您将看到大量与轮廓有关的功能。

1. 特征矩

特征矩可以帮助您计算一些特征,例如物体的质心,物体的面积等。请查看特征矩上的维基百科页面。函数 cv.moments() 提供了所有计算出的矩值的字典。见下文:

python 复制代码
import numpy as np
import cv2 as cv
img = cv.imread('star.jpg',0)
ret,thresh = cv.threshold(img,127,255,0)
contours,hierarchy = cv.findContours(thresh, 1, 2)
cnt = contours[0]
M = cv.moments(cnt)
print( M )

从这一刻起,您可以提取有用的数据,例如面积,质心等。

2、轮廓质心

质心由关系给出,cx=M10/M00 和 cy=M01/M00。可以按照以下步骤进行,第一个示例为简单的检测单个轮廓,第二个示例能检测图片中的多个轮廓。

python 复制代码
import numpy as np
import cv2 as cv

img = cv.imread('star.jpg',0)

ret,thresh = cv.threshold(img,127,255,0)

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'])

print('轮廓的质心坐标为:(%d,%d) '%cx %cy)
python 复制代码
import cv2  
import numpy as np  
  
# 读取图像  
image = cv2.imread('7.jpg')  
  
# 转换为灰度图像  
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)  
  
# 应用阈值来获取二值图像  
_, thresholded = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)  
  
# 查找轮廓  
contours, _ = cv2.findContours(thresholded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)  
  
# 遍历每个轮廓  
for contour in contours:  
    # 计算轮廓的矩  
    M = cv2.moments(contour)  
      
    # 检查矩是否存在(轮廓不为空)  
    if M["m00"] != 0:  
        # 计算质心  
        cX = int(M["m10"] / M["m00"])  
        cY = int(M["m01"] / M["m00"])  
          
        # 在图像上绘制质心  
        cv2.circle(image, (cX, cY), 5, (255, 0, 0), -1)  
        cv2.putText(image, "centroid", (cX - 25, cY - 25), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)  
  
# 显示结果图像  
cv2.imshow('Image with Centroids', image)  
cv2.waitKey(0)  
cv2.destroyAllWindows()

3. 轮廓面积

轮廓区域由函数 cv.contourArea() 或从矩 M['m00'] 中给出。

python 复制代码
import numpy as np
import cv2 as cv

img = cv.imread('star.jpg',0)

ret,thresh = cv.threshold(img,127,255,0)

contours,hierarchy = cv.findContours(thresh, 1, 2)

cnt = contours[0]

M = cv.moments(cnt)
print( M )

area = cv.contourArea(cnt) 

4. 轮廓周长

也称为弧长。可以使用 cv.arcLength() 函数找到它。第二个参数指定形状是闭合轮廓(True)还是曲线。

python 复制代码
import numpy as np
import cv2 as cv

img = cv.imread('star.jpg',0)

ret,thresh = cv.threshold(img,127,255,0)

contours,hierarchy = cv.findContours(thresh, 1, 2)

cnt = contours[0]

M = cv.moments(cnt)
print( M )

perimeter = cv.arcLength(cnt,True)

5. 轮廓近似

根据我们指定的精度,它可以将轮廓形状近似为顶点数量较少的其他形状。它是Douglas-Peucker算法的实现。检查维基百科页面上的算法和演示。

为了理解这一点,假设您试图在图像中找到一个正方形,但是由于图像中的某些问题,您没有得到一个完美的正方形,而是一个"坏形状"(如下图所示)。现在,您可以使用此功能来近似形状。在这种情况下,第二个参数称为epsilon,它是从轮廓到近似轮廓的最大距离。它是一个精度参数。需要正确选择epsilon才能获得正确的输出。

python 复制代码
import numpy as np
import cv2 as cv

img = cv.imread('star.jpg',0)

ret,thresh = cv.threshold(img,127,255,0)

contours,hierarchy = cv.findContours(thresh, 1, 2)

cnt = contours[0]

M = cv.moments(cnt)
print( M )

epsilon = 0.1*cv.arcLength(cnt,True) 
approx = cv.approxPolyDP(cnt,epsilon,True)

在第二张图片中,绿线显示了ε=弧长的10%时的近似曲线。第三幅图显示了ε=弧长度的1%时的情况。第三个参数指定曲线是否闭合。

6. 轮廓凸包

凸包外观看起来与轮廓逼近相似,但不相似(在某些情况下两者可能提供相同的结果)。在这里,cv.convexHull()函数检查曲线是否存在凸凹缺陷并对其进行校正。一般而言,凸曲线是始终凸出或至少平坦的曲线。如果在内部凸出,则称为凸度缺陷。例如,检查下面的手的图像。红线显示手的凸包。双向箭头标记显示凸度缺陷,这是凸包与轮廓线之间的局部最大偏差。

python 复制代码
import numpy as np
import cv2 as cv

img = cv.imread('star.jpg',0)

ret,thresh = cv.threshold(img,127,255,0)

contours,hierarchy = cv.findContours(thresh, 1, 2)

cnt = contours[0]

M = cv.moments(cnt)
print( M )

hull = cv.convexHull(cnt) 

但是,如果要查找凸度缺陷,则需要传递returnPoints = False。为了理解它,我们将拍摄上面的矩形图像。首先,我发现它的轮廓为cnt。现在,我发现它的带有returnPoints = True的凸包,得到以下值:[[[234 202]],[[51 202]],[[51 79]],[[234 79]]],它们是四个角 矩形的点。现在,如果对returnPoints = False执行相同的操作,则会得到以下结果:[[129],[67],[0],[142]]。这些是轮廓中相应点的索引。例如,检查第一个值:cnt [129] = [[234,202]]与第一个结果相同(对于其他结果依此类推)。

7. 边界矩形

有两种类型的边界矩形。

7.1.直角矩形

它是一个矩形,不考虑物体的旋转。所以边界矩形的面积不是最小的。它是由函数cv.boundingRect()找到的。

(x,y)为矩形的左上角坐标,而(w,h)为矩形的宽度和高度。

python 复制代码
import numpy as np
import cv2 as cv

img = cv.imread('star.jpg',0)

ret,thresh = cv.threshold(img,127,255,0)

contours,hierarchy = cv.findContours(thresh, 1, 2)

cnt = contours[0]

M = cv.moments(cnt)
print( M )


x,y,w,h = cv.boundingRect(cnt)
cv.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
7.2. 旋转矩形

这里,边界矩形是用最小面积绘制的,所以它也考虑了旋转。使用函数是 cv.minAreaRect()。它返回一个Box2D结构,其中包含以下细节 -(中心(x,y),(宽度,高度),旋转角度)。但要画出这个矩形,我们需要矩形的四个角。它由函数 cv.boxPoints() 获得:

python 复制代码
import numpy as np
import cv2 as cv

img = cv.imread('star.jpg',0)

ret,thresh = cv.threshold(img,127,255,0)

contours,hierarchy = cv.findContours(thresh, 1, 2)

cnt = contours[0]

M = cv.moments(cnt)
print( M )


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

两个矩形都显示在一张单独的图像中。绿色矩形显示正常的边界矩形。红色矩形是旋转后的矩形。

8. 最小闭合圈

接下来,使用函数 cv.minEnclosingCircle() 查找对象的圆周。它是一个以最小面积完全覆盖物体的圆。

python 复制代码
import numpy as np
import cv2 as cv

img = cv.imread('star.jpg',0)

ret,thresh = cv.threshold(img,127,255,0)

contours,hierarchy = cv.findContours(thresh, 1, 2)

cnt = contours[0]

M = cv.moments(cnt)
print( M )

(x,y),radius = cv.minEnclosingCircle(cnt)
center = (int(x),int(y))
radius = int(radius)
cv.circle(img,center,radius,(0,255,0),2)

9. 拟合一个椭圆

下一个是把一个椭圆拟合到一个物体上。它返回内接椭圆的旋转矩形。

python 复制代码
import numpy as np
import cv2 as cv

img = cv.imread('star.jpg',0)

ret,thresh = cv.threshold(img,127,255,0)

contours,hierarchy = cv.findContours(thresh, 1, 2)

cnt = contours[0]

M = cv.moments(cnt)
print( M )

ellipse = cv.fitEllipse(cnt)
cv.ellipse(img,ellipse,(0,255,0),2)

10. 拟合直线

同样,我们可以将一条直线拟合到一组点。下图包含一组白点。我们可以近似一条直线。

python 复制代码
import numpy as np
import cv2 as cv

img = cv.imread('star.jpg',0)

ret,thresh = cv.threshold(img,127,255,0)

contours,hierarchy = cv.findContours(thresh, 1, 2)

cnt = contours[0]

M = cv.moments(cnt)
print( M )

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)

12. 长宽比

它是对象边界矩形的宽度与高度的比值。

x,y,w,h = cv.boundingRect(cnt)
aspect_ratio = float(w)/h

12. 范围

范围是轮廓区域与边界矩形区域的比值。

area = cv.contourArea(cnt)
x,y,w,h = cv.boundingRect(cnt)
rect_area = w*h
extent = float(area)/rect_area

13. 坚实度

坚实度是等高线面积与其凸包面积之比。

area = cv.contourArea(cnt)
hull = cv.convexHull(cnt)
hull_area = cv.contourArea(hull)
solidity = float(area)/hull_area

14. 等效直径

等效直径是面积与轮廓面积相同的圆的直径。

area = cv.contourArea(cnt)
equi_diameter = np.sqrt(4*area/np.pi)

15. 取向

取向是物体指向的角度。以下方法还给出了主轴和副轴的长度。

(x,y),(MA,ma),angle = cv.fitEllipse(cnt)

16. 掩码和像素点

在某些情况下,我们可能需要构成该对象的所有点。可以按照以下步骤完成:

mask = np.zeros(imgray.shape,np.uint8)
cv.drawContours(mask,[cnt],0,255,-1)
pixelpoints = np.transpose(np.nonzero(mask))
#pixelpoints = cv.findNonZero(mask)

这里提供了两个方法,一个使用Numpy函数,另一个使用OpenCV函数(最后的注释行)。结果也是一样的,只是略有不同。Numpy给出的坐标是(行、列)格式,而OpenCV给出的坐标是(x,y)格式。所以基本上答案是可以互换的。注意,row = x, column = y

17. 最大值,最小值和它们的位置

我们可以使用掩码图像找到这些参数。

min_val, max_val, min_loc, max_loc = cv.minMaxLoc(imgray,mask = mask)

18. 平均颜色或平均强度

在这里,我们可以找到对象的平均颜色。或者可以是灰度模式下物体的平均强度。我们再次使用相同的掩码进行此操作。

mean_val = cv.mean(im,mask = mask)

19. 极端点

极点是指对象的最顶部,最底部,最右侧和最左侧的点。

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

例如,如果我将其应用于印度地图,则会得到以下结果:

相关推荐
昨日之日20061 小时前
Moonshine - 新型开源ASR(语音识别)模型,体积小,速度快,比OpenAI Whisper快五倍 本地一键整合包下载
人工智能·whisper·语音识别
浮生如梦_1 小时前
Halcon基于laws纹理特征的SVM分类
图像处理·人工智能·算法·支持向量机·计算机视觉·分类·视觉检测
深度学习lover1 小时前
<项目代码>YOLOv8 苹果腐烂识别<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·苹果腐烂识别
热爱跑步的恒川2 小时前
【论文复现】基于图卷积网络的轻量化推荐模型
网络·人工智能·开源·aigc·ai编程
API快乐传递者2 小时前
淘宝反爬虫机制的主要手段有哪些?
爬虫·python
阡之尘埃4 小时前
Python数据分析案例61——信贷风控评分卡模型(A卡)(scorecardpy 全面解析)
人工智能·python·机器学习·数据分析·智能风控·信贷风控
孙同学要努力6 小时前
全连接神经网络案例——手写数字识别
人工智能·深度学习·神经网络
Eric.Lee20216 小时前
yolo v5 开源项目
人工智能·yolo·目标检测·计算机视觉
其实吧37 小时前
基于Matlab的图像融合研究设计
人工智能·计算机视觉·matlab
丕羽7 小时前
【Pytorch】基本语法
人工智能·pytorch·python