【图像轮廓特征查找】图像处理(OpenCV) -part8

17 图像轮廓特征查找

图像轮廓特征查找其实就是他的外接轮廓。

应用:

图像分割

形状分析

物体检测与识别

根据轮廓点进行,所以要先找到轮廓。

先灰度化、二值化。目标物体白色,非目标物体黑色,选择合适的儿值化方式。

有了轮廓点就可以找到最上、最下、最左、最右的四个坐标,X_{min}、X_{max}、Y_{min}、Y_{max}。就可以绘制出矩形。

17.1 外接矩形

复制代码
boundingRect(轮廓点)

形状的外接矩形有两种,如下图,绿色的叫外接矩形,表示不考虑旋转并且能包含整个轮廓的矩形。其中,外接矩形可根据获得到的轮廓坐标中最上、最下、最左、最右的点的坐标来绘制外接矩形,也就是下图中的绿色矩形。蓝色的是最小外接矩形,会考虑面积。

cv.boundingRect 函数用于计算一组点(通常是轮廓)的最小外接矩形。这个矩形是一个 轴对齐的矩形,也就是说,它的边与图像坐标轴平行。

作用

快速获取一个能够包含目标轮廓的矩形边界。

简单直观地定位目标轮廓的大致区域。

返回参数

x:外接矩形左上角的 x 坐标。

y:外接矩形左上角的 y 坐标。

w:外接矩形的宽度。

h:外接矩形的高度。


python 复制代码
import cv2 as cv
import numpy as np
img = cv.imread('images/ikun4.jpg')
#灰度图
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
#二值化处理,阈值法 因为目标是白色我们需要白色
ret, binary = cv.threshold(gray, 200, 255, cv.THRESH_BINARY_INV)
#查找轮廓
contours, hierarchy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):
    #查找凸包
    hull = cv.convexHull(contours[i])
    #绘制凸包
    cv.polylines(img, [hull], True, (100, 100, 255), 3)
#画出外接矩形
for i in range(len(contours)):
    x, y, w, h = cv.boundingRect(contours[i])
    cv.rectangle(img, (x, y), (x + w, y + h), (255, 255, 0), 2)
cv.imshow('1', img)
# cv.imshow('2', binary)
cv.waitKey(0)
cv.destroyAllWindows()

获取方式

在代码中,通过循环遍历查找到的轮廓 contours,对每个轮廓调用 cv.boundingRect 函数来获取其外接矩形的位置和大小参数,包括左上角顶点坐标(x,y)、宽度 w 和高度 h。

绘制目的

使用 cv.rectangle 函数在原图上绘制出这些外接矩形,通过矩形的边界将目标轮廓大致框选出来,便于更直观地观察和分析目标在图像中的分布情况,以及与其他图像元素的相对位置关系。

17.2 最小外接矩形

定义与原理

最小外接矩形 是能够完全包含目标轮廓的最小面积的矩形,它允许矩形相对于图像坐标轴旋转,因此可以更好地贴合轮廓的形状,相比普通外接矩形(轴对齐的外接矩形),它可以更精确地描述轮廓的形状和方向。

其基本原理是通过计算轮廓点集的最小面积矩形,这个矩形的边不一定与图像坐标轴对齐。它需要找到一组四个点,使得这四个点构成的矩形能够包含所有轮廓点,并且面积是所有可能的包含该轮廓的矩形中最小的。

计算方法

从轮廓点集出发,利用几何算法来确定最小外接矩形的边界。

一种常见的方法是基于旋转卡壳(Rotating Calipers)算法,它通过旋转两条平行的切线来寻找能够包含整个点集的最小矩形。具体步骤为:首先找到点集的凸包;然后在凸包上选择两个点作为初始两个的顶点,这两点确定一条边;接着,寻找与该边相对的另一条边,使得这两条边之间的距离最大,从而形成一个初始的矩形;最后,逐步旋转这两条边,找到使矩形面积最小的那一对边,从而确定最小外接矩形。

在 OpenCV 中,可以通过 cv.minAreaRect 函数获取轮廓的最小外接矩形,该函数返回一个包含中心坐标、长宽以及旋转角度的元组,利用这些参数可以绘制出最小外接矩形。

需要使用到的API说明:

contours, hierarchy = cv2.findContours(image_np_thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

contours为二值图像上查找所有的外部轮廓

rect = cv2.minAreaRect(cnt)

传入的cnt参数为contours中的轮廓,可以遍历contours中的所有轮廓,然后计算出每个轮廓的小面积外接矩形

rect 是计算轮廓最小面积外接矩形:rect 结构通常包含中心点坐标 (x, y)、宽度 width、高度 height 和旋转角度 angle

cv2.boxPoints(rect).astype(int)

cv2.boxPoints(rect)返回 是一个形状为 4行2列的数组,每一行代表一个点的坐标(x, y),顺序按照逆时针或顺时针方向排列

将最小外接矩形转换为边界框的四个角点,并转换为整数坐标

cv2.drawContours(image, contours, contourIdx, color, thickness)

image:原图像,一般为 numpy 数组,通常为灰度或彩色图像。

contours:一个包含多个轮廓的列表,可以用上一个api得到的 [box]

contourIdx :要绘制的轮廓索引。如果设置为 -1,则绘制所有轮廓。

color :轮廓的颜色,可以是 BGR 颜色格式的三元组,例如 (0, 0, 255) 表示红色。

thickness:轮廓线的粗细,如果是正数,则绘制实线;如果是 0,则绘制轮廓点;如果是负数,则填充轮廓内部区域。


python 复制代码
#最小外接矩形 旋转卡壳法
#读取图像
img = cv.imread('images/feiwu.png')
gary = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
#二值化
ret, binary = cv.threshold(gary, 200, 255, cv.THRESH_BINARY_INV)
#查找轮廓
contours, hierarchy = cv.findContours(binary, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):
    #最小外接矩形 rect = (center(x,y), (width, height), angle)
    rect = cv.minAreaRect(contours[i])
    box = cv.boxPoints(rect).astype(np.int32)
    cv.drawContours(img, [box], -1, (0, 0, 255), 2,cv.LINE_AA)
#画出外接矩形
for i in range(len(contours)):
    x, y, w, h = cv.boundingRect(contours[i])
    cv.rectangle(img, (x, y), (x + w, y + h), (0, 0, 0), 2)
cv.imshow("1", img)
cv.waitKey(0)
cv.destroyAllWindows()

绘制外接矩形和最小外接矩形是有区别的

17.3 最小外接圆

寻找最小外接圆使用的算法是Welzl算法。Welzl算法基于一个定理:希尔伯特圆定理表明,对于平面上的任意三个不在同一直线上的点,存在一个唯一的圆同时通过这三个点,且该圆是最小面积的圆(即包含这三个点的圆中半径最小的圆,也称为最小覆盖圆)。

进一步推广到任意 n 个不在同一圆上的点,总存在一个唯一的最小覆盖圆包含这 n 个点。

若已经存在平面上互不共线(或共圆)的 n 个点,并确定了它们的最小覆盖圆,那么添加第 n+1 个点,并且要求这个点不在原来的最小覆盖圆内(即在圆外),为了使新的包含 n+1 个点的最小覆盖圆的半径增大,新加入的点必须位于由原 n 个点确定的最小覆盖圆的边界上(即圆周上)。这是因为,如果新点在原最小覆盖圆的内部,显然不会影响最小覆盖圆;如果新点在原最小覆盖圆之外但不在圆周上,那么通过新点和至少两个原有圆上的点可以构造出一个更大的圆,这个圆必然比原最小覆盖圆更大,因此不是包含所有 n+1 个点的最小覆盖圆。所以,按照这一逻辑,当第 n+1 个点在原 n 个点的最小覆盖圆外时,确实这个点会位于包含所有 n+1 个点的新最小覆盖圆的圆周上。

有了这个定理,就可以先取3个点建立一个圆(不共线的三个点即可确定一个圆,如果共线就取距离最远的两个点作为直径建立圆),然后遍历剩下的所有点,对于遍历到的点P来说:

如果该点在圆内,那么最小覆盖圆不变。

如果该点在圆外,根据上述定理,该点一定在想要求得的最小覆盖圆的圆周上,又因为三个点才能确定一个圆,所以需要枚举P点之前的点来找其余的两个点。当找到与P点组成的圆能够将所有点都包含在圆内或圆上,该圆就是这些点的最小外接圆。

在OpenCV中,可以直接使用cv2.minEnclosingCircle() 来获取最小外接圆,该函数只需要输入一个参数,就是要绘制最小外接圆的点集的坐标,然后会返回最小外接圆的圆心坐标与半径。通过该函数返回的内容信息即可绘制某点集的最小外接圆。如下图所示:

需要使用的API说明

cv2.minEnclosingCircle(points) -> (center, radius)

参数说明:

points:输入参数图片轮廓数据

返回值:

center:一个包含圆心坐标的二元组 (x, y)

radius:浮点数类型,表示计算得到的最小覆盖圆的半径。

cv2.circle(img, center, radius, color, thickness)

img:输入图像,通常是一个numpy数组,代表要绘制圆形的图像。

center:一个二元组 (x, y),表示圆心的坐标位置。

radius:整型或浮点型数值,表示圆的半径长度。

color:颜色标识,可以是BGR格式的三元组 (B, G, R),例如 (255, 0, 0) 表示红色。

thickness:整数,表示圆边框的宽度。如果设置为 -1,则会填充整个圆。

复制代码
python 复制代码
img = cv.imread('images/haimbb.jpg')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, binary = cv.threshold(gray, 100, 255, cv.THRESH_BINARY_INV)
#查找轮廓
contours, hierarchy = cv.findContours(binary, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
for i in range(len(contours)):
    #绘制外接圆
    (x, y), radius = cv.minEnclosingCircle(contours[i])
    center = (int(x), int(y))
    radius = int(radius)
    cv.circle(img, center, radius, (128, 128, 128), 2)
    #绘制外接矩形
    rect = cv.minAreaRect(contours[i])
    box = cv.boxPoints(rect)
cv.imshow("1", img)
cv.imshow("2", binary)
cv.waitKey(0)
cv.destroyAllWindows()

18 直方图均衡化

相关推荐
石榴花专场2 分钟前
分类算法中one-vs-rest策略和one-vs-one 策略的区别是什么?
人工智能·python·机器学习·数据挖掘
youcans_4 分钟前
【医学影像 AI】早产儿视网膜病变国际分类(第三版)
论文阅读·人工智能·计算机视觉·医学影像·rop
神经星星7 分钟前
多主体驱动生成能力达SOTA,字节UNO模型可处理多种图像生成任务
人工智能·开源·强化学习
hello_ejb310 分钟前
聊聊Spring AI Alibaba的FeiShuDocumentReader
人工智能·python·spring
何双新11 分钟前
企业AI应用模式解析:从本地部署到混合架构
人工智能·架构
深度学习lover11 分钟前
<数据集>小船识别数据集<目标检测>
人工智能·python·yolo·目标检测·计算机视觉·船舶识别
带娃的IT创业者13 分钟前
《AI大模型应知应会100篇》第30篇:大模型进行数据分析的方法与局限:从实战到边界探索
人工智能·数据挖掘·数据分析
白熊18818 分钟前
【计算机视觉】CV实战项目- CMU目标检测与跟踪系统 Object Detection & Tracking for Surveillance Video
人工智能·目标检测·计算机视觉
向上的车轮29 分钟前
云原生与AI的关系是怎么样的?
人工智能·云原生
Blossom.11832 分钟前
量子计算在金融领域的应用与展望
数据库·人工智能·分布式·金融·架构·量子计算·ai集成