MATLAB实现水平集算法的图像目标检测

水平集方法(Level Set Method)是一种强大的图像分割技术,通过隐式地表示演化曲线(零水平集)来捕捉目标边界。下面以 Chan-Vese 模型(基于区域的主动轮廓)为例, MATLAB 实现,用于图像目标检测(分割)。


1. Chan-Vese 水平集模型简介

Chan-Vese 模型假设图像由两个同质区域组成(前景和背景),通过最小化能量泛函驱动曲线演化:

\[E(C) = \mu \cdot \text{Length}(C) + \nu \cdot \text{Area}(\text{inside}) + \lambda_1 \int_{\text{inside}} |I - c_1|^2 dx + \lambda_2 \int_{\text{outside}} |I - c_2|^2 dx \]

对应的水平集演化方程为:

\[\frac{\partial \phi}{\partial t} = \delta(\phi)\left[\mu \cdot \nabla \cdot \left(\frac{\nabla \phi}{|\nabla \phi|}\right) - \nu - \lambda_1(I - c_1)^2 + \lambda_2(I - c_2)^2\right] \]

其中:

  • \(\phi\) 为水平集函数(符号距离函数)
  • \(c_1\), \(c_2\) 分别为曲线内部和外部的灰度均值
  • \(\delta(\phi)\) 为 Dirac delta 函数(窄带内有效)
  • \(\mu\) 控制轮廓平滑度,\(\lambda_1,\lambda_2\) 控制拟合项权重

2. MATLAB 完整代码

%% 水平集 Chan-Vese 模型实现图像目标检测
clc; clear; close all;

%% 1. 读取图像并预处理
I = imread('coins.png');        % 示例图像(可替换为自己的图像)
if size(I,3) == 3
    I = rgb2gray(I);
end
I = im2double(I);
[M, N] = size(I);

%% 2. 初始化水平集函数 φ(符号距离函数)
% 初始轮廓:一个较小的圆或矩形(位于图像中央)
phi = ones(M, N) * 2;           % 外部为正
center = [round(M/2), round(N/2)];
radius = min(M,N)/4;
[X, Y] = meshgrid(1:N, 1:M);
phi((X - center(2)).^2 + (Y - center(1)).^2 < radius^2) = -2;  % 内部为负

%% 3. 参数设置
mu = 0.2;           % 长度项权重
nu = 0;             % 面积项权重(通常设为0)
lambda1 = 1;        % 内部拟合项权重
lambda2 = 1;        % 外部拟合项权重
dt = 0.1;           % 时间步长
epsilon = 1e-6;     % 正则化参数(防止除以0)
iterNum = 500;      % 迭代次数
tol = 1e-3;         % 收敛阈值

%% 4. 主迭代
figure;
subplot(1,2,1); imshow(I); title('原始图像');
hold on;
contour(phi, [0 0], 'r', 'LineWidth', 2);
hold off;

for iter = 1:iterNum
    % 4.1 计算内部和外部均值
    inside = phi < 0;
    outside = phi >= 0;
    c1 = mean(I(inside));
    c2 = mean(I(outside));
    
    % 4.2 计算曲率项
    [phi_x, phi_y] = gradient(phi);
    grad_norm = sqrt(phi_x.^2 + phi_y.^2 + epsilon);
    curvature = divergence(phi_x ./ grad_norm, phi_y ./ grad_norm);
    
    % 4.3 计算 Dirac delta 函数的近似
    delta_phi = (1/pi) * (epsilon ./ (epsilon^2 + phi.^2));
    
    % 4.4 更新水平集函数
    force = mu * curvature - nu - lambda1 * (I - c1).^2 + lambda2 * (I - c2).^2;
    phi = phi + dt * delta_phi .* force;
    
    % 4.5 周期性重新初始化为符号距离函数(可选,提高稳定性)
    if mod(iter, 20) == 0
        phi = reinitializeDistance(phi);
    end
    
    % 4.6 检查收敛(零水平集变化量)
    if mod(iter, 10) == 0
        new_contour = phi < 0;
        change = sum(sum(abs(new_contour - old_contour))) / (M*N);
        if change < tol && iter > 10
            fprintf('在第 %d 次迭代收敛\n', iter);
            break;
        end
        old_contour = new_contour;
    end
    
    % 4.7 实时显示(每20帧刷新一次)
    if mod(iter, 20) == 0
        subplot(1,2,2); imshow(I); hold on;
        contour(phi, [0 0], 'g', 'LineWidth', 2);
        title(sprintf('迭代 %d', iter));
        hold off; drawnow;
    end
end

%% 5. 最终结果
final_seg = phi < 0;  % 二值分割结果
figure;
subplot(1,2,1); imshow(I); title('原始图像');
subplot(1,2,2); imshow(final_seg); title('目标检测结果(二值掩膜)');

% 叠加显示轮廓
figure; imshow(I); hold on;
contour(phi, [0 0], 'r', 'LineWidth', 2);
title('检测到的目标轮廓');
hold off;

%% ========== 辅助函数 ==========
function phi = reinitializeDistance(phi)
    % 将水平集函数重新初始化为符号距离函数(快速近似)
    % 使用 bwdist 计算到零水平集的距离
    zero_level = phi >= 0;
    dist_out = bwdist(zero_level);   % 外部距离
    dist_in = bwdist(~zero_level);   % 内部距离
    phi = dist_in - dist_out;        % 内部为负,外部为正
end

3. 代码说明

3.1 初始化

  • 使用圆形初始轮廓(也可以手动绘制多边形或矩形)
  • 水平集函数 \(\phi\) 初始化为符号距离函数:内部为负,外部为正

3.2 核心迭代

  • 每一步计算当前轮廓内外的灰度均值 \(c_1, c_2\)
  • 计算曲率项(控制轮廓平滑度)
  • 计算驱动力并更新 \(\phi\)
  • 每隔一定步数重新初始化为符号距离函数,防止梯度异常

3.3 收敛判断

  • 比较前后两次迭代的零水平集区域变化百分比,小于阈值则停止

3.4 结果显示

  • 实时显示轮廓演化过程
  • 最终输出二值分割掩膜和轮廓叠加图

4. 参数调优指南

参数 作用 典型值 调整方向
\(\mu\) 轮廓平滑度 0.1~0.5 越大越平滑,但可能丢失细节
\(\lambda_1,\lambda_2\) 区域拟合权重 1 若目标与背景灰度差异不对称,可调不同值
\(dt\) 时间步长 0.01~0.1 太大易发散,太小收敛慢
初始轮廓位置 决定检测范围 尽量包围目标 若目标在边缘,初始轮廓应覆盖目标区域

5. 扩展应用

5.1 多目标检测

Chan-Vese 模型天然支持多个目标(只要初始轮廓能包围所有目标)。若需要分离粘连目标,可加入形状约束或使用测地线活动轮廓(Geodesic Active Contours)结合边缘信息。

5.2 彩色图像

将灰度图像改为 RGB 三个通道,拟合项改为:

\[\lambda_1 \|I - c_1\|^2 = \lambda_1 \sum_{ch} (I_{ch} - c_{1,ch})^2 \]

5.3 加入边缘项(Geodesic Active Contour)

edge_stop = 1 ./ (1 + (gradient_magnitude / threshold).^2);
force = alpha * edge_stop * curvature + beta * (edge_stop .* grad_norm) + ...;

5.4 窄带加速

只更新零水平集附近窄带内的 \(\phi\) 值,大幅减少计算量。

参考代码 MATLAB实现水平集算法的图像目标检测 www.youwenfan.com/contentcnv/81469.html

6. 注意事项

  • 本代码适用于单目标或区域灰度均匀的图像。若目标内部灰度不均匀,需使用更高阶模型(如分段常数模型的多相水平集)。
  • 初始轮廓必须与目标有交集,否则无法检测到。
  • 若图像噪声大,可先进行高斯滤波平滑。
  • 迭代次数和收敛阈值可根据图像大小调整(例如 256×256 图像约 200~500 次迭代)。

7. 运行效果

使用 MATLAB 自带的 coins.png 图像,运行上述代码后,水平集轮廓会逐步演化贴合硬币边缘,最终输出每个硬币的分割掩膜。如下图所示(示意):

原始图像                分割结果
┌──────────────┐       ┌──────────────┐
│ ○ ○ ○ ○ ○ ○ │       │ ██ ██ ██ ██ │
│  ○ ○ ○ ○ ○  │  →    │  ██ ██ ██   │
│   ○ ○ ○ ○   │       │   ██ ██ ██  │
└──────────────┘       └──────────────┘
posted @ 2026-06-18 10:24  荒川之主  阅读(7)  评论(0)    收藏  举报