【图像处理基石】如何在图像中提取出基本形状,比如圆形,椭圆,方形等等?

在计算机视觉领域,基本形状提取(圆形、椭圆、方形、三角形等)是一项基础且核心的任务,广泛应用于工业质检(如零件尺寸检测)、目标识别(如交通标志检测)、机器人视觉(如障碍物形状判断)等场景。传统方法无需训练数据,依赖图像处理技术即可实现,适合快速落地和入门学习。

本文将聚焦 霍夫变换轮廓检测+形状特征匹配 两种经典算法,用 Python+OpenCV 手把手实现基本形状提取,兼顾原理讲解和实战代码,适合初学者直接上手。

一、核心算法原理

1.1 霍夫变换(Hough Transform):主打圆形/直线检测

霍夫变换的核心思想是 将图像空间的特征(点、线、圆)映射到参数空间,通过投票机制筛选出最可能的特征

  • 霍夫圆检测 :圆的方程为 (x−a)2+(y−b)2=r2(x-a)^2 + (y-b)^2 = r^2(x−a)2+(y−b)2=r2,其中 (a,b)(a,b)(a,b) 是圆心,rrr 是半径。将图像中每个边缘点映射到 (a,b,r)(a,b,r)(a,b,r) 三维参数空间,统计参数空间中投票数最高的点,即为检测到的圆。
  • 霍夫直线检测 :直线的极坐标方程为 ρ=xcos⁡θ+ysin⁡θ\rho = x\cos\theta + y\sin\thetaρ=xcosθ+ysinθ,映射到 (ρ,θ)(\rho,\theta)(ρ,θ) 二维参数空间,投票峰值对应直线。(方形可通过直线检测+角点组合推导)

1.2 轮廓检测+形状特征匹配:通用形状识别

轮廓是图像中连续的像素集合(前景与背景的边界)。通过轮廓的几何特征(边数、圆形度、长宽比等),可快速识别形状:

  1. 轮廓提取 :先对图像预处理(灰度化、模糊、阈值分割),再用 findContours 函数提取轮廓;
  2. 轮廓近似 :用 approxPolyDP 函数将不规则轮廓近似为多边形(减少冗余点);
  3. 特征判断
    • 边数=3 → 三角形;
    • 边数=4 → 方形(需验证长宽比、内角接近90°);
    • 圆形度(轮廓面积/最小外接圆面积)≈1 → 圆形;
    • fitEllipse 拟合椭圆 → 椭圆。

二、实战准备:环境与依赖

需安装 Python3 和 OpenCV(图像处理核心库),命令如下:

bash 复制代码
pip install opencv-python matplotlib numpy

三、代码实现:分模块落地

3.1 第一步:图像预处理(关键!决定检测效果)

预处理的目标是 降噪+突出前景轮廓,步骤通常为:

  1. 读取图像 → 2. 灰度化 → 3. 高斯模糊(降噪) → 4. 阈值分割/边缘检测(突出轮廓)
python 复制代码
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 读取图像(替换为你的图像路径)
img = cv2.imread("shapes.jpg")
# 复制原图用于绘制结果
img_result = img.copy()
# 1. 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 2. 高斯模糊(核大小为奇数, sigmaX控制模糊程度)
blurred = cv2.GaussianBlur(gray, (5, 5), 1)
# 3. 阈值分割(将图像转为黑白二值图,突出前景)
_, thresh = cv2.threshold(blurred, 127, 255, cv2.THRESH_BINARY_INV)
# 可选:形态学操作(进一步优化轮廓,如填充小缺口)
kernel = np.ones((3, 3), np.uint8)
thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel)

# 显示预处理结果
plt.figure(figsize=(12, 4))
plt.subplot(1, 3, 1)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title("原图")
plt.axis("off")

plt.subplot(1, 3, 2)
plt.imshow(gray, cmap="gray")
plt.title("灰度图")
plt.axis("off")

plt.subplot(1, 3, 3)
plt.imshow(thresh, cmap="gray")
plt.title("预处理后(二值图)")
plt.axis("off")
plt.show()

3.2 第二步:霍夫圆检测(专门针对圆形)

OpenCV 提供 cv2.HoughCircles 函数,直接实现霍夫圆检测,关键参数需根据图像调整:

  • dp:累加器分辨率(越大检测越慢,精度越高);
  • minDist:两个圆的最小距离(避免重复检测);
  • param1:Canny 边缘检测的高阈值(低阈值为其1/2);
  • param2:投票阈值(越大检测到的圆越可靠);
  • minRadius/maxRadius:圆的半径范围。
python 复制代码
# 霍夫圆检测
circles = cv2.HoughCircles(
    blurred,  # 输入图像(建议用模糊后的灰度图)
    cv2.HOUGH_GRADIENT,  # 检测方法(固定)
    dp=1.2,  # 累加器分辨率
    minDist=50,  # 两圆最小距离
    param1=50,  # Canny边缘高阈值
    param2=30,  # 投票阈值
    minRadius=10,  # 最小半径
    maxRadius=100  # 最大半径
)

# 绘制检测到的圆
if circles is not None:
    circles = np.uint16(np.around(circles))  # 转为整数坐标
    for i in circles[0, :]:
        # 绘制圆心
        cv2.circle(img_result, (i[0], i[1]), 2, (0, 255, 0), -1)
        # 绘制圆轮廓
        cv2.circle(img_result, (i[0], i[1]), i[2], (255, 0, 0), 2)
        # 标注"圆形"
        cv2.putText(
            img_result, "Circle", (i[0]-i[2], i[1]-10),
            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 1
        )

3.3 第三步:轮廓检测+多形状识别(方形、三角形、椭圆)

通过轮廓的几何特征识别方形、三角形,用 fitEllipse 拟合椭圆:

python 复制代码
# 提取轮廓(RETR_EXTERNAL:只保留最外层轮廓)
contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# 遍历每个轮廓
for cnt in contours:
    # 过滤小轮廓(避免检测噪声)
    area = cv2.contourArea(cnt)
    if area < 100:
        continue

    # 轮廓近似(epsilon:近似精度,通常为周长的0.02倍)
    peri = cv2.arcLength(cnt, True)
    approx = cv2.approxPolyDP(cnt, 0.02 * peri, True)
    vertices = len(approx)  # 近似多边形的边数

    # 计算轮廓的外接矩形(用于标注文字位置)
    x, y, w, h = cv2.boundingRect(approx)
    center_x = x + w // 2
    center_y = y + h // 2

    # 1. 三角形(边数=3)
    if vertices == 3:
        cv2.drawContours(img_result, [approx], 0, (0, 255, 0), 2)
        cv2.putText(img_result, "Triangle", (center_x-30, center_y), 
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1)
    
    # 2. 方形(边数=4,且长宽比接近1,内角接近90°)
    elif vertices == 4:
        # 计算长宽比
        aspect_ratio = float(w) / h
        # 验证是否为矩形(用轮廓的外接矩形面积与轮廓面积的比值)
        rect_area = w * h
        area_ratio = area / rect_area
        if 0.9 < aspect_ratio < 1.1 and area_ratio > 0.85:
            cv2.drawContours(img_result, [approx], 0, (0, 0, 255), 2)
            cv2.putText(img_result, "Square", (center_x-25, center_y), 
                        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1)
        else:
            # 非正方形(长方形)
            cv2.drawContours(img_result, [approx], 0, (128, 0, 128), 2)
            cv2.putText(img_result, "Rectangle", (center_x-35, center_y), 
                        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (128, 0, 128), 1)
    
    # 3. 椭圆(轮廓点数足够,且拟合椭圆的长宽比合理)
    elif vertices > 8:
        # 拟合椭圆(需轮廓点数≥5)
        if len(cnt) >= 5:
            ellipse = cv2.fitEllipse(cnt)
            # 计算椭圆的长宽比(避免将圆识别为椭圆)
            major_axis = max(ellipse[1])
            minor_axis = min(ellipse[1])
            ellipse_ratio = minor_axis / major_axis
            if ellipse_ratio < 0.9:  # 长宽比差异较大,判定为椭圆
                cv2.ellipse(img_result, ellipse, (255, 255, 0), 2)
                cv2.putText(img_result, "Ellipse", (center_x-25, center_y), 
                            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 0), 1)

3.4 第四步:显示最终结果

python 复制代码
# 显示结果
plt.figure(figsize=(8, 6))
plt.imshow(cv2.cvtColor(img_result, cv2.COLOR_BGR2RGB))
plt.title("基本形状提取结果")
plt.axis("off")
plt.show()

# 保存结果
cv2.imwrite("shapes_result.jpg", img_result)
print("结果已保存为 shapes_result.jpg")

四、效果展示与参数调优

4.1 测试图像与结果

假设测试图像 shapes.jpg 包含圆形、方形、长方形、三角形、椭圆,运行代码后:

  • 圆形:蓝色轮廓+"Circle"标注;
  • 方形:红色轮廓+"Square"标注;
  • 长方形:紫色轮廓+"Rectangle"标注;
  • 三角形:绿色轮廓+"Triangle"标注;
  • 椭圆:青色轮廓+"Ellipse"标注。

4.2 常见问题与调优技巧

  1. 检测不到形状/漏检

    • 降低 HoughCirclesparam2(圆检测);
    • 减小 approxPolyDPepsilon(轮廓近似更精细);
    • 降低阈值分割的阈值(cv2.threshold 的第二个参数)。
  2. 误检(检测到噪声)

    • 增大 HoughCirclesparam2minRadius
    • 提高轮廓面积阈值(area > 200,过滤小噪声);
    • 增大高斯模糊的核大小(如 (7,7))。
  3. 圆被识别为椭圆

    • 优化霍夫圆检测参数(确保圆先被检测到);
    • 调整椭圆判定的 ellipse_ratio(如改为 < 0.8)。

五、总结与扩展

本文通过 霍夫变换轮廓检测+特征匹配 实现了基本形状提取,核心优势是:

  • 无需训练数据,代码轻量化;
  • 实时性好,适合嵌入式设备;
  • 原理直观,适合入门学习。

局限性与扩展方向

  1. 局限性:对遮挡、变形、复杂背景敏感;
  2. 扩展方向
    • 复杂场景:结合深度学习(如 Mask R-CNN)实现端到端形状分割;
    • 3D 形状:结合立体视觉(如双目相机)提取 3D 形状;
    • 实时处理:用 C++ 重写核心代码,结合 GPU 加速。
相关推荐
蓝牙先生1 小时前
简易TCP C/S通信
c语言·tcp/ip·算法
温轻舟2 小时前
Python自动办公工具05-Word表中相同内容的单元格自动合并
开发语言·python·word·自动化办公·温轻舟
习习.y3 小时前
python笔记梳理以及一些题目整理
开发语言·笔记·python
撸码猿3 小时前
《Python AI入门》第10章 拥抱AIGC——OpenAI API调用与Prompt工程实战
人工智能·python·aigc
qq_386218993 小时前
Gemini生成的自动搜索和下载论文的python脚本
开发语言·python
vx_vxbs663 小时前
【SSM电影网站】(免费领源码+演示录像)|可做计算机毕设Java、Python、PHP、小程序APP、C#、爬虫大数据、单片机、文案
java·spring boot·python·mysql·小程序·php·idea
音视频牛哥4 小时前
轻量级RTSP服务的工程化设计与应用:从移动端到边缘设备的实时媒体架构
人工智能·计算机视觉·音视频·音视频开发·rtsp播放器·安卓rtsp服务器·安卓实现ipc功能
稚辉君.MCA_P8_Java4 小时前
Gemini永久会员 Java中的四边形不等式优化
java·后端·算法
稚辉君.MCA_P8_Java4 小时前
通义 插入排序(Insertion Sort)
数据结构·后端·算法·架构·排序算法