1图像轮廓概念:
图像轮廓是指图像中连续的像素边界,这些边界通常代表了图像中的物体或者物体的边缘。在数字图像处理中,轮廓是由相同像素值组成的曲线,它们连接相同的颜色或灰度值,并且具有连续性。轮廓可以用来描述和分析图像中的形状和结构,是许多计算机视觉任务的基础,如目标检测、形状识别、图像分割等
任务2 查找与绘制图像轮廓
2.1查找图像轮廓
在 OpenCV 中,查找图像轮廓的函数是 `cv2.findContours()`,其语法如下:
contours, hierarchy = cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
各参数的意义如下:
- - image:输入的二值图像,通常是经过阈值化或边缘检测后的图像。
- - mode:轮廓检索模式,指定轮廓的检索方式。常用的模式包括:
- - cv2.RETR_EXTERNAL:仅检测外部轮廓。
- - cv2.RETR_LIST:检测所有轮廓,不建立轮廓间的层级关系。
- - cv2.RETR_CCOMP:检测所有轮廓,建立两级轮廓结构。
- - cv2.RETR_TREE:检测所有轮廓,建立完整的轮廓层级结构。
- - `method`:轮廓逼近方法,指定轮廓的逼近方式。常用的方法包括:
- - `cv2.CHAIN_APPROX_NONE`:保存所有的轮廓点。
- - `cv2.CHAIN_APPROX_SIMPLE`:压缩水平、垂直和对角方向的像素,只保留端点。
- - `cv2.CHAIN_APPROX_TC89_L1`:使用 Teh-Chin 链逼近算法之一。
- - `cv2.CHAIN_APPROX_TC89_KCOS`:使用 Teh-Chin 链逼近算法之二。
函数返回两个值:
- contours:检测到的轮廓,每个轮廓是一个点集的列表。
- hierarchy:可选输出的层级信息,用于描述轮廓之间的层级关系。
2.2绘制图像轮廓
在 OpenCV 中,绘制图像轮廓的函数是 `cv2.drawContours()`,其语法如下:
`
image = cv2.drawContours(image, contours, contourIdx, color, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]])
其中各参数的意义如下:
- - `image`:要绘制轮廓的输入图像。
- - `contours`:要绘制的轮廓列表,通常是通过 `cv2.findContours()` 函数得到的轮廓。
- - `contourIdx`:要绘制的轮廓的索引,如果为负数,则绘制所有轮廓。
- - `color`:轮廓的颜色,可以是一个单通道的灰度值(0-255),或者是一个包含三个通道的颜色值 (B, G, R)。
- - `thickness`:轮廓的线条粗细,如果为负数或 `cv2.FILLED`,则填充轮廓内部。
- - `lineType`:轮廓线条的类型,可选参数,默认为 `cv2.LINE_8`。
- - `hierarchy`:可选参数,用于描述轮廓之间的层级关系。
- - `maxLevel`:可选参数,绘制轮廓的最大层级。
- - `offset`:可选参数,指定轮廓偏移量。
任务演练-实现图像轮廓的绘制与查找
代码1 绘制图像外轮廓:
#8.1
import cv2
import numpy as np
img= cv2.imread("C:/Users/win11/opencv/sucai8/shape.jpg")
cv2.imshow("img",img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary=cv2.threshold(gray,180,255,0)
contours,hierarchy=cv2.findContours(binary,cv2.RETR_EXTERNAL,\
cv2.CHAIN_APPROX_NONE)
dst=cv2.drawContours(img,contours,-1,(0,255,255),thickness=5)
cv2.imshow("contours",dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:可以看出实现的图在原图上多了一层黄色的外轮廓
代码2绘制图像的全部轮廓
#8-2
import cv2
import numpy as np
img= cv2.imread("C:/Users/win11/opencv/sucai8/shape.jpg")
cv2.imshow("img",img)
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary=cv2.threshold(gray,180,255,0)
contours,hierarchy=cv2.findContours(binary,cv2.RETR_TREE,\
cv2.CHAIN_APPROX_NONE)
dst=cv2.drawContours(img,contours,-1,(0,255,255),thickness=5)
cv2.imshow("binary",binary)
cv2.imshow("contours",dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:所有的图像外面都有一层轮廓
任务3:计算轮廓长度与面积
在OpenCV中,你可以使用`cv2.arcLength()`函数计算轮廓的长度,以及使用`cv2.contourArea()`函数计算轮廓的面积。这两个函数的语法如下:
length = cv2.arcLength(curve, closed)
area = cv2.contourArea(contour)
其中各参数的意义如下:
- - `curve`:要计算长度的曲线,通常是轮廓中的点集。
- - `closed`:布尔值,指示曲线是否封闭。对于轮廓来说,通常是True,表示闭合曲线。
- - `contour`:要计算面积的轮廓。
任务演练:使用cv2.arcLength()函数计算轮廓长度,返回单位为像素点个数
代码:
import cv2
img= cv2.imread("C:/Users/win11/opencv/sucai8/shape.jpg")
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary=cv2.threshold(gray,220,255,cv2.THRESH_BINARY)
contours,hierarchy=cv2.findContours(binary,cv2.RETR_TREE,\
cv2.CHAIN_APPROX_NONE)
n=len(contours)
contoursImg=[]
for i in range(n):
length=cv2.arcLength(contours[i],True)
print(f"轮廓{i+1}的长度:\n{length}")
结果如图:
2使用cv2.contoursArea()函数计算轮廓面积 ,返回单位为像素点个数
代码:
import cv2
img= cv2.imread("C:/Users/win11/opencv/sucai8/shape.jpg")
gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,binary=cv2.threshold(gray,220,255,cv2.THRESH_BINARY)
contours,hierarchy=cv2.findContours(binary,cv2.RETR_TREE,\
cv2.CHAIN_APPROX_NONE)
n=len(contours)
contoursImg=[]
for i in range(n):
area=cv2.contourArea(contours[i])
print(f"轮廓{i}的面积:\n{area}")
任务3:实现形状匹配
在 OpenCV 中,你可以使用 `cv2.matchShapes()` 函数来实现形状匹配。这个函数可以用来比较两个形状或轮廓的相似度。它的语法如下:
match_value = cv2.matchShapes(contour1, contour2, method, parameter)
其中各参数的意义如下:
- - `contour1`:第一个输入的轮廓。
- - `contour2`:第二个输入的轮廓。
- - `method`:形状匹配的方法,是一个比较轮廓相似度的度量标准。常用的方法包括:
- - `cv2.CONTOURS_MATCH_I1`:Hu 矩的相关性,具有较高的鲁棒性。
- - `cv2.CONTOURS_MATCH_I2`:Hu 矩的其他相关性度量。
- - `cv2.CONTOURS_MATCH_I3`:基于物理距离的相似性度量。
- - `parameter`:方法参数,通常为0。
函数返回形状匹配的数值,值越小表示两个形状越相似。
任务演练——形状匹配
代码:
import cv2
o1 = cv2.imread("C:/Users/win11/opencv/sucai8/m1.png")
o2 = cv2.imread("C:/Users/win11/opencv/sucai8/m2.png")
gray1 = cv2.cvtColor(o1, cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(o2, cv2.COLOR_BGR2GRAY)
ret, binary1 = cv2.threshold(gray1, 127, 255, cv2.THRESH_BINARY)
ret, binary2 = cv2.threshold(gray2, 127, 255, cv2.THRESH_BINARY)
contours1, hierarchy = cv2.findContours(binary1, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
contours2, hierarchy = cv2.findContours(binary2, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cent1 = contours1[0]
cent2 = contours2[0]
ret0 = cv2.matchShapes(cent1, cent1, 1, 0.0)
ret1 = cv2.matchShapes(cent1, cent2, 1, 0.0)
print("相同图像的matchShape=", ret0)
print("相似图像的matchShape=", ret1)
m1和m2的图像如下:
结果如下:
相同图像的matchShape= 0.0
相似图像的matchShape= 0.28749410662718267
任务4轮廓的几何形状拟合
4.1
在 OpenCV 中,你可以使用 cv2.boundingRect()
函数来获取轮廓的矩形包围框。这个函数可以用来获取包围轮廓的最小矩形,即矩形包围框的左上角坐标以及宽度和高度。它的语法如下:
x, y, w, h = cv2.boundingRect(points)
其中各参数的意义如下:
points
:轮廓中的点集。x, y
:矩形的左上角坐标。w
:矩形的宽度。h
:矩形的高度。
函数返回矩形包围框的左上角坐标以及宽度和高度。
4.2
在 OpenCV 中,你可以使用 cv2.minAreaRect()
函数来获取轮廓的最小外接矩形框。这个函数可以用来获取包围轮廓的最小旋转矩形,即旋转矩形框的中心点坐标、宽度、高度以及旋转角度。它的语法如下:
rect = cv2.minAreaRect(points)
其中各参数的意义如下:
points
:轮廓中的点集。rect
:返回的最小外接矩形对象,包含矩形的中心点坐标、宽度、高度以及旋转角度。
函数返回的是一个 RotatedRect
对象,你可以通过该对象的方法来获取矩形的信息
4.3
OpenCV 中,你可以使用 cv2.minEnclosingCircle()
函数来获取轮廓的最小包围圆。这个函数可以用来获取包围轮廓的最小圆,即圆心坐标和半径。它的语法如下:
(center, radius) = cv2.minEnclosingCircle(points)
其中各参数的意义如下:
points
:轮廓中的点集。center
:返回的圆心坐标,通常是一个二元元组(x, y)
。radius
:返回的圆的半径。
函数返回的是一个二元元组,包含圆心坐标和半径信息。
任务演练——几何形状拟合实践
1使用矩形包围框进行拟合
代码:
import cv2
img = cv2.imread("C:/Users/win11/opencv/sucai8/shape.jpg")
cv2.imshow("original", img)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
x, y, w, h = cv2.boundingRect(contours[0])
cv2.rectangle(img, (x, y), (x+w, y+h), (0, 0, 0), 2)
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:
2使用最小包围矩形框进行拟合
代码:
import cv2
import numpy as np
img = cv2.imread("C:/Users/win11/opencv/sucai8/shape.jpg")
cv2.imshow("original", img)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
retval=cv2.minAreaRect(contours[1])
points=cv2.boxPoints(retval)
points=np.int64(points)
cv2.drawContours(img,[points],0,(0,0,0),2)
cv2.imshow("result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:
3使用最小包围圆形进行拟合
代码:
import cv2
import numpy as np
# 读取图像
img = cv2.imread("C:/Users/win11/opencv/sucai8/shape.jpg")
cv2.imshow("Original", img)
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化处理
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
# 寻找轮廓
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
# 获取第二个轮廓的最小外接圆
(x, y), radius = cv2.minEnclosingCircle(contours[1])
center = (int(x), int(y))
radius = int(radius)
# 绘制最小外接圆
cv2.circle(img, center, radius, (0, 0, 0), 2)
# 显示结果图像
cv2.imshow("Result", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:
任务5——绘制凸包
凸包是指包围一组点集的最小凸多边形。在计算机视觉和图形学中,凸包常用于图像处理中的形状分析和轮廓检测。通常,通过计算轮廓中的凸包可以得到目标物体的外形信息,这对于识别和分析图像中的对象非常有用。
在OpenCV中,可以使用 cv2.convexHull()
函数来计算凸包并绘制。下面是该函数的语法和参数:
hull = cv2.convexHull(points[, hull[, clockwise[, returnPoints]]])
points
: 输入的点集,通常是轮廓的点集。hull
: 可选参数,输出的凸包点集。clockwise
: 可选参数,指定是否输出凸包点按照顺时针排序,默认为False
。returnPoints
: 可选参数,指定输出是点集的索引还是实际坐标,默认为True
,表示输出实际坐标。
任务演练——获取简单图像的凸包
代码:
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread("C:/Users/win11/opencv/sucai8/contours2.png")
cv2.imshow("original", img)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
hull=cv2.convexHull(contours[0])
cv2.polylines(img,[hull],True,(255,0,0),2)
cv2.imshow("hull", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
plt.imshow(img)
结果如下:
任务6——轮廓分类
在 OpenCV 中,有一些函数和参数可以用于轮廓分类、计算宽高比和占空比:
-
轮廓分类(Contour Hierarchy):
cv2.findContours()
函数中的hierarchy
参数用于指定轮廓的层级信息。常用的层级类型包括cv2.RETR_LIST
、cv2.RETR_EXTERNAL
、cv2.RETR_TREE
等,它们会影响轮廓的提取和排序方式。
-
宽高比计算:
- 计算轮廓外接矩形的宽高比可以通过计算矩形的宽度除以高度来实现。在代码中,可以使用以下公式来计算宽高比:
aspect_ratio = float(w) / h
- 计算轮廓外接矩形的宽高比可以通过计算矩形的宽度除以高度来实现。在代码中,可以使用以下公式来计算宽高比:
-
占空比计算:
- 占空比(Aspect Ratio)是指对象的宽度与高度之比。在轮廓分析中,可以将外接矩形的宽度和高度比较来计算占空比。在代码中,可以使用以下公式来计算:
aspect_ratio = float(w) / h
- 占空比(Aspect Ratio)是指对象的宽度与高度之比。在轮廓分析中,可以将外接矩形的宽度和高度比较来计算占空比。在代码中,可以使用以下公式来计算:
任务演练——轮廓分类 使用特征值对轮廓进行分类 将长扁圆与扁扁圆进行分类 并对其更换yans
代码:
import cv2 # 导入OpenCV库
import numpy as np # 导入NumPy库用于数组操作
# 读取图像
img = cv2.imread("C:/Users/win11/opencv/sucai8/face.png")
cv2.imshow("original", img) # 显示原始图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 转换为灰度图像
ret, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)#对灰度图像进行二值化处理
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)#查找图像中的轮廓。
h, w, c = img.shape # 获取图像的高度、宽度和通道数
mask = np.zeros((h, w, c), np.uint8) # 创建与原始图像相同大小的全零图像作为掩码
# 遍历轮廓
for cnt in contours:
# 获取边界框
x, y, w, h = cv2.boundingRect(cnt)#获取当前轮廓的边界框
cv2.rectangle(img, (x, y), (x+w, y+h), (255, 255, 255), 3) # 绘制边界框 在原始图像上绘制当前轮廓的全白边界框。
cv2.imshow("temp", img) # 显示临时结果图像
# 计算椭圆的宽高比
AR = float(w) / h
if AR < 1:
# 绘制红色轮廓(长的椭圆)
cv2.drawContours(mask, [cnt], -1, (0, 0, 255), -1) # 在填充 掩码mask上绘制轮廓填充
print(AR, "是长的椭圆")
else:
# 绘制红色轮廓(扁的椭圆)
cv2.drawContours(mask, [cnt], -1, (0, 255, 255), -1) # 在掩码上绘制轮廓
print(AR, "是扁的椭圆")
# 显示最终结果
cv2.imshow("result", mask)
cv2.waitKey(0) # 等待按键按下
cv2.destroyAllWindows() # 关闭所有窗口
结果如下: