使用Python OpenCV实现图像形状检测

发布于:2024-11-29 ⋅ 阅读:(22) ⋅ 点赞:(0)

目录

一、环境准备

二、读取和预处理图像

读取图像

灰度化

滤波去噪

三、边缘检测

四、查找轮廓

五、绘制轮廓

六、形状分类

七、显示结果

八、完整代码示例

九、总结


图像形状检测是计算机视觉领域中的一项关键技术,广泛应用于工业自动化、机器人视觉、医学图像处理等多个领域。本文将详细介绍如何使用Python和OpenCV库实现图像形状检测,通过简洁明了的步骤和代码示例,帮助你快速掌握这一技能。

一、环境准备

在开始之前,确保你的电脑上已经安装了Python和OpenCV库。你可以通过以下命令来安装OpenCV库:

pip install opencv-python

同时,确保你能够编写和运行Python代码,并熟悉基本的图像处理概念。

二、读取和预处理图像

读取图像

使用OpenCV的cv2.imread()函数读取图像文件。例如,读取一张包含不同形状的图像:

import cv2
 
# 读取图像
img = cv2.imread('shapes.png')

灰度化

将彩色图像转换为灰度图像,以简化后续处理。使用cv2.cvtColor()函数:

# 转换为灰度图像
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

滤波去噪

使用高斯模糊来去除图像中的噪声。高斯模糊是一种常用的图像处理技术,可以平滑图像并减少噪声干扰。使用cv2.GaussianBlur()函数:

# 高斯模糊
blurred_img = cv2.GaussianBlur(gray_img, (5, 5), 0)

三、边缘检测

边缘检测是形状检测的重要步骤,它可以帮助我们找到图像中的轮廓。使用Canny边缘检测算法,该算法是一种常用的边缘检测算法,具有良好的边缘检测效果。使用cv2.Canny()函数:

# Canny边缘检测
edges = cv2.Canny(blurred_img, 50, 150)

四、查找轮廓

使用cv2.findContours()函数查找图像中的轮廓。该函数会返回轮廓点集、层次结构和轮廓的近似方法。我们主要关注轮廓点集:

# 查找轮廓
contours, hierarchy = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

五、绘制轮廓

为了可视化检测到的轮廓,我们可以使用cv2.drawContours()函数在原图像上绘制轮廓:

# 绘制轮廓
contour_img = img.copy()
cv2.drawContours(contour_img, contours, -1, (0, 255, 0), 2)

六、形状分类

根据轮廓的顶点数目、面积、周长等特征,我们可以对检测到的形状进行分类。以下是一个简单的形状分类示例:

for contour in contours:
    # 计算轮廓面积
    area = cv2.contourArea(contour)
    
    # 计算轮廓周长
    perimeter = cv2.arcLength(contour, True)
    
    # 近似轮廓为多边形
    epsilon = 0.02 * perimeter
    approx = cv2.approxPolyDP(contour, epsilon, True)
    
    # 获取轮廓顶点数目
    num_vertices = len(approx)
    
    # 根据顶点数目判断形状
    shape = 'Unknown'
    if num_vertices == 3:
        shape = 'Triangle'
    elif num_vertices == 4:
        # 判断是否为正方形或矩形
        x, y, w, h = cv2.boundingRect(approx)
        aspect_ratio = w / float(h)
        if 0.95 < aspect_ratio < 1.05:
            shape = 'Square'
        else:
            shape = 'Rectangle'
    elif num_vertices == 5:
        shape = 'Pentagon'
    elif num_vertices == 6:
        shape = 'Hexagon'
    else:
        # 对于顶点数目大于6的形状,可以根据周长面积比等特征进一步分类
        # 例如,圆形可以通过周长面积比接近某个阈值来判断
        if 4 * 3.14 * (area / 3.14) ** 0.5 / perimeter > 0.8 and 4 * 3.14 * (area / 3.14) ** 0.5 / perimeter < 1.2:
            shape = 'Circle'
        else:
            shape = 'Other Polygon'
    
    # 在图像上标注形状名称和顶点数目
    M = cv2.moments(contour)
    if M['m00'] != 0:
        cX = int(M['m10'] / M['m00'])
        cY = int(M['m01'] / M['m00'])
    else:
        cX, cY = 0, 0
    
    cv2.putText(contour_img, f'{shape} ({num_vertices} vertices)', (cX - 50, cY - 50), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
    cv2.drawContours(contour_img, [approx], -1, (0, 0, 255), 2)

七、显示结果

最后,使用cv2.imshow()函数显示处理后的图像:

# 显示结果图像
cv2.imshow('Shape Detection', contour_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

八、完整代码示例

以下是完整的代码示例,将上述步骤整合在一起:

import cv2
 
# 读取图像
img = cv2.imread('shapes.png')
 
# 转换为灰度图像
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
 
# 高斯模糊
blurred_img = cv2.GaussianBlur(gray_img, (5, 5), 0)
 
# Canny边缘检测
edges = cv2.Canny(blurred_img, 50, 150)
 
# 查找轮廓
contours, hierarchy = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
 
# 绘制轮廓并分类形状


contour_img = img.copy()
for contour in contours:
    # 计算轮廓面积
    area = cv2.contourArea(contour)
    
    # 计算轮廓周长
    perimeter = cv2.arcLength(contour, True)
    
    # 近似轮廓为多边形
    epsilon = 0.02 * perimeter
    approx = cv2.approxPolyDP(contour, epsilon, True)
    
    # 获取轮廓顶点数目
    num_vertices = len(approx)
    
    # 根据顶点数目判断形状
    shape = 'Unknown'
    if num_vertices == 3:
        shape = 'Triangle'
    elif num_vertices == 4:
        # 判断是否为正方形或矩形
        x, y, w, h = cv2.boundingRect(approx)
        aspect_ratio = w / float(h)
        if 0.95 < aspect_ratio < 1.05:
            shape = 'Square'
        else:
            shape = 'Rectangle'
    elif num_vertices == 5:
        shape = 'Pentagon'
    elif num_vertices == 6:
        shape = 'Hexagon'
    else:
        # 对于顶点数目大于6的形状,可以根据周长面积比等特征进一步分类
        # 例如,圆形可以通过周长面积比接近某个阈值来判断
        if 4 * 3.14 * (area / 3.14) ** 0.5 / perimeter > 0.8 and 4 * 3.14 * (area / 3.14) ** 0.5 / perimeter < 1.2:
            shape = 'Circle'
        else:
            shape = 'Other Polygon'
    
    # 在图像上标注形状名称和顶点数目
    M = cv2.moments(contour)
    if M['m00'] != 0:
        cX = int(M['m10'] / M['m00'])
        cY = int(M['m01'] / M['m00'])
    else:
        cX, cY = 0, 0
    
    # 绘制形状名称和顶点数目
    cv2.putText(contour_img, f'{shape} ({num_vertices} vertices)', (cX - 50, cY - 50), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)
    
    # 绘制轮廓(近似多边形)
    cv2.drawContours(contour_img, [approx], -1, (0, 0, 255), 2)

# 显示结果图像
cv2.imshow('Shape Detection', contour_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

九、总结

本文详细介绍了如何使用Python和OpenCV库实现图像形状检测。通过环境准备、图像预处理、边缘检测、轮廓查找、绘制轮廓及形状分类等步骤,展示了完整的图像形状检测流程。利用高斯模糊、Canny边缘检测和轮廓近似等技术,实现了对图像中不同形状的有效检测与分类。通过示例代码,读者可以快速掌握图像形状检测的基本方法和技巧,为工业自动化、机器人视觉等领域的实际应用提供有力支持。本文内容全面、步骤清晰,适合初学者及有一定基础的读者学习和参考。