图像分割是将图像划分为若干个具有不同特征的区域(如前景/背景、目标/背景)的核心技术,MATLAB的Image Processing Toolbox提供了丰富的分割函数,覆盖阈值分割、边缘分割、区域分割、聚类分割等主流方法。
一、图像分割基础准备
1. 核心概念与数据准备
- 分割目标:将图像中感兴趣的目标(如硬币、车牌、细胞)从背景中分离;
- 图像类型:优先使用灰度图(二维矩阵)进行分割,RGB图需先转换为灰度图;
- 预处理:分割前通常需去噪(中值滤波、高斯滤波)、增强对比度(直方图均衡化),提升分割效果。
matlab
% 基础准备:读取图像并预处理
img = imread('coins.png'); % 读取MATLAB内置灰度图(硬币示例)
img = im2double(img); % 转换为double型(便于计算)
% 预处理:去噪+对比度增强
img_denoise = medfilt2(img, [3 3]); % 3×3中值滤波去噪
img_enhance = adapthisteq(img_denoise); % CLAHE对比度增强
% 显示预处理结果
figure;
subplot(1,2,1); imshow(img); title('原始图像');
subplot(1,2,2); imshow(img_enhance); title('预处理后图像');
二、基础分割:阈值分割(最常用)
阈值分割是通过设定灰度值阈值,将图像分为"大于阈值"和"小于阈值"两部分,适合目标与背景灰度差异明显的场景(如黑白对比强烈的图像)。
1. 手动阈值分割
适用于已知目标/背景灰度范围的场景,手动调整阈值实现分割。
matlab
% 手动设定阈值(0.4,需根据图像灰度范围调整)
threshold = 0.4;
img_binary = img_enhance > threshold; % 二值化:大于阈值为1(白色),小于为0(黑色)
% 显示分割结果
figure;
subplot(1,2,1); imshow(img_enhance); title('预处理图像');
subplot(1,2,2); imshow(img_binary); title('手动阈值分割(阈值=0.4)');
2. 自动阈值分割(Otsu方法,推荐)
MATLAB内置graythresh函数实现Otsu算法,自动计算最优阈值(适合双峰灰度直方图的图像)。
matlab
% 步骤1:计算最优阈值
level = graythresh(img_enhance); % 输出0-1之间的归一化阈值
fprintf('Otsu自动计算的阈值:%.4f\n', level);
% 步骤2:二值化分割
img_otsu = imbinarize(img_enhance, level);
% 步骤3:形态学操作优化(去除小噪点、填补孔洞)
se = strel('disk', 2); % 2×2圆盘结构元素
img_otsu_clean = imopen(img_otsu, se); % 开运算(先腐蚀后膨胀,去除小噪点)
img_otsu_clean = imfill(img_otsu_clean, 'holes'); % 填补孔洞
% 对比分割效果
figure;
subplot(1,3,1); imshow(img_enhance); title('预处理图像');
subplot(1,3,2); imshow(img_otsu); title('Otsu原始分割');
subplot(1,3,3); imshow(img_otsu_clean); title('形态学优化后');
3. 自适应阈值分割(应对光照不均)
当图像光照不均(如局部亮、局部暗)时,全局阈值分割效果差,使用adaptthresh实现局部自适应阈值。
matlab
% 自适应阈值分割(窗口大小15×15,偏移量0.05)
level_adapt = adaptthresh(img_enhance, 0.05, 'NeighborhoodSize', 15);
img_adapt = imbinarize(img_enhance, level_adapt);
% 显示效果(对比全局Otsu)
figure;
subplot(1,2,1); imshow(img_otsu_clean); title('全局Otsu分割');
subplot(1,2,2); imshow(img_adapt); title('自适应阈值分割');
三、边缘基分割:基于边缘检测的分割
通过检测图像边缘(灰度突变处)实现分割,适合目标轮廓清晰的场景,核心使用edge函数结合Canny/Sobel算子。
matlab
% 步骤1:边缘检测(Canny算子,最优边缘检测效果)
edges_canny = edge(img_enhance, 'canny', [0.1, 0.3]); % 高低阈值0.1/0.3
% 步骤2:边缘连接与闭合(形态学膨胀)
se = strel('line', 3, 0); % 3像素线结构元素
edges_dilate = imdilate(edges_canny, se); % 膨胀连接断裂边缘
% 步骤3:填充边缘包围的区域(得到分割结果)
img_edge_seg = imfill(edges_dilate, 'holes');
% 显示边缘分割流程
figure;
subplot(1,3,1); imshow(edges_canny); title('Canny边缘检测');
subplot(1,3,2); imshow(edges_dilate); title('边缘膨胀连接');
subplot(1,3,3); imshow(img_edge_seg); title('边缘分割结果');
四、区域基分割:区域生长与连通域分析
1. 区域生长分割
从种子点出发,将灰度相似的像素合并为一个区域,适合目标区域灰度均匀的场景。
matlab
% 步骤1:选择种子点(手动选1个硬币的中心像素)
% 先显示图像,点击选择种子点坐标
figure; imshow(img_enhance); title('点击选择种子点');
[x, y] = ginput(1); % 手动点击获取坐标
seed_x = round(x); % 取整
seed_y = round(y);
fprintf('选择的种子点坐标:(%d, %d)\n', seed_x, seed_y);
% 步骤2:区域生长(灰度差阈值5)
img_region = regiongrowing(img_enhance, seed_x, seed_y, 5); % 自定义区域生长函数
% 自定义区域生长函数(核心)
function J = regiongrowing(I, x, y, t)
[M, N] = size(I);
J = zeros(M, N); % 初始化分割结果
J(y, x) = 1; % 标记种子点
seed_val = I(y, x); % 种子点灰度值
queue = [y, x]; % 队列存储待扩展像素
% 4邻域扩展
dirs = [[-1,0], [1,0], [0,-1], [0,1]];
while ~isempty(queue)
% 取出队列首像素
curr_y = queue(1,1);
curr_x = queue(1,2);
queue(1,:) = [];
% 遍历4邻域
for d = 1:4
ny = curr_y + dirs(d,1);
nx = curr_x + dirs(d,2);
% 检查坐标是否在图像内,且未被标记,且灰度差小于阈值
if ny >= 1 && ny <= M && nx >= 1 && nx <= N && J(ny, nx) == 0 && abs(I(ny, nx) - seed_val) < t
J(ny, nx) = 1;
queue = [queue; ny, nx];
end
end
end
J = logical(J); % 转换为逻辑型
end
% 显示区域生长结果
figure;
subplot(1,2,1); imshow(img_enhance); hold on; plot(seed_x, seed_y, 'r*', 'MarkerSize', 10); title('种子点位置');
subplot(1,2,2); imshow(img_region); title('区域生长分割结果');
2. 连通域分析(分割多个目标)
对二值化图像进行连通域标记,提取每个目标的区域特征(面积、中心、边界框),适合多目标分割。
matlab
% 基于Otsu分割后的图像进行连通域分析
[L, num] = bwlabel(img_otsu_clean); % L为标记矩阵,num为连通域数量
fprintf('检测到的连通域数量:%d\n', num);
% 提取连通域特征(中心、面积、边界框)
stats = regionprops(L, 'Centroid', 'Area', 'BoundingBox');
% 绘制连通域标记结果
img_labeled = imlabeloverlay(img_enhance, L); % 叠加标记到原图
figure; imshow(img_labeled); title(sprintf('连通域分割(共%d个目标)', num));
% 绘制每个目标的边界框
hold on;
for i = 1:num
bbox = stats(i).BoundingBox;
rectangle('Position', bbox, 'EdgeColor', 'r', 'LineWidth', 2);
end
hold off;
% 筛选面积大于100的目标(去除小噪点)
min_area = 100;
img_filtered = ismember(L, find([stats.Area] > min_area));
figure; imshow(img_filtered); title('筛选后分割结果(面积>100)');
五、高级分割:K-Means聚类分割(适合彩色图像)
K-Means聚类分割无需设定阈值,通过聚类将像素分为K类(如前景/背景),适合彩色图像或灰度分布复杂的图像。
matlab
% 以彩色图像为例(MATLAB内置peppers.jpg)
img_rgb = imread('peppers.jpg');
img_rgb = im2double(img_rgb);
% 步骤1:将图像转换为像素向量(行×列,3通道)
[M, N, C] = size(img_rgb);
img_vec = reshape(img_rgb, M*N, C); % 转换为(M*N)×3的矩阵
% 步骤2:K-Means聚类(K=2,分为前景/背景)
k = 2;
[idx, centers] = kmeans(img_vec, k); % idx为每个像素的聚类标签,centers为聚类中心
% 步骤3:重构分割图像
img_kmeans = reshape(idx, M, N); % 转换回图像尺寸
img_kmeans = imbinarize(img_kmeans, 1.5); % 转换为二值图(1类为背景,2类为前景)
% 显示K-Means分割结果
figure;
subplot(1,2,1); imshow(img_rgb); title('原始彩色图像');
subplot(1,2,2); imshow(img_kmeans); title('K-Means聚类分割(K=2)');
六、分割效果评估(可选)
通过交集并集比(IoU) 评估分割精度(需有标注的真实分割图),无标注时可通过视觉对比+连通域特征判断。
matlab
% 假设mask_true为真实分割标签(二值图),mask_pred为预测分割结果
% IoU = 交集面积 / 并集面积
% 以Otsu分割结果为例,模拟真实标签(取前5个硬币为真实目标)
mask_true = false(size(img_otsu_clean));
mask_true(10:80, 10:80) = true; % 模拟真实目标区域
mask_pred = img_otsu_clean;
% 计算IoU
intersection = sum(sum(mask_true & mask_pred));
union = sum(sum(mask_true | mask_pred));
iou = intersection / union;
fprintf('分割IoU:%.4f\n', iou);
七、常见问题与避坑指南
| 问题现象 | 核心原因 | 解决方案 |
|---|---|---|
| 阈值分割结果有大量噪点 | 图像未去噪/阈值设置不当 | 先中值滤波去噪,使用Otsu自动阈值替代手动阈值 |
| 边缘分割轮廓断裂 | 边缘检测阈值过高/图像噪声多 | 降低Canny算子低阈值,先做高斯滤波平滑图像 |
| 区域生长分割漏检目标 | 种子点选择不当/灰度阈值太小 | 选择目标中心像素作为种子点,适当增大灰度差阈值 |
| K-Means分割结果混乱 | K值设置错误/未归一化像素值 | 先将像素值归一化到0-1,通过试错确定最优K值(如K=2/3) |
| 连通域数量过多 | 二值图有小噪点/孔洞 | 形态学开运算去除小噪点,imfill填补孔洞后再做连通域分析 |