OpenCV 例程200篇 总目录-202206更新

文章目录

  • 【youcans 的 OpenCV 例程300篇】200.轮廓的基本属性
    • 2.4 轮廓的基本属性
      • 2.4.1 轮廓的宽高比(Aspect Ratio)
      • 2.4.2 轮廓的面积比(Extent)
      • 2.4.3 轮廓的坚实度(Solidity)
      • 2.4.4 轮廓的等效直径(Equivalent diameter)
      • 2.4.5 轮廓的方向(Orientation)
      • 2.4.6 轮廓的掩模(Mask)
      • 2.4.7 最大值/最小值及其位置
      • 2.4.8 灰度均值和颜色均值
      • 2.4.9 极端点位置
    • 例程 12.6:轮廓的基本属性

【youcans 的 OpenCV 例程300篇】200.轮廓的基本属性

在对实际图像进行轮廓查找时,得到的轮廓数量很多。获取轮廓后,通常基于轮廓的特征进行筛选、识别和处理。例如,基于轮廓的周长和面积对轮廓进行筛选,然后绘制筛选的目标轮廓或其最小外接矩形。

2.4 轮廓的基本属性

2.4.1 轮廓的宽高比(Aspect Ratio)

对象的宽高比(Aspect Ratio),是指对象垂直边界矩形的宽度与高度的比值,是对象/轮廓的重要特征。

通过对象/轮廓的垂直矩形边界框,可以计算宽高比:

AspectRatio=Width(BoundingRect)Height(BoundingRect)AspectRatio = \frac{Width_{(BoundingRect)}}{Height_{(BoundingRect)}} AspectRatio=Height(BoundingRect)​Width(BoundingRect)​​

例程:

    # 轮廓的宽高比 (Aspect Ratio)x, y, wv, hv = cv2.boundingRect(cnt)  # 轮廓外接垂直矩形的左上顶点 (x,y), 宽度 w, 高度 haspect_ratio = round(wv/hv, 2)  # 轮廓外接垂直矩形的宽高比

注意:

  1. 在 OpenCV 中使用垂直边界矩形计算宽高比,而不是用最小边界矩形计算。
  2. 有的资料中用“长宽比”描述,但从 OpenCV 的定义应为“宽高比”。

2.4.2 轮廓的面积比(Extent)

对象的面积(Extent),是指对象面积与垂直边界矩形面积的比值。

通过轮廓面积和垂直边界矩形面积,可以计算面积比:
Extent=Area(Object)Area(BoundingRect)Extent = \frac{Area_{(Object)}}{Area_{(BoundingRect)}} Extent=Area(BoundingRect)​Area(Object)​​
例程:

    # 轮廓的面积比 (Extent)x, y, wv, hv = cv2.boundingRect(cnt)  # 轮廓外接垂直矩形的左上顶点 (x,y), 宽度 w, 高度 hrect_area = wv * hv  # 轮廓外接垂直矩形的面积cnt_area = cv2.contourArea(cnt)  # 轮廓的面积extent = round(cnt_area/rect_area, 2)  # 轮廓的面积比

注意:

  1. 在 OpenCV 中的使用外接垂直边界矩形计算面积比,而不是用最小矩形边界计算。
  2. 有的资料中将 Extent 译为“占空比”、“范围”,皆供参考。

2.4.3 轮廓的坚实度(Solidity)

对象的坚实度(Solidity),是指对象面积与其凸包面积的比值。

通过轮廓面积和凸包面积,可以计算坚实度:
Solidity=Area(Object)Area(ConvexHull)Solidity = \frac{Area_{(Object)}}{Area_{(ConvexHull)}} Solidity=Area(ConvexHull)​Area(Object)​​
例程:

    # 轮廓的坚实度 (Solidity)cnt_area = cv2.contourArea(cnt)  # 轮廓的面积hull = cv2.convexHull(cnt)  # 轮廓的凸包,返回凸包顶点集hull_area = cv2.contourArea(hull)  # 凸包的面积solidity = round(cnt_area/hull_area, 2)  # 轮廓的坚实度

2.4.4 轮廓的等效直径(Equivalent diameter)

轮廓的等效直径(Equivalent diameter), 是指与轮廓面积相等的圆形的直径 。

通过轮廓面积,可以计算轮廓的等效直径:
Dequ=4∗Area(Object)/πD_{equ} = \sqrt{4 * Area_{(Object)} / {\pi}} Dequ​=4∗Area(Object)​/π​

例程:

    # 轮廓的等效直径 (Equivalent diameter)cnt_area = cv2.contourArea(cnt)  # 轮廓的面积dEqu = round(np.sqrt(4*cnt_area/np.pi), 2)  # 轮廓的等效直径

注意:

  1. 轮廓的等效直径,也称为当量直径,注意不是轮廓外接圆/内接圆的直径。

2.4.5 轮廓的方向(Orientation)

轮廓的方向(Orientation), 是指物体指向的角度。

通过函数 cv2.fitEllipse() 可以得到轮廓的最优拟合椭圆,并返回椭圆的中心点、轴长和旋转角度:

  • retval = [(x,y), (a,b), ang],椭圆中心点坐标 (x,y),椭圆长轴、短轴长度 (a,b),旋转角度 angle

例程:

    # 轮廓的方向 (Orientation)ellipse = cv2.fitEllipse(cnt)  # 椭圆中心点 (x,y), 长轴短轴长度 (a,b), 旋转角度 angangle = round(ellipse[2], 1)  # 轮廓的方向, 指椭圆长轴 a 与水平方向的夹角

注意:

  1. 旋转角度 angle 表示轮廓的方向,指椭圆长轴与水平方向的夹角,顺时针为正。

2.4.6 轮廓的掩模(Mask)

图像掩模(Mask)也常被写成“图像掩膜”,或称为掩码、掩像、模板、遮罩,有的资料中甚至译成“面具”。图像处理时,可以只对掩模区域进行处理,或者只对非掩模区域进行处理。

轮廓的掩模是轮廓区域的掩模图像,背景为黑色、轮廓区域为白色。
轮廓的掩模可以通过绘制轮廓 cv2.drawContours() 函数的内部填充功能(“CV_FILLED”)实现。

轮廓的像素点(Pixelpoints),是指轮廓区域内的所有像素点。
轮廓的像素点可以由轮廓掩模的非 0 筛选(切片)获得,如通过 Numpy 函数 np.nonzero() 或 OpenCV 函数 cv2.findNonZero() 实现。

例程:

    # 轮廓的掩模和像素点 (Mask)maskCnt = np.zeros(gray.shape, np.uint8)  # 背景区域置为黑色cv2.drawContours(maskCnt, [cnt], 0, 255, -1)  # 轮廓区域置为白色pixelsNP = np.transpose(np.nonzero(maskCnt))  # (15859, 2)pixelsCV = cv2.findNonZero(maskCnt)  # (15859, 1, 2)

注意:

  1. 通过函数 np.nonzero() 获得的像素点集形状为 (len,2),像素点的坐标格式为行-列:(y, x)。
  2. 通过函数 cv.findNonZero() 获得的像素点集形状为 (len,1,2),像素点的坐标格式为列-行:(x, y)。

2.4.7 最大值/最小值及其位置

轮廓中像素点的灰度值的最大值、最小值及其位置,可以由函数 **cv.minMaxLoc() ** 通过掩模图像获得。

函数说明:

cv.minMaxLoc(src[, mask]) → minVal, maxVal, minLoc, maxLoc

对于灰度图像或二维数组,查找最大值、最小值及其位置。

参数说明:

  • src:单通道图像或二维数组
  • mask:掩模图像,可选项,只对掩模区域查找最大值、最小值
  • minVal: 最小值,浮点数
  • maxVal: 最大值,浮点数
  • minLoc: 最小值像素的位置,像素坐标 (x, y)
  • maxLoc: 最大值像素的位置,像素坐标 (x, y)

例程:

    # 轮廓的掩模maskCnt = np.zeros(gray.shape, np.uint8)  # 背景区域置为黑色cv2.drawContours(maskCnt, [cnt], 0, 255, -1)  # 轮廓区域置为白色# 轮廓的最大值/最小值及其位置min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(gray, mask=maskCnt)  # 必须用灰度图像print(min_val, max_val, min_loc, max_loc)  # 0.0 255.0 (468, 291) (379, 357)

注意:

  1. 最大值、最小值是针对灰度图像的像素值而言的,对于多通道的彩色图像是无所谓最大值最小值的。
  2. 最大值、最小值像素点坐标的格式为列-行:(x, y)。
  3. 如果存在多个最大值/最小值的像素,只返回其中一个最大值/最小值像素点的位置。

2.4.8 灰度均值和颜色均值

轮廓中像素点的颜色均值或灰度值均值,可以由函数 **cv.mean() ** 对掩模图像计算。

函数说明:

cv.mean(src[, mask]) → retval

对于单通道或多通道图像,计算整个图像或掩模区域的像素值的均值。

参数说明:

  • src:单通道或多通道图像
  • mask:掩模图像,可选项
  • retval:4 个元素的元组,元素值为浮点数

例程:

    # 轮廓的掩模maskCnt = np.zeros(gray.shape, np.uint8)  # 背景区域置为黑色cv2.drawContours(maskCnt, [cnt], 0, 255, -1)  # 轮廓区域置为白色# 轮廓的灰度均值和颜色均值gray_mean = cv2.mean(gray, maskCnt)  # (mg, 0.0, 0.0, 0.0)img_mean = cv2.mean(img, maskCnt)  # (mR, mG, mB, 0.0)

注意:

  1. 函数允许 1~4 通道的图像输入,返回值是一个元组,包含 4个元素,是图像对应通道的均值。如果该通道不存在,则输出的均值为 0.0。例如输入为灰度图像时输出为 (mg, 0.0, 0.0, 0.0)。

2.4.9 极端点位置

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

查找轮廓的极端点,可以通过轮廓边界点集 contours[i],对所有边界点的横坐标、纵坐标分别查找最大值、最小值及其位置。

由轮廓上下左右的极端点位置,就可以得到轮廓的垂直矩形边界框的顶点坐标和宽度高度。

例程:

    # 轮廓的极端点位置leftmost = tuple(cnt[cnt[:, :, 0].argmin()][0])  # cnt[:,:,0], 所有边界点的横坐标rightmost = tuple(cnt[cnt[:, :, 0].argmax()][0])topmost = tuple(cnt[cnt[:, :, 1].argmin()][0])  # cnt[:,:,1], 所有边界点的纵坐标bottommost = tuple(cnt[cnt[:, :, 1].argmax()][0])

例程 12.6:轮廓的基本属性

    # 12.6 轮廓的基本属性img = cv2.imread("../images/seagull01.png", flags=1)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 灰度图像# HSV 色彩空间图像分割hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)  # 将图片转换到 HSV 色彩空间lowerBlue, upperBlue = np.array([100, 43, 46]), np.array([124, 255, 255])  # 蓝色阈值segment = cv2.inRange(hsv, lowerBlue, upperBlue)  # 背景色彩图像分割kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))  # (5, 5) 结构元binary = cv2.dilate(cv2.bitwise_not(segment), kernel=kernel, iterations=3)  # 图像膨胀# 寻找二值化图中的轮廓# binary, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  # OpenCV3contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  # OpenCV4~#  绘制全部轮廓,contourIdx=-1 绘制全部轮廓imgCnts = img.copy()imgCnts = cv2.drawContours(imgCnts, contours, -1, (255,255,255), -1)  # 绘制全部轮廓, 内部填充print("len(contours) =", len(contours))  # 所有轮廓的列表cnt = contours[1]# 轮廓的垂直矩形边界框# boundingBoxes = [cv2.boundingRect(cnt) for cnt in contours]  # 所有轮廓的外接垂直矩形xv, yv, wv, hv = cv2.boundingRect(cnt)  # 矩形左上顶点的坐标 x, y, 矩形宽度 w, 高度 hprint("Vertical rectangle: (x,y)={}, (w,h)={}".format((xv, yv), (wv, hv)))cv2.rectangle(imgCnts, (xv,yv), (xv+wv,yv+hv), (0, 0, 255), 2)  # 绘制垂直矩形边界框# 轮廓的宽高比 (Aspect Ratio)xv, yv, wv, hv = cv2.boundingRect(cnt)  # 轮廓外接垂直矩形的左上顶点 (x,y), 宽度 w, 高度 haspect_ratio = round(wv/hv, 2)  # 轮廓外接垂直矩形的宽高比print("Vertical rectangle: w={}, h={}".format(wv,hv))print("Aspect ratio:", aspect_ratio)# 轮廓的面积比 (Extent)xv, yv, wv, hv = cv2.boundingRect(cnt)  # 轮廓外接垂直矩形的左上顶点 (x,y), 宽度 w, 高度 hrect_area = wv * hv  # 轮廓外接垂直矩形的面积cnt_area = cv2.contourArea(cnt)  # 轮廓的面积extent = round(cnt_area/rect_area, 2)  # 轮廓的面积比print("Area of cnt:", cnt_area)print("Area of VertRect:", rect_area)print("Extent(area ratio):", extent)# 轮廓的坚实度 (Solidity)cnt_area = cv2.contourArea(cnt)  # 轮廓的面积hull = cv2.convexHull(cnt)  # 轮廓的凸包,返回凸包顶点集hull_area = cv2.contourArea(hull)  # 凸包的面积solidity = round(cnt_area/hull_area, 2)  # 轮廓的坚实度print("Area of cnt:", cnt_area)print("Area of convex hull:", hull_area)print("Solidity(area ratio):", solidity)# 轮廓的等效直径 (Equivalent diameter)cnt_area = cv2.contourArea(cnt)  # 轮廓的面积dEqu = round(np.sqrt(4*cnt_area/np.pi), 2)  # 轮廓的等效直径print("Area of cnt:", cnt_area)print("Equivalent diameter:", dEqu)# 轮廓的方向 (Orientation)ellipse = cv2.fitEllipse(cnt)  # 椭圆中心点 (x,y), 长轴短轴长度 (a,b), 旋转角度 angangle = round(ellipse[2], 1)  # 轮廓的方向, 指椭圆长轴与水平方向的夹角print("Orientation of cnt: {}".format(angle))# 轮廓的掩模和像素点 (Mask)maskCnt = np.zeros(gray.shape, np.uint8)  # 背景区域置为黑色cv2.drawContours(maskCnt, [cnt], 0, 255, -1)  # 轮廓区域置为白色pixelsNP = np.transpose(np.nonzero(maskCnt))  # (15859, 2): (y, x)pixelsCV = cv2.findNonZero(maskCnt)  # (15859, 1, 2): (x, y)print("pixelsNP: {}, pixelsCV: {}".format(pixelsNP.shape, pixelsCV.shape))# 轮廓的最大值/最小值及其位置min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(gray, mask=maskCnt)  # 必须用灰度图像print("Minimum value is {} at Pos{}".format(min_val, min_loc))print("Maximum value is {} at Pos{}".format(max_val, max_loc))# 轮廓的灰度均值和颜色均值gray_mean = cv2.mean(gray, maskCnt)  # (mg, 0, 0, 0)img_mean = cv2.mean(img, maskCnt)  # (mR, mG, mB, 0)print("gray_mean: {:.1f} \nimg_mean: ({:.1f}, {:.1f}, {:.1f})".format(gray_mean[0], img_mean[0], img_mean[1], img_mean[2]))# 轮廓的极端点位置leftmost = tuple(cnt[cnt[:, :, 0].argmin()][0])  # cnt[:,:,0], 所有边界点的横坐标rightmost = tuple(cnt[cnt[:, :, 0].argmax()][0])topmost = tuple(cnt[cnt[:, :, 1].argmin()][0])  # cnt[:,:,1], 所有边界点的纵坐标bottommost = tuple(cnt[cnt[:, :, 1].argmax()][0])print("Left most is {} at Pos{}".format(leftmost[0], leftmost))print("Right most is {} at Pos{}".format(rightmost[0], rightmost))print("Top most is {} at Pos{}".format(topmost[1], topmost))print("Bottom most is {} at Pos{}".format(bottommost[1], bottommost))for point in [leftmost, rightmost, topmost, bottommost]:cv2.circle(imgCnts, point, 5, (0, 0, 255), -1)  # 在轮廓的极端点上绘制圆点plt.figure(figsize=(9, 6))plt.subplot(131), plt.axis('off'), plt.title("Origin")plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))plt.subplot(132), plt.axis('off'), plt.title("Tree contour")plt.imshow(cv2.cvtColor(imgCnts, cv2.COLOR_BGR2RGB))plt.subplot(133), plt.axis('off'), plt.title("Contour mask")plt.imshow(cv2.cvtColor(maskCnt, cv2.COLOR_BGR2RGB))plt.tight_layout()plt.show()

运行结果:

len(contours) = 6
Vertical rectangle: (x,y)=(168, 173), (w,h)=(132, 156)
Vertical rectangle: w=132, h=156
Aspect ratio: 0.85
Area of cnt: 9302.5
Area of VertRect: 20592
Extent(area ratio): 0.45
Area of cnt: 9302.5
Area of convex hull: 12546.5
Solidity(area ratio): 0.74
Area of cnt: 9302.5
Equivalent diameter: 108.83
Orientation of cnt: 155.4
pixelsNP: (9551, 2), pixelsCV: (9551, 1, 2)
Minimum value is 0.0 at Pos(204, 179)
Maximum value is 255.0 at Pos(233, 220)
gray_mean: 111.2
img_mean: (127.8, 113.6, 100.1)
Left most is 168 at Pos(168, 256)
Right most is 299 at Pos(299, 322)
Top most is 173 at Pos(203, 173)
Bottom most is 328 at Pos(288, 328)

(本节完)


版权声明:
youcans@xupt 原创作品,转载必须标注原文链接:(https://blog.csdn.net/youcans/article/details/125112262)
Copyright 2022 youcans, XUPT
Crated:2022-5-28
欢迎关注 『youcans 的 OpenCV 例程 200 篇』 系列,持续更新中
欢迎关注 『youcans 的 OpenCV学习课』 系列,持续更新中
更多内容,请见:
【OpenCV 例程200篇 总目录-202206更新】

194.寻找图像轮廓(cv.findContours)
195.绘制图像轮廓(cv.drawContours)
196.图像的矩和不变矩(cv.moments)
197.轮廓的基本特征
198.基于不变矩的形状相似性检测
199.轮廓的外接边界框
200.轮廓的基本属性

【OpenCV 例程300篇】200.轮廓的基本属性相关推荐

  1. 【youcans的OpenCV例程300篇】总目录

    版权声明: 转载本系列作品时必须标注以下版权内容: [youcans@qq.com, youcans的OpenCV 例程300篇, https://blog.csdn.net/youcans/cate ...

  2. 【OpenCV 例程300篇】214. 绘制椭圆的参数详解

    OpenCV 例程200篇 总目录 [youcans 的 OpenCV 例程300篇]214. 绘制椭圆的参数详解 OpenCV提供了绘图功能,可以在图像上绘制直线.矩形.圆.椭圆等各种几何图形. 7 ...

  3. 【OpenCV 例程 300篇】222. 特征提取之弗里曼链码(Freeman chain code)

    OpenCV 例程200篇 总目录 [youcans 的 OpenCV 例程 300篇]222. 特征提取之弗里曼链码(Freeman chain code) 目标特征的基本概念 通过图像分割获得多个 ...

  4. 【OpenCV 例程300篇】209. HSV 颜色空间的彩色图像分割

    OpenCV 例程200篇 总目录 [youcans 的 OpenCV 例程300篇]209. HSV 颜色空间的彩色图像分割 5.1 HSV 颜色空间的彩色图像分割 HSV 模型是针对用户观感的一种 ...

  5. 【OpenCV 例程300篇】216. 绘制多段线和多边形

    专栏地址:『youcans 的 OpenCV 例程200篇』 文章目录:『youcans 的 OpenCV 例程200篇-总目录』 [youcans 的 OpenCV 例程300篇]216. 绘制多段 ...

  6. 【OpenCV 例程 300篇】237. 基于主成分提取的方向校正(OpenCV)

    『youcans 的 OpenCV 例程200篇 - 总目录』 [youcans 的 OpenCV 例程 300篇]237. 基于主成分提取的方向校正(OpenCV) 主成分分析(Principal ...

  7. 【OpenCV 例程 300篇】226. 区域特征之紧致度/圆度/偏心率

    『youcans 的 OpenCV 例程200篇 - 总目录』 [youcans 的 OpenCV 例程 300篇]226. 区域特征之紧致度/圆度/偏心率 特征通常是针对于图像中的某个目标而言的. ...

  8. 【OpenCV 例程 300篇】221.加密马赛克图像处理与解密复原

    『youcans 的 OpenCV 例程200篇 - 总目录』 [youcans 的 OpenCV 例程 300篇]221.加密马赛克图像处理与解密复原 9. 图像的马赛克处理 马赛克效果是广泛使用的 ...

  9. 【OpenCV 例程 300篇】219. 添加数字水印(盲水印)

    OpenCV 例程200篇 总目录 [youcans 的 OpenCV 例程 300篇]219. 添加数字水印(盲水印) 8.2 添加数字盲水印 数字水印,是指将特征信息嵌入音频.图像或是视频等数字信 ...

最新文章

  1. 聚焦五大领域:浙江大学发布《重大领域交叉前沿方向2021》报告
  2. 分享基于EF6、Unitwork、Autofac的Repository模式设计
  3. SOCKET/串口通信粘包问题处理,附带详细代码
  4. 继续聊WPF——动态数据模板
  5. 初探react,用react实现一个todoList功能
  6. 【Gym - 101775J】Straight Master(差分,思维)
  7. 数十亿次数学运算只消耗几毫瓦电力,谷歌开源Pixel 4背后的视觉模型
  8. linux内核模块和功能,我可以用模块替换Linux内核功能吗?
  9. java保护表格_读密码保护的工作表(版本 - Excel中95,97-2003)的Java
  10. zookeeper 原理
  11. Linux常用命令(补充)--其他
  12. 中国互联网是如何起步的
  13. 如何在EXCEL中练习VBA?
  14. pascal语言基础(一)
  15. Rust_lings
  16. 微信小程序---倒计时
  17. pmp中ram和raci的区别_【PMP考前冲刺】知识点大全(四)
  18. 数据库人大金仓KingbaseES 数据库对象管理工具连接错误(实例创建失败)问题解决办法
  19. 火山小视频服务器维护中,火山小视频整改时间多久 火山小视频整改哪些方面...
  20. linux 使用 mondo rescue 备份 还原系统 iso u盘

热门文章

  1. Android模拟器加速
  2. Android Socket 遇到的Soure Not Find 错误
  3. 统计字符串长度,strlen和sizeof有啥区别?
  4. 3、ssm框架登录验证
  5. SyntaxError: unexpected EOF while parsing解决方法
  6. python百元买鸡问题_用python解决数学题——100块买100只鸡
  7. 用 Python 登录主流网站
  8. 研发源代码防泄密加密软件分析
  9. C++期末考试复习一
  10. 22个奢侈品网站4类风貌