%% 实验二:图像分割
% 功能:实现基于阈值、形态学、边缘检测、区域生长的图像分割
% 使用内置函数 + 手动实现算法,包含预处理、后处理与结果可视化
% 作者:编程专家
clc; clear; close all;
%% 1. 读取并预处理图像
img = imread('coins.png'); % 自带图像,硬币在浅色背景上
% 转为灰度图(如果是彩色)
if size(img, 3) == 3
img_gray = rgb2gray(img);
else
img_gray = img;
end
% 预处理:中值滤波去除噪声(椒盐干扰),有助于后续分割
img_filtered = medfilt2(img_gray); % 中值滤波平滑
% 显示原始与滤波后图像对比
figure('Name', '图像分割实验', 'NumberTitle', 'off', 'Position', [100, 100, 1400, 900]);
subplot(4,5,1); imshow(img_gray); title('原始图像');
subplot(4,5,2); imshow(img_filtered); title('预处理:中值滤波');
%% 2. 全局阈值法分割
% a) 直接指定阈值
T_direct = 100;
bw_direct = img_filtered > T_direct;
subplot(4,5,3); imshow(bw_direct); title(['直接阈值 T=', num2str(T_direct)]);
% b) 基于直方图选择阈值
subplot(4,5,4); imhist(img_filtered); xlim([0 255]); title('灰度直方图');
T_hist = 120;
bw_hist = img_filtered > T_hist;
subplot(4,5,5); imshow(bw_hist); title(['直方图选阈值 T=', num2str(T_hist)]);
% c) OTSU 自动阈值法(最优类间方差)
T_otsu = graythresh(img_filtered); % 返回 [0,1] 归一化阈值
bw_otsu = imbinarize(img_filtered, T_otsu); % 推荐使用 imbinarize 替代 im2bw
subplot(4,5,6); imshow(bw_otsu); title(['OTSU自动阈值 T=', num2str(round(T_otsu*255))]);
%% 3. 形态学处理(开运算 + 闭运算)去噪与填充
se = strel('disk', 2); % 圆形结构元素,半径2
% 开运算:先腐蚀后膨胀,去除小颗粒噪声
bw_opened = imopen(bw_otsu, se);
subplot(4,5,7); imshow(bw_opened); title('形态学开运算去噪');
% 闭运算:先膨胀后腐蚀,填充内部空洞
bw_closed = imclose(bw_opened, se);
subplot(4,5,8); imshow(bw_closed); title('闭运算填充孔洞');
% 去除面积过小的连通区域(<30像素)
bw_clean = bwareaopen(bw_closed, 30);
subplot(4,5,9); imshow(bw_clean); title('去除小区域');
% 填充剩余孔洞(确保每个目标完整)
bw_final = imfill(bw_clean, 'holes');
subplot(4,5,10); imshow(bw_final); title('最终二值分割结果');
%% 4. 连通域标记(贴标签)
[labeled_img, numObjects] = bwlabel(bw_final);
subplot(4,5,11);
imshow(label2rgb(labeled_img, @jet, 'k', 'shuffle'));
title(['连通域标记 (共', num2str(numObjects), '个目标)']);
disp(['✅ 检测到 ', num2str(numObjects), ' 个独立物体']);
%% 5. 边缘检测分割(基于边界)
% 多种边缘算子比较
edge_canny = edge(img_filtered, 'canny');
subplot(4,5,12); imshow(edge_canny); title('Canny 边缘检测');
edge_sobel = edge(img_filtered, 'sobel');
subplot(4,5,13); imshow(edge_sobel); title('Sobel 边缘检测');
edge_log = edge(img_filtered, 'log', 0.5); % LoG: Laplacian of Gaussian
subplot(4,5,14); imshow(edge_log); title('LoG 边缘检测');
% 尝试从边缘重构分割区域(闭合边缘)
edge_filled = imfill(edge_canny, 'holes'); % 填充封闭轮廓
edge_seg = bwareaopen(edge_filled, 50); % 去除小碎片
subplot(4,5,15); imshow(edge_seg); title('边缘法重建分割');
%% 6. 区域生长分割(手动实现)
% 定义种子点(可通过 ginput 手动选取,此处固定示例)
seeds = [100, 200; % 硬币1中心附近
150, 100; % 硬币2
200, 250]; % 硬币3
region_threshold = 15; % 灰度差异容忍度(越大越容易扩展)
% 调用自定义区域生长函数
segmented_region = region_grow(img_filtered, seeds, region_threshold);
subplot(4,5,16); imshow(segmented_region); title('区域生长初始结果');
%% 7. 对区域生长结果进行修饰
se_small = strel('disk', 1);
cleaned_region = imopen(segmented_region, se_small); % 开运算去噪
filled_region = imfill(cleaned_region, 'holes'); % 填充内部空洞
refined_region = bwareaopen(filled_region, 50); % 去除太小区域
subplot(4,5,17); imshow(refined_region); title('修饰后区域生长结果');
%% 8. 分割结果叠加显示(融合原图与分割图)
% 方法1:颜色叠加(使用 label2rgb)
overlay_labels = label2rgb(labeled_img, 'hsv', 'k', 'shuffle');
subplot(4,5,18); imshowpair(img_gray, overlay_labels, 'blend'); title('分割结果叠加(颜色融合)');
% 方法2:轮廓叠加(更直观)
BW_edge = bwperim(bw_final); % 提取分割边界的像素
RGB_overlay = cat(3, double(img_gray)/255 + BW_edge, ...
double(img_gray)/255, ...
double(img_gray)/255); % 红色边缘
subplot(4,5,19); imshow(RGB_overlay); title('原图+红色分割轮廓');
%% 9. 阈值方法对比柱状图
ax = subplot(4,5,20);
bar(ax, [T_direct, T_hist, T_otsu*255], 'FaceColor', [0.2 0.6 1]);
set(ax, 'XTickLabel', {'直接', '直方图', 'Otsu'});
ylabel('阈值大小');
title('三种阈值比较');
grid on;
加入腐蚀膨胀
最新发布