概述
图像形状检测是计算机视觉中的一个重要任务,广泛应用于物体识别、机器人导航等领域。本文将详细介绍如何使用 Python 和 OpenCV 实现图像形状检测,包括读取图像、预处理图像、查找轮廓、绘制轮廓以及形状分类。通过本文的学习,你将能够理解和实现一个完整的图像形状检测系统。
环境准备
确保你已经安装了 OpenCV 库。如果没有安装,可以使用以下命令进行安装:
pip install opencv-python
此外,准备好一张包含不同形状的图像文件 shapes.png
,用于形状检测。
示例详解
import cv2
from utils import img_stack_util
def get_contours(img, img_contour):
"""
获取轮廓
:param img: 预处理图(灰度高斯模糊图)
:param img_contour: 原图副本,绘制轮廓
:return:
"""
# 寻找轮廓
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for cnt in contours:
# 计算轮廓区域面积
area = cv2.contourArea(cnt)
print(area)
if area > 500:
# 面积大于500
# 绘制轮廓
cv2.drawContours(img_contour, cnt, -1, (255, 0, 0), 3)
# 计算曲线周长(轮廓曲线,是否封闭)
perimeter = cv2.arcLength(curve=cnt, closed=True)
print(perimeter)
# 近似多边曲线(轮廓曲线,逼近精度[值越小,两线最大距离越小,折线越多,多边形边数越多],是否封闭),返回定点向量
approx = cv2.approxPolyDP(curve=cnt, epsilon=0.02*perimeter, closed=True)
print(approx)
# 多边形角数
obj_cor = len(approx)
print(obj_cor)
# 计算灰度图像边距
x, y, w, h = cv2.boundingRect(approx)
# 根据角数判断形状
if obj_cor == 3:
object_type = "Tri"
elif obj_cor == 4:
asp_ratio = w/float(h)
if 1.03 > asp_ratio > 0.98:
object_type = "Square"
else:
object_type = "Rectangle"
elif obj_cor > 4:
object_type = "Circles"
else:
object_type = "None"
# 绘制矩形边框
cv2.rectangle(img_contour, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 边框左下角绘制文字
cv2.putText(img_contour, object_type,
(x, y + h), cv2.FONT_HERSHEY_COMPLEX, 0.7,
(0, 0, 0), 2)
def start():
"""
入口
:return:
"""
img = cv2.imread(r'./resources/shapes.png') # 读取原始图像
# 副本
img_contour = img.copy()
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图像
# 高斯模糊,降噪
img_blur = cv2.GaussianBlur(img_gray, ksize=(7, 7), sigmaX=1)
img_canny = cv2.Canny(img_blur, 40, 40) # Canny边缘检测
get_contours(img_canny, img_contour) # 获取轮廓并绘制
img_stack = img_stack_util.stack_img(
img_arr=([img, img_gray, img_blur],
[img_canny, img_contour]),
scale=0.6,
labels=(['origin', 'gray', 'blur'],
['canny', 'contour'])
)
cv2.imshow("Stack", img_stack) # 显示图像堆栈
cv2.waitKey(0) # 等待用户按键
cv2.destroyAllWindows() # 关闭所有窗口
if __name__ == '__main__':
start()
代码详解
1. 导入必要的库
import cv2
from utils import img_stack_util
import cv2
:导入 OpenCV 库,用于图像处理和显示。from utils import img_stack_util
:导入自定义的图像堆叠工具函数img_stack_util
,用于将多个图像堆叠在一起显示。
2. 定义 get_contours
函数
def get_contours(img, img_contour):
"""
获取轮廓
:param img: 预处理图(灰度高斯模糊图)
:param img_contour: 原图副本,绘制轮廓
:return:
"""
# 寻找轮廓
contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for cnt in contours:
# 计算轮廓区域面积
area = cv2.contourArea(cnt)
print(area)
if area > 500:
# 面积大于500
# 绘制轮廓
cv2.drawContours(img_contour, cnt, -1, (255, 0, 0), 3)
# 计算曲线周长(轮廓曲线,是否封闭)
perimeter = cv2.arcLength(curve=cnt, closed=True)
print(perimeter)
# 近似多边曲线(轮廓曲线,逼近精度[值越小,两线最大距离越小,折线越多,多边形边数越多],是否封闭),返回定点向量
approx = cv2.approxPolyDP(curve=cnt, epsilon=0.02*perimeter, closed=True)
print(approx)
# 多边形角数
obj_cor = len(approx)
print(obj_cor)
# 计算灰度图像边距
x, y, w, h = cv2.boundingRect(approx)
# 根据角数判断形状
if obj_cor == 3:
object_type = "Tri"
elif obj_cor == 4:
asp_ratio = w/float(h)
if 1.03 > asp_ratio > 0.98:
object_type = "Square"
else:
object_type = "Rectangle"
elif obj_cor > 4:
object_type = "Circles"
else:
object_type = "None"
# 绘制矩形边框
cv2.rectangle(img_contour, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 边框左下角绘制文字
cv2.putText(img_contour, object_type,
(x, y + h), cv2.FONT_HERSHEY_COMPLEX, 0.7,
(0, 0, 0), 2)
cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
:寻找图像中的轮廓,cv2.RETR_EXTERNAL
表示只检索外部轮廓,cv2.CHAIN_APPROX_NONE
表示存储所有的轮廓点。cv2.contourArea(cnt)
:计算轮廓的面积。cv2.drawContours(img_contour, cnt, -1, (255, 0, 0), 3)
:在原图副本img_contour
上绘制轮廓,颜色为蓝色,线条宽度为 3。cv2.arcLength(curve=cnt, closed=True)
:计算轮廓的周长。cv2.approxPolyDP(curve=cnt, epsilon=0.02*perimeter, closed=True)
:近似多边曲线,epsilon
参数控制逼近精度。len(approx)
:计算多边形的角数。cv2.boundingRect(approx)
:计算轮廓的边界矩形。cv2.rectangle(img_contour, (x, y), (x+w, y+h), (0, 255, 0), 2)
:在原图副本img_contour
上绘制矩形边框,颜色为绿色,线条宽度为 2。cv2.putText(img_contour, object_type, (x, y + h), cv2.FONT_HERSHEY_COMPLEX, 0.7, (0, 0, 0), 2)
:在矩形边框的左下角绘制形状类型文字。
3. 定义 start
函数
def start():
"""
入口
:return:
"""
img = cv2.imread(r'./resources/shapes.png') # 读取原始图像
# 副本
img_contour = img.copy()
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换为灰度图像
# 高斯模糊,降噪
img_blur = cv2.GaussianBlur(img_gray, ksize=(7, 7), sigmaX=1)
img_canny = cv2.Canny(img_blur, 40, 40) # Canny边缘检测
get_contours(img_canny, img_contour) # 获取轮廓并绘制
img_stack = img_stack_util.stack_img(
img_arr=([img, img_gray, img_blur],
[img_canny, img_contour]),
scale=0.6,
labels=(['origin', 'gray', 'blur'],
['canny', 'contour'])
)
cv2.imshow("Stack", img_stack) # 显示图像堆栈
cv2.waitKey(0) # 等待用户按键
cv2.destroyAllWindows() # 关闭所有窗口
cv2.imread(r'./resources/shapes.png')
:读取原始图像shapes.png
。img.copy()
:创建原图的副本,用于绘制轮廓。cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
:将图像从 BGR 格式转换为灰度格式。cv2.GaussianBlur(img_gray, ksize=(7, 7), sigmaX=1)
:对灰度图像进行高斯模糊,以减少噪声。cv2.Canny(img_blur, 40, 40)
:使用 Canny 边缘检测算法检测图像边缘。get_contours(img_canny, img_contour)
:调用get_contours
函数,获取轮廓并在原图副本上绘制。img_stack_util.stack_img
:使用自定义的图像堆叠工具函数,将多个图像堆叠在一起显示。cv2.imshow("Stack", img_stack)
:在窗口中显示图像堆栈。cv2.waitKey(0)
:等待用户按键。cv2.destroyAllWindows()
:关闭所有 OpenCV 窗口。
运行效果展示
假设我们有一张包含不同形状的图像 shapes.png
:
运行上述代码后,生成的结果图像如下所示:
总结
本文详细介绍了如何使用 Python 和 OpenCV 实现图像形状检测,包括读取图像、预处理图像、查找轮廓、绘制轮廓以及形状分类。通过理解这些基本概念和技术,你可以更加灵活地在图像处理和物体识别中应用 OpenCV。