当前位置: 首页 > news >正文

Python----计算机视觉处理(Opencv:图像轮廓特征查找:外接轮廓)

一、轮廓特征应用

1. 图像分割

2. 形状分析

3. 物体检测与识别

二、外接轮廓

2.1、外界矩形

        如上图所示,红色方框为外接矩形,表示不考虑旋转并且能包含整个轮廓的矩形。其中,外接矩形可根据获得到的轮廓坐标中最上、最下、最左、最右的点的坐标来绘制外接矩形。

2.2、最小外接矩形

        旋转卡壳法

        旋转卡壳法有一个很重要的前提条件:对于多边形P的一个外接矩形存在一条边与原多边形的边共线。

        根据前提条件,上面的凸多边形的最小外接矩形与凸多边形的某条边是共线的。因此我们只需要以其中 的一条边为起始边,然后按照逆时针方向计算每个凸包点与起始边的距离,并将距离最大的点记录下 来。 

        如上图所示,我们首先以a、b两点为起始边,并计算出e点离起始边最远,那么e到起始边的距离就是一 个矩形的高度,因此我们只需要再找出矩形的宽度即可。对于矩形的最右边,以向量\vec{ab} 为基准,然后分 别计算凸包点在向量\vec{ab}上的投影的长度,投影最长的凸包点所在的垂直于起始边的直线就是矩形最右边 所在的直线。 

        如上图所示,c点就是在向量 上投影最长的凸包点,那么通过c点垂直于直线ab的直线就是矩形的右边 界所在的直线。矩形的左边界的也是这么计算的,不同的是使用的向量不是\vec{ab}而是\vec{ba}

        如上图所示,h点垂直于ab的直线就是以ab为起始边所计算出来的矩形所在的左边界所在的直线。其中 矩形的高就是e点到直线ab的距离,矩形的宽是h点在向量上\vec{ba} 的投影加上c点在向量\vec{ab}上的投影减去ab 的长度,即: 

        于是我们就有了以ab为起始边所构成的外接矩形的宽和高,这样就可以得到该矩形的面积。然后再以bc 为起始边,并计算其外接矩形的面积。也就是说凸多边形有几个边,就要构建几次外接矩形,然后找到 其中面积最小的矩形作为该凸多边形的最小外接矩形。 在OpenCV中,可以直接使用cv2.minAreaRect()来获取最小外接矩形,该函数只需要输入一个参数,就 是凸包点的坐标,然后会返回最小外接矩形的中心点坐标、宽高以及旋转角度。通过返回的内容信息, 即可绘制凸多边形的的最小外接矩形。 

2.3、最小外接圆

        寻找最小外接圆使用的算法是Welzl算法。Welzl算法基于一个定理:对于平面上任意n个点,在其最小覆 盖圆外取第n+1个点,那么第n+1个点一定在这n+1个点的最小覆盖圆的圆周上。

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

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

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

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

contour_type:外接轮廓的类别:

        boundingRect:外接矩形,

        minAreaRect:最小外接矩形,

        minEnclosingCircle:最小外接圆。

color:绘制外接轮廓的颜色。 thickness:绘制外接轮廓的线宽。

三、图像轮廓特征查找

3.1、外接矩形

导入模块 

import cv2
import numpy as np

输入图像 

img = cv2.imread('img_.png')

灰度化 

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

二值化 

ret, img_threshold = cv2.threshold(img_gray, 127, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)

 寻找轮廓

contours, hierarch = cv2.findContours(img_threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

 绘制轮廓

cv2.drawContours(img, contours, -1, (0, 0, 255), thickness=2)

绘制外接轮廓 

for i in contours:
    x,y,w,h=cv2.boundingRect(i)
    top_left=(x,y)
    botton_right=(x+w,y+h)
    cv2.rectangle(img,top_left,botton_right,color=(0,0,255),thickness=2)

 输出图像

cv2.imshow('img', img)
cv2.waitKey(0)

 完整代码

import cv2  
import numpy as np  

# 读取图像文件 'img_.png'  
img = cv2.imread('img_.png')  

# 将彩色图像转换为灰度图像  
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  

# 使用 Otsu 方法对灰度图像进行阈值处理,生成二值图像  
# cv2.threshold() 的参数:  
# 1. 输入图像 (img_gray)  
# 2. 阈值 (127): 用于二值化的固定阈值,Otsu 方法会自动选择  
# 3. 最大值 (255): 二值化后像素的最大值  
# 4. 阈值类型 (cv2.THRESH_OTSU + cv2.THRESH_BINARY): 使用 Otsu 方法进行自适应阈值处理  
ret, img_threshold = cv2.threshold(img_gray, 127, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)  

# 查找轮廓  
# cv2.findContours() 的参数:  
# 1. 输入图像 (img_threshold)  
# 2. 轮廓检索模式 (cv2.RETR_TREE): 检索所有轮廓并重建一个完整的层次结构  
# 3. 轮廓近似方法 (cv2.CHAIN_APPROX_SIMPLE): 仅保留轮廓的端点信息  
contours, hierarch = cv2.findContours(img_threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  

# 在原图像上绘制所有轮廓  
# cv2.drawContours() 的参数:  
# 1. 图像 (img): 要绘制轮廓的图像  
# 2. 轮廓 (contours): 要绘制的轮廓列表  
# 3. -1: 表示绘制所有轮廓  
# 4. 颜色 (0, 0, 255): 红色(BGR格式)  
# 5. 厚度 (2): 绘制轮廓的线条厚度  
cv2.drawContours(img, contours, -1, (0, 0, 255), thickness=2)  

# 遍历每个轮廓,计算其外接矩形并绘制  
for i in contours:  
    # 获取轮廓的外接矩形,返回值为 (x, y, w, h)  
    x, y, w, h = cv2.boundingRect(i)  
    # 计算矩形的左上角和右下角坐标  
    top_left = (x, y)           # 左上角坐标  
    bottom_right = (x + w, y + h)  # 右下角坐标  
    # 在图像上绘制外接矩形  
    cv2.rectangle(img, top_left, bottom_right, color=(0, 0, 255), thickness=2)  

# 显示处理后的图像  
cv2.imshow('img', img)  

# 等待用户按键后关闭窗口  
cv2.waitKey(0)  

3.2、最小外接矩形

 

导入模块 

import cv2
import numpy as np

输入图像 

img = cv2.imread('img_.png')

灰度化 

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

二值化 

ret, img_threshold = cv2.threshold(img_gray, 127, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)

 寻找轮廓

contours, hierarch = cv2.findContours(img_threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

 绘制轮廓

cv2.drawContours(img, contours, -1, (0, 0, 255), thickness=2)

绘制外接轮廓 

for i in contours:
    rect=cv2.minAreaRect(i)
    box=np.int32(cv2.boxPoints(rect))
    cv2.drawContours(img, [box], -1, (0, 255, 0), thickness=2)

 输出图像

cv2.imshow('img', img)
cv2.waitKey(0)

 完整代码

import cv2  
import numpy as np  

# 读取图像文件 'img_.png'  
img = cv2.imread('img_.png')  

# 将彩色图像转换为灰度图像  
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  

# 使用 Otsu 方法对灰度图像进行阈值处理,生成二值图像  
# cv2.threshold() 的参数:  
# 1. 输入图像 (img_gray)  
# 2. 阈值 (127): 用于二值化的固定阈值,Otsu 方法会自动选择  
# 3. 最大值 (255): 二值化后像素的最大值  
# 4. 阈值类型 (cv2.THRESH_OTSU + cv2.THRESH_BINARY): 使用 Otsu 方法进行自适应阈值处理  
ret, img_threshold = cv2.threshold(img_gray, 127, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)  

# 查找轮廓  
# cv2.findContours() 的参数:  
# 1. 输入图像 (img_threshold)  
# 2. 轮廓检索模式 (cv2.RETR_TREE): 检索所有轮廓并重建一个完整的层次结构  
# 3. 轮廓近似方法 (cv2.CHAIN_APPROX_SIMPLE): 仅保留轮廓的端点信息  
contours, hierarch = cv2.findContours(img_threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  

# 在原图像上绘制所有轮廓  
# cv2.drawContours() 的参数:  
# 1. 图像 (img): 要绘制轮廓的图像  
# 2. 轮廓 (contours): 要绘制的轮廓列表  
# 3. -1: 表示绘制所有轮廓  
# 4. 颜色 (0, 0, 255): 红色(BGR格式)  
# 5. 厚度 (2): 绘制轮廓的线条厚度  
cv2.drawContours(img, contours, -1, (0, 0, 255), thickness=2)  

# 遍历每个轮廓,计算其最小外接矩形并绘制  
for i in contours:  
    # 获取轮廓的最小外接矩形  
    rect = cv2.minAreaRect(i)  
    # 将矩形的四个角点获取为整数类型  
    box = np.int32(cv2.boxPoints(rect))  # box_points 返回的四个点是浮点数,需转为整数  

    # 在原图像上绘制最小外接矩形  
    cv2.drawContours(img, [box], -1, (0, 255, 0), thickness=2)  # 使用绿色来绘制矩形  

# 显示处理后的图像  
cv2.imshow('img', img)  

# 等待用户按键后关闭窗口  
cv2.waitKey(0)  

3.3、最小外接圆

 

导入模块 

import cv2
import numpy as np

输入图像 

img = cv2.imread('img_.png')

灰度化 

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

二值化 

ret, img_threshold = cv2.threshold(img_gray, 127, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)

 寻找轮廓

contours, hierarch = cv2.findContours(img_threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

 绘制轮廓

cv2.drawContours(img, contours, -1, (0, 0, 255), thickness=2)

绘制外接轮廓 

for i in contours:
    (x,y),radius=cv2.minEnclosingCircle(i)
    (x,y,radius)=np.int32((x,y,radius))

    cv2.circle(img,(x,y),radius,(255,0,0),thickness=2)

 输出图像

cv2.imshow('img', img)
cv2.waitKey(0)

 完整代码

import cv2  
import numpy as np  

# 读取图像文件 'img_.png'  
img = cv2.imread('img_.png')  

# 将彩色图像转换为灰度图像  
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  

# 使用 Otsu 方法对灰度图像进行阈值处理,生成二值图像  
# cv2.threshold() 的参数:  
# 1. 输入图像 (img_gray)  
# 2. 阈值 (127): 用于二值化的固定阈值,Otsu 方法会自动选择  
# 3. 最大值 (255): 二值化后像素的最大值  
# 4. 阈值类型 (cv2.THRESH_OTSU + cv2.THRESH_BINARY): 使用 Otsu 方法进行自适应阈值处理  
ret, img_threshold = cv2.threshold(img_gray, 127, 255, cv2.THRESH_OTSU + cv2.THRESH_BINARY)  

# 查找轮廓  
# cv2.findContours() 的参数:  
# 1. 输入图像 (img_threshold)  
# 2. 轮廓检索模式 (cv2.RETR_TREE): 检索所有轮廓并重建一个完整的层次结构  
# 3. 轮廓近似方法 (cv2.CHAIN_APPROX_SIMPLE): 仅保留轮廓的端点信息  
contours, hierarch = cv2.findContours(img_threshold, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)  

# 在原图像上绘制所有轮廓  
# cv2.drawContours() 的参数:  
# 1. 图像 (img): 要绘制轮廓的图像  
# 2. 轮廓 (contours): 要绘制的轮廓列表  
# 3. -1: 表示绘制所有轮廓  
# 4. 颜色 (0, 0, 255): 红色(BGR格式)  
# 5. 厚度 (2): 绘制轮廓的线条厚度  
cv2.drawContours(img, contours, -1, (0, 0, 255), thickness=2)  

# 遍历每个轮廓,计算其最小外接圆并绘制  
for i in contours:  
    # 计算轮廓的最小外接圆  
    (x, y), radius = cv2.minEnclosingCircle(i)  
    # 将圆心坐标和半径转换为整数  
    (x, y, radius) = np.int32((x, y, radius))  

    # 在原图像上绘制最小外接圆  
    cv2.circle(img, (x, y), radius, (255, 0, 0), thickness=2)  # 使用蓝色来绘制圆  

# 显示处理后的图像  
cv2.imshow('img', img)  

# 等待用户按键后关闭窗口  
cv2.waitKey(0)  

四、库函数

4.1、findContours()

cv.findContours(	image, mode, method[, contours[, hierarchy[, offset]]]	) ->	contours, hierarchy
方法描述
image源,一个 8 位单通道图像。非零像素被视为 1。零像素仍为 0,因此图像被视为 binary 。您可以使用 compare、inRange、threshold、adaptiveThreshold、Canny 等创建灰度或彩色图像的二进制图像。如果 mode 等于 RETR_CCOMP 或 RETR_FLOODFILL,则输入也可以是标签的 32 位整数图像 (CV_32SC1)。
contours检测到的轮廓。每个轮廓都存储为点向量(例如 std::vector<std::vector<cv::P oint> >)。
hierarchy可选的输出向量(例如 std::vector<cv::Vec4i>),包含有关图像拓扑的信息。它的单元数与等值线的数量一样多。对于每个第 i 个轮廓轮廓[i],元素 hierarchy[i][0] 、hierarchy[i][1] 、hierarchy[i][2] 和 hierarchy[i][3] 在同一层次结构级别的下一个和上一个轮廓的轮廓中分别设置为从 0 开始的索引,即第一个子轮廓和父轮廓。如果轮廓 i 没有 next、previous 、parent 或 nested 等值线,则 hierarchy[i] 的相应元素将为负数。
mode等值线检索模式,参见 RetrievalModes
method等值线近似方法,请参阅 ContourApproximationModes
offset每个等值线点移动的可选偏移量。如果轮廓是从图像 ROI 中提取的,然后应该在整个图像上下文中对其进行分析,这将非常有用。
RETR_EXTERNAL

Python:cv.RETR_EXTERNAL

仅检索极端外轮廓。它为所有轮廓设置。hierarchy[i][2]=hierarchy[i][3]=-1

RETR_LIST

Python:cv.RETR_LIST

检索所有等值线,而不建立任何分层关系。

RETR_CCOMP

Python:cv.RETR_CCOMP

检索所有等值线并将它们组织到一个两级层次结构中。在顶层,有组件的外部边界。在第二层,有孔的边界。如果已连接零部件的孔内有其他轮廓,则仍将其置于顶层。

RETR_TREE

Python:cv.RETR_TREE

检索所有等值线并重新构建嵌套等值线的完整层次结构。

RETR_FLOODFILL

Python:cv.RETR_FLOODFILL

CHAIN_APPROX_NONE

Python:cv.CHAIN_APPROX_NONE

绝对存储所有等高线点。也就是说,等值线的任意 2 个后续点 (x1,y1) 和 (x2,y2) 将是水平、垂直或对角线相邻点,即 max(abs(x1-x2),abs(y2-y1))==1。

CHAIN_APPROX_SIMPLE

Python:cv.CHAIN_APPROX_SIMPLE

压缩水平、垂直和对角线段,仅保留其端点。例如,一个直立的矩形轮廓用 4 个点编码。

CHAIN_APPROX_TC89_L1

Python:cv.CHAIN_APPROX_TC89_L1

应用了 Teh-Chin 链近似算法的一种风格 [266]

CHAIN_APPROX_TC89_KCOS

Python:cv.CHAIN_APPROX_TC89_KCOS

应用了 Teh-Chin 链近似算法的一种风格 [266]

4.2、drawContours()

cv.drawContours(	image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]	) ->	image
方法描述
image目标图像。
contours所有输入等值线。每个等值线都存储为点向量。
contourIdx指示要绘制的轮廓的参数。如果为负数,则绘制所有等值线。
color等值线的颜色。
thickness绘制等高线时使用的线条粗细。如果为负数(例如, thickness=FILLED ),则绘制等值线内部
lineType线路连接。请参阅线型
hierarchy有关层次结构的可选信息。仅当您只想绘制部分等值线时才需要它(请参阅 maxLevel )。
maxLevel绘制轮廓的最大级别。如果为 0,则仅绘制指定的轮廓。如果为 1,则函数绘制 contour 和所有嵌套 contour。如果为 2,则函数绘制等值线、所有嵌套等值线、所有嵌套到嵌套的等值线,依此类推。仅当有可用的层次结构时,才会考虑此参数。
offset可选的轮廓偏移参数。将所有绘制的轮廓移动指定

注意

当 thickness=FILLED 时,该函数旨在正确处理具有孔的连通零部件,即使未提供层次结构数据也是如此。这是通过使用奇偶规则一起分析所有轮廓来完成的。如果您有单独检索的轮廓的联合集合,这可能会产生不正确的结果。为了解决这个问题,你需要为每个 contour 的子组单独调用 drawContours,或者使用 contourIdx 参数迭代集合。

4.3、boundingRect()

计算点集的右上边界矩形或灰度图像的非零像素。

该函数计算并返回指定点集或灰度图像的非零像素的最小右上边界矩形。

cv.boundingRect(	array	) ->	retval
函数描述
array 输入灰度图像或 2D 点集,存储在 std::vector 或 Mat 中。

4.4、rectangle()

cv.rectangle(	img, pt1, pt2, color[, thickness[, lineType[, shift]]]	) ->	img
cv.rectangle(	img, rec, color[, thickness[, lineType[, shift]]]	) ->	img
函数描述
img图像。
pt1矩形的顶点。
pt2与 pt1 相对的矩形的顶点。
color矩形颜色或亮度(灰度图像)。
thickness

构成矩形的线条的粗细。负值(如 FILLED)表示函数必须绘制填充矩形

-1表示实心

1,2,...表示线的粗细

lineType线路的类型。
shift点坐标中的小数位数。

4.5、minAreaRect()

查找包含输入 2D 点集的最小区域的旋转矩形。

该函数计算并返回指定点集的最小面积边界矩形(可能已旋转)。开发人员应记住,当数据接近包含的 Mat 元素边界时,返回的 RotatedRect 可以包含负索引。

cv.minAreaRect(	points	) ->	retval
函数描述
points点的输入向量,存储在 std::vector 或 Mat <> 中

4.6、boxPoints()

查找旋转矩形的四个顶点。用于绘制旋转的矩形。

该函数查找旋转矩形的四个顶点。此函数可用于绘制矩形。

cv.boxPoints(	box[, points]	) ->	points
函数描述
box输入旋转矩形。它可能是 minAreaRect 的输出。
points矩形的四个顶点的输出数组。

4.7、minEnclosingCircle()

查找包含 2D 点集的最小面积的圆。

该函数使用迭代算法找到 2D 点集的最小封闭圆。

cv.minEnclosingCircle(	points	) ->	center, radius
函数描述
points2D 点的输入向量,存储在 std::vector 或 Mat <> 中
center圆的输出中心。
radius圆的输出半径。

4.8、circle()

绘制一个圆。

函数 cv::circle 绘制一个具有给定圆心和半径的简单圆或实心圆。

cv.circle(	img, center, radius, color[, thickness[, lineType[, shift]]]	) ->	img
函数描述
img绘制圆的图像。
center圆心。
radius圆的半径。
color圆形颜色。
thickness圆轮廓的粗细(如果为正)。负值(如 FILLED)表示要绘制实心圆。
lineType圆边界的类型。请参阅线型
shiftcenter 坐标和 radius 值中的小数位数。

相关文章:

  • 华为HCIE方向那么多应该如何选择?
  • Linux的SPI子系统的原理和结构详解【SPI控制器(spi_master)、SPI总线(device-driver-match匹配机制)、SPI设备、SPI万能驱动`spidev.c`】
  • 前端性能优化方案总结
  • ARCGIS PRO SDK 创建右键菜单
  • 基于腾讯云HAI-CPU部署DeepSeek:搭建图书馆知识库,赋能智慧图书馆建设
  • 从技术架构和生态考虑,不是单纯的配置优化,还有哪些方式可以提高spark的计算性能
  • TCP 三次握手与四次挥手过程
  • Nordic Semiconductor 芯片(如 nRF52/nRF53 系列)的 VSCode 开发环境的步骤
  • 大型语言模型(LLM)推理框架的全面分析与选型指南(2025年版)
  • LLM之RAG实战(五十二)| 如何使用混合搜索优化RAG 检索
  • 鸿蒙进行视频上传,使用 request.uploadFile方法
  • 深入理解C#中的享元模式(Flyweight Pattern)
  • 感应电机反电动势频率与电源频率相等以及转差率的测量机制
  • 26考研——图_图的遍历(6)
  • 【C++】vector的push_back和emplace_back
  • 电动自行车/电动工具锂电池PCM方案--SH367003、SH367004、SH79F329
  • C# SerialPort 类中 Handshake 属性的作用
  • 基于springboot人脸识别的社区流调系统(源码+lw+部署文档+讲解),源码可白嫖!
  • 如何解决用户名文件夹是中文导致的识别不到路径,获取不到ssh密匙
  • 淘宝历史价格数据获取指南:API 与爬虫方案的合法性与效率对比
  • 澎湃回声丨23岁小伙“被精神病8年”续:今日将被移出“重精”管理系统
  • 这就是上海!
  • “75后”袁达已任国家发改委秘书长
  • 西夏文残碑等文物来沪,见证一段神秘灿烂的历史
  • 西藏阿里地区日土县连发两次地震,分别为4.8级和3.8级
  • 4月人文社科联合书单|天文学家的椅子