一、实验目的与意义

本实验旨在深入理解图像区域的轮廓提取原理,掌握多种轮廓提取算法的实现方法,并通过时间测试对比不同算法的性能。轮廓提取是计算机视觉中的基础任务,广泛应用于目标检测、图像分割、形状分析等领域。通过本实验,不仅能熟悉经典图像处理算法的应用,还能培养针对具体问题设计优化方案的能力。

二、实验原理

轮廓提取的核心是识别图像中物体与背景(或不同物体)之间的边界。其基本流程通常包括:

  1. 图像预处理(去噪、灰度化等)
  2. 边缘 / 区域分割(通过边缘检测或阈值分割)
  3. 轮廓提取与优化

本实验采用三种不同策略实现轮廓提取,每种策略基于不同的图像处理原理:

1. 基于边缘检测算子的轮廓提取

边缘检测算子通过计算图像梯度识别像素值突变的区域(边缘)。本实验使用 Prewitt 算子,其原理是利用两个方向的卷积核(水平和垂直)计算梯度,再通过梯度合成得到边缘图像,最后从边缘图像中提取轮廓。

2. 基于阈值分割的轮廓提取

阈值分割通过设定灰度值阈值将图像分为前景和背景。本实验采用大津法(Otsu)自动确定最优阈值,该方法通过最大化类间方差寻找最佳阈值,适用于对比度较明显的图像,再从二值化结果中提取轮廓。

3. 基于 Canny 边缘检测的轮廓提取

Canny 算法是一种多阶段边缘检测算法,包括:

  • 高斯滤波去噪
  • 计算梯度强度与方向
  • 非极大值抑制(保留局部梯度最大的像素)
  • 双阈值检测与边缘连接该方法能有效检测弱边缘并抑制噪声,生成的边缘更连续,适合轮廓提取。

三、实验代码实现

1. 核心功能模块

import cv2
import numpy as np
import time
import matplotlib.pyplot as plt

def load_and_preprocess(image_path):
    """加载图像并进行预处理(灰度化、去噪)"""
    # 读取图像
    img = cv2.imread(image_path)
    if img is None:
        raise ValueError("Image path error: Cannot load image")

    # 转为单通道灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # 高斯滤波去噪
    blurred = cv2.GaussianBlur(gray, (5, 5), 1.4)

    # 转为3通道灰度图(用于后续绘制彩色元素)
    gray_3ch = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)

    return gray_3ch, gray, blurred, img  # 返回处理后的各类图像

2. 时间测试模块

def time_algorithm(func, *args):
    """测试算法运行时间的工具函数"""
    start_time = time.time()  # 记录开始时间
    result = func(*args)      # 执行目标函数
    end_time = time.time()    # 记录结束时间
    return result, end_time - start_time  # 返回结果和耗时

3. 三种轮廓提取策略实现

策略 1:基于边缘检测算子
def strategy_edge_based(gray_3ch, blurred):
    """使用Prewitt边缘检测算子的轮廓提取策略"""
    # Prewitt边缘检测
    edge_img, time_edge = time_algorithm(prewitt_edge_detector, blurred)
    
    # 二值化处理
    binary_img, time_bin = time_algorithm(binarize_image, edge_img, 50)
    
    # 形态学后处理(填补边缘间隙)
    processed_binary, time_post = time_algorithm(postprocess_binary, binary_img)
    
    # 提取并绘制轮廓
    contour_img, time_contour = time_algorithm(
        extract_and_draw_contours, gray_3ch, processed_binary)
    
    total_time = time_edge + time_bin + time_post + time_contour
    return contour_img, total_time, "Edge-based (Prewitt)"
策略 2:基于阈值分割
def strategy_threshold_based(gray_3ch, gray):
    """使用大津法阈值分割的轮廓提取策略"""
    # 大津法自动阈值分割(无需手动设定阈值)
    binary_img, time_bin = time_algorithm(
        cv2.threshold, gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    
    # 形态学处理(去除噪点)
    processed_binary, time_morph = time_algorithm(postprocess_binary, binary_img)
    
    # 提取轮廓
    contour_img, time_contour = time_algorithm(
        extract_and_draw_contours, gray_3ch, processed_binary)
    
    total_time = time_bin + time_morph + time_contour
    return contour_img, total_time, "Threshold-based (Otsu)"
策略 3:基于 Canny 边缘检测
def strategy_canny_based(gray_3ch, blurred):
    """使用Canny边缘检测的轮廓提取策略"""
    # Canny边缘检测(双阈值控制边缘提取精度)
    edges, time_canny = time_algorithm(cv2.Canny, blurred, 50, 150)
    
    # 形态学处理
    processed_edges, time_morph = time_algorithm(postprocess_binary, edges)
    
    # 提取轮廓
    contour_img, time_contour = time_algorithm(
        extract_and_draw_contours, gray_3ch, processed_edges)
    
    total_time = time_canny + time_morph + time_contour
    return contour_img, total_time, "Canny-based"

4. 优化的轮廓提取方法

针对复杂图像(如存在重叠物体、弱边缘的场景),实现了基于分水岭算法的优化方案:

def optimize_contour_extraction(original_img):
    """优化的轮廓提取方法:结合色彩空间和分水岭算法"""
    # 转换到HSV色彩空间,利用颜色信息辅助分割
    hsv = cv2.cvtColor(original_img, cv2.COLOR_BGR2HSV)
    
    # 对亮度通道进行自适应阈值处理
    v_channel = hsv[:, :, 2]
    adaptive_thresh = cv2.adaptiveThreshold(
        v_channel, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
        cv2.THRESH_BINARY_INV, 11, 2
    )
    
    # 形态学处理去除噪声
    kernel = np.ones((2, 2), np.uint8)
    opening = cv2.morphologyEx(adaptive_thresh, cv2.MORPH_OPEN, kernel, iterations=1)
    
    # 提取确定的背景区域
    sure_bg = cv2.dilate(opening, kernel, iterations=3)
    
    # 距离变换找到确定的前景区域
    dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
    _, sure_fg = cv2.threshold(dist_transform, 0.5 * dist_transform.max(), 255, 0)
    
    # 找到未知区域(前景和背景之间的过渡区)
    sure_fg = np.uint8(sure_fg)
    unknown = cv2.subtract(sure_bg, sure_fg)
    
    # 连通组件标记
    _, markers = cv2.connectedComponents(sure_fg)
    markers += 1  # 确保背景不是0值
    markers[unknown == 255] = 0  # 未知区域标记为0
    
    # 分水岭算法分割(能有效处理重叠物体)
    markers = cv2.watershed(original_img, markers)
    original_img[markers == -1] = [0, 0, 255]  # 红色标记边界
    
    return original_img

四、实验结果与分析

(1)效果对比
  • 基于 Prewitt 算子:边缘检测对噪声较敏感,轮廓可能存在较多毛刺,但计算简单
  • 基于大津法阈值分割:对光照均匀、对比度高的图像效果好,但易受光照变化影响
  • 基于 Canny 算子:提取的轮廓更连续、完整,抗噪声能力强,是三种基础方法中效果最优的
  • 优化方案(分水岭算法):能有效分割重叠物体,保留更精细的轮廓细节,尤其适合复杂场景
(2)时间性能对比

一般情况下,三种基础策略的执行时间关系为:

  • 阈值分割法 < Prewitt 算子法 < Canny 算子法
  • 优化方案(分水岭算法)由于涉及更多预处理步骤,耗时相对较长,但精度提升显著

五、实验总结与展望

通过本实验,验证了不同轮廓提取策略的适用性:

  1. 简单场景(如高对比度、低噪声图像)可选择阈值分割法,兼顾效率和效果
  2. 中等复杂场景推荐使用 Canny 算子,在抗噪声和轮廓完整性间取得平衡
  3. 复杂场景(如重叠物体、弱边缘)需采用优化方案(如分水岭算法),结合色彩信息和形态学操作

未来可进一步优化的方向:

  1. 结合深度学习方法(如边缘检测网络)提升复杂场景下的轮廓提取精度
  2. 针对实时应用场景,研究基于硬件加速的快速轮廓提取算法
  3. 引入轮廓特征描述(如面积、周长、凸包等),实现从轮廓提取到形状分析的完整流程

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐