基于深度学习的图像分割MATLAB实现

简介: 基于深度学习的图像分割MATLAB程序,使用U-Net架构实现语义分割任务

基于深度学习的图像分割MATLAB程序,使用U-Net架构实现语义分割任务

%% 基于深度学习的图像分割 - U-Net实现
% 描述: 使用U-Net架构进行图像分割的完整实现

%% 清理工作区
clear; close all; clc;

%% 1. 数据准备
% 使用内置的硬币图像作为示例数据
img = imread('coins.png');
groundTruth = imread('coins.png'); % 实际应用中应使用真实标注

% 显示原始图像和标注
figure;
subplot(1,2,1); imshow(img); title('原始图像');
subplot(1,2,2); imshow(groundTruth); title('人工标注');

% 创建模拟数据集(实际应用中应使用真实数据集)
dataSet = createSyntheticDataset(10, [256, 256]);

% 划分训练集和测试集
[trainData, testData] = splitData(dataSet, 0.8);

% 创建数据存储
imds = imageDatastore({
   trainData.images}, 'Labels', {
   });
pxds = pixelLabelDatastore({
   trainData.masks}, {
   'Background', 'Object'}, [0 1]);

% 数据增强
augmenter = imageDataAugmenter(...
    'RandRotation', [-20, 20], ...
    'RandXTranslation', [-10, 10], ...
    'RandYTranslation', [-10, 10], ...
    'RandXScale', [0.8, 1.2], ...
    'RandYScale', [0.8, 1.2], ...
    'RandYReflection', true);

% 创建增强后的数据存储
augImds = augmentedImageDatastore([256, 256], imds);
augPxds = pixelLabelImageDatastore(pxds, augmentedImageDatastore([256, 256]));

%% 2. 构建U-Net网络
inputSize = [256, 256, 1]; % 输入图像尺寸
numClasses = 2; % 类别数(背景+目标)

% 使用MATLAB的U-Net实现
lgraph = unetLayers(inputSize, numClasses, 'EncoderDepth', 4);

% 自定义U-Net实现(可选)
% lgraph = buildCustomUNet(inputSize, numClasses);

% 显示网络结构
analyzeNetwork(lgraph);

%% 3. 设置训练选项
options = trainingOptions('adam', ...
    'InitialLearnRate', 1e-3, ...
    'MaxEpochs', 30, ...
    'MiniBatchSize', 4, ...
    'Shuffle', 'every-epoch', ...
    'ValidationData', {
   testData.images, testData.masks}, ...
    'ValidationFrequency', 30, ...
    'Verbose', true, ...
    'Plots', 'training-progress', ...
    'ExecutionEnvironment', 'auto'); % 自动选择CPU/GPU

%% 4. 训练网络
[net, info] = trainNetwork(augImds, augPxds, lgraph, options);

%% 5. 评估模型
% 在测试集上进行预测
predMasks = classifyPixels(net, testData.images);

% 计算性能指标
metrics = evaluateSegmentation(predMasks, testData.masks);

% 显示评估结果
disp('===== 分割性能评估 =====');
disp(['准确率(Accuracy): ', num2str(metrics.Accuracy)]);
disp(['精确率(Precision): ', num2str(metrics.Precision)]);
disp(['召回率(Recall): ', num2str(metrics.Recall)]);
disp(['F1分数(F1-score): ', num2str(metrics.F1score)]);
disp(['IoU(Jaccard Index): ', num2str(metrics.IoU)]);

%% 6. 可视化结果
visualizeResults(testData.images, testData.masks, predMasks);

%% 7. 保存模型
save('segmentationModel.mat', 'net');

%% 辅助函数定义

function dataset = createSyntheticDataset(numImages, imgSize)
    % 创建合成数据集用于演示
    dataset = struct('images', {
   }, 'masks', {
   });

    for i = 1:numImages
        % 创建随机形状
        img = randi([200, 255], imgSize, 'uint8');
        mask = false(imgSize);

        % 添加圆形
        centerX = randi([50, imgSize(2)-50]);
        centerY = randi([50, imgSize(1)-50]);
        radius = randi([20, 40]);
        [x, y] = meshgrid(1:imgSize(2), 1:imgSize(1));
        circle = (x - centerX).^2 + (y - centerY).^2 <= radius^2;
        mask = mask | circle;

        % 添加矩形
        rectW = randi([30, 60]);
        rectH = randi([30, 60]);
        rectX = randi([10, imgSize(2)-rectW-10]);
        rectY = randi([10, imgSize(1)-rectH-10]);
        rect = false(imgSize);
        rect(rectY:rectY+rectH, rectX:rectX+rectW) = true;
        mask = mask | rect;

        % 添加三角形
        triX = [randi([20, imgSize(2)-20]), randi([20, imgSize(2)-20]), randi([20, imgSize(2)-20])];
        triY = [randi([20, imgSize(1)-20]), randi([20, imgSize(1)-20]), randi([20, imgSize(1)-20])];
        tri = poly2mask(triX, triY, imgSize(1), imgSize(2));
        mask = mask | tri;

        % 添加噪声
        noise = randi([0, 50], imgSize, 'uint8');
        img = img - noise;
        img = max(0, min(255, img));

        % 应用形状到图像
        imgR = img;
        imgG = img;
        imgB = img;
        imgR(mask) = 255;
        imgG(mask) = 0;
        imgB(mask) = 0;
        img = cat(3, imgR, imgG, imgB);

        % 二值化掩码
        mask = uint8(mask) * 255;

        % 添加到数据集
        dataset(i).images = img;
        dataset(i).masks = mask;
    end
end

function [trainData, testData] = splitData(dataset, trainRatio)
    % 划分训练集和测试集
    numImages = length(dataset);
    numTrain = round(numImages * trainRatio);

    indices = randperm(numImages);
    trainIndices = indices(1:numTrain);
    testIndices = indices(numTrain+1:end);

    trainData = struct('images', {
   }, 'masks', {
   });
    testData = struct('images', {
   }, 'masks', {
   });

    for i = 1:numTrain
        trainData(i).images = dataset(trainIndices(i)).images;
        trainData(i).masks = dataset(trainIndices(i)).masks;
    end

    for i = 1:(numImages - numTrain)
        testData(i).images = dataset(testIndices(i)).images;
        testData(i).masks = dataset(testIndices(i)).masks;
    end
end

function lgraph = buildCustomUNet(inputSize, numClasses)
    % 自定义U-Net实现
    layers = [
        % 编码器路径
        imageInputLayer(inputSize, 'Name', 'input')

        % 第一级下采样
        convolution2dLayer(3, 64, 'Padding', 'same', 'Name', 'conv1_1')
        batchNormalizationLayer('Name', 'bn1_1')
        reluLayer('Name', 'relu1_1')
        convolution2dLayer(3, 64, 'Padding', 'same', 'Name', 'conv1_2')
        batchNormalizationLayer('Name', 'bn1_2')
        reluLayer('Name', 'relu1_2')
        maxPooling2dLayer(2, 'Stride', 2, 'Name', 'pool1')

        % 第二级下采样
        convolution2dLayer(3, 128, 'Padding', 'same', 'Name', 'conv2_1')
        batchNormalizationLayer('Name', 'bn2_1')
        reluLayer('Name', 'relu2_1')
        convolution2dLayer(3, 128, 'Padding', 'same', 'Name', 'conv2_2')
        batchNormalizationLayer('Name', 'bn2_2')
        reluLayer('Name', 'relu2_2')
        maxPooling2dLayer(2, 'Stride', 2, 'Name', 'pool2')

        % 第三级下采样
        convolution2dLayer(3, 256, 'Padding', 'same', 'Name', 'conv3_1')
        batchNormalizationLayer('Name', 'bn3_1')
        reluLayer('Name', 'relu3_1')
        convolution2dLayer(3, 256, 'Padding', 'same', 'Name', 'conv3_2')
        batchNormalizationLayer('Name', 'bn3_2')
        reluLayer('Name', 'relu3_2')
        maxPooling2dLayer(2, 'Stride', 2, 'Name', 'pool3')

        % 第四级下采样
        convolution2dLayer(3, 512, 'Padding', 'same', 'Name', 'conv4_1')
        batchNormalizationLayer('Name', 'bn4_1')
        reluLayer('Name', 'relu4_1')
        convolution2dLayer(3, 512, 'Padding', 'same', 'Name', 'conv4_2')
        batchNormalizationLayer('Name', 'bn4_2')
        reluLayer('Name', 'relu4_2')
        maxPooling2dLayer(2, 'Stride', 2, 'Name', 'pool4')

        % 底部
        convolution2dLayer(3, 1024, 'Padding', 'same', 'Name', 'conv5_1')
        batchNormalizationLayer('Name', 'bn5_1')
        reluLayer('Name', 'relu5_1')
        convolution2dLayer(3, 1024, 'Padding', 'same', 'Name', 'conv5_2')
        batchNormalizationLayer('Name', 'bn5_2')
        reluLayer('Name', 'relu5_2')

        % 解码器路径
        transposedConv2dLayer(2, 512, 'Stride', 2, 'Name', 'upconv4')
        concatenationLayer(3, 2, 'Name', 'concat4')
        convolution2dLayer(3, 512, 'Padding', 'same', 'Name', 'conv_up4_1')
        batchNormalizationLayer('Name', 'bn_up4_1')
        reluLayer('Name', 'relu_up4_1')
        convolution2dLayer(3, 512, 'Padding', 'same', 'Name', 'conv_up4_2')
        batchNormalizationLayer('Name', 'bn_up4_2')
        reluLayer('Name', 'relu_up4_2')

        transposedConv2dLayer(2, 256, 'Stride', 2, 'Name', 'upconv3')
        concatenationLayer(3, 2, 'Name', 'concat3')
        convolution2dLayer(3, 256, 'Padding', 'same', 'Name', 'conv_up3_1')
        batchNormalizationLayer('Name', 'bn_up3_1')
        reluLayer('Name', 'relu_up3_1')
        convolution2dLayer(3, 256, 'Padding', 'same', 'Name', 'conv_up3_2')
        batchNormalizationLayer('Name', 'bn_up3_2')
        reluLayer('Name', 'relu_up3_2')

        transposedConv2dLayer(2, 128, 'Stride', 2, 'Name', 'upconv2')
        concatenationLayer(3, 2, 'Name', 'concat2')
        convolution2dLayer(3, 128, 'Padding', 'same', 'Name', 'conv_up2_1')
        batchNormalizationLayer('Name', 'bn_up2_1')
        reluLayer('Name', 'relu_up2_1')
        convolution2dLayer(3, 128, 'Padding', 'same', 'Name', 'conv_up2_2')
        batchNormalizationLayer('Name', 'bn_up2_2')
        reluLayer('Name', 'relu_up2_2')

        transposedConv2dLayer(2, 64, 'Stride', 2, 'Name', 'upconv1')
        concatenationLayer(3, 2, 'Name', 'concat1')
        convolution2dLayer(3, 64, 'Padding', 'same', 'Name', 'conv_up1_1')
        batchNormalizationLayer('Name', 'bn_up1_1')
        reluLayer('Name', 'relu_up1_1')
        convolution2dLayer(3, 64, 'Padding', 'same', 'Name', 'conv_up1_2')
        batchNormalizationLayer('Name', 'bn_up1_2')
        reluLayer('Name', 'relu_up1_2')

        % 输出层
        convolution2dLayer(1, numClasses, 'Name', 'output_conv')
        softmaxLayer('Name', 'softmax')
        pixelClassificationLayer('Name', 'output')
    ];

    % 连接跳跃连接
    lgraph = layerGraph(layers);

    lgraph = connectLayers(lgraph, 'relu1_2', 'concat1/in2');
    lgraph = connectLayers(lgraph, 'relu2_2', 'concat2/in2');
    lgraph = connectLayers(lgraph, 'relu3_2', 'concat3/in2');
    lgraph = connectLayers(lgraph, 'relu4_2', 'concat4/in2');
end

function predMasks = classifyPixels(net, images)
    % 使用训练好的网络进行像素分类
    numImages = length(images);
    predMasks = cell(1, numImages);

    for i = 1:numImages
        img = images{
   i};
        if size(img, 3) == 3
            img = rgb2gray(img);
        end
        img = im2single(img);
        img = imresize(img, [256, 256]);
        img = cat(3, img, img, img); % 转换为3通道

        % 预测
        pred = semanticseg(img, net, 'MiniBatchSize', 1);
        predMasks{
   i} = pred;
    end
end

function metrics = evaluateSegmentation(predMasks, trueMasks)
    % 评估分割性能
    numImages = length(predMasks);
    confMat = zeros(2, 2); % 二分类混淆矩阵

    for i = 1:numImages
        predMask = predMasks{
   i};
        trueMask = trueMasks{
   i};

        % 二值化掩码
        predBin = predMask > 0.5;
        trueBin = trueMask > 128;

        % 计算混淆矩阵
        tp = sum(sum(predBin & trueBin));
        fp = sum(sum(predBin & ~trueBin));
        fn = sum(sum(~predBin & trueBin));
        tn = sum(sum(~predBin & ~trueBin));

        confMat(1,1) = confMat(1,1) + tp;
        confMat(1,2) = confMat(1,2) + fp;
        confMat(2,1) = confMat(2,1) + fn;
        confMat(2,2) = confMat(2,2) + tn;
    end

    % 计算指标
    accuracy = (confMat(1,1) + confMat(2,2)) / sum(confMat(:));
    precision = confMat(1,1) / (confMat(1,1) + confMat(1,2));
    recall = confMat(1,1) / (confMat(1,1) + confMat(2,1));
    f1score = 2 * (precision * recall) / (precision + recall);
    iou = confMat(1,1) / (confMat(1,1) + confMat(1,2) + confMat(2,1));

    % 返回结果
    metrics = struct(...
        'Accuracy', accuracy, ...
        'Precision', precision, ...
        'Recall', recall, ...
        'F1score', f1score, ...
        'IoU', iou, ...
        'ConfusionMatrix', confMat);
end

function visualizeResults(images, trueMasks, predMasks)
    % 可视化分割结果
    numImages = min(4, length(images)); % 最多显示4张图像

    figure('Position', [100, 100, 1200, 800]);
    for i = 1:numImages
        % 原始图像
        subplot(numImages, 3, (i-1)*3+1);
        imshow(images{
   i});
        title(sprintf('原始图像 %d', i));

        % 真实掩码
        subplot(numImages, 3, (i-1)*3+2);
        imshow(trueMasks{
   i});
        title('真实掩码');

        % 预测掩码
        subplot(numImages, 3, (i-1)*3+3);
        imshow(labeloverlay(im2double(images{
   i}), predMasks{
   i}));
        title('预测掩码');
    end

    % 单独显示预测结果
    figure;
    for i = 1:numImages
        subplot(2, numImages, i);
        imshow(images{
   i});
        title(sprintf('原始图像 %d', i));

        subplot(2, numImages, numImages+i);
        imshow(label2rgb(predMasks{
   i}));
        title(sprintf('预测结果 %d', i));
    end
end

程序功能说明

1. 数据准备模块

  • 合成数据生成createSyntheticDataset函数创建带有随机形状的合成图像数据集
  • 数据划分splitData函数将数据划分为训练集和测试集
  • 数据增强:使用imageDataAugmenter进行随机旋转、平移和缩放

2. 网络构建模块

  • U-Net实现:提供两种U-Net实现方式
    • 使用MATLAB内置的unetLayers函数
    • 自定义U-Net实现buildCustomUNet
  • 网络结构:编码器-解码器结构,包含跳跃连接

3. 训练配置模块

  • 训练选项:使用Adam优化器,设置学习率、批次大小等参数
  • 硬件加速:自动选择CPU或GPU进行训练

4. 评估与可视化模块

  • 性能评估evaluateSegmentation计算准确率、精确率、召回率等指标
  • 结果可视化visualizeResults显示原始图像、真实掩码和预测掩码

深度学习图像分割关键技术

1. U-Net架构

U-Net是一种专为生物医学图像分割设计的卷积神经网络,其特点包括:

  • 对称的编码器-解码器结构
  • 跳跃连接融合低级和高级特征
  • 适用于小样本数据集

2. 损失函数

本程序使用交叉熵损失函数,适用于多类分割任务:

download.png

其中 $y_i,c$是真实标签,$p_i,c$是预测概率

3. 数据增强

为增加数据多样性,提高模型泛化能力,采用以下增强技术:

  • 随机旋转(-20°到20°)
  • 随机平移(±10像素)
  • 随机缩放(0.8-1.2倍)
  • 随机水平翻转

参考代码 利用深度学习的matlab程序编码仿真实现图像分割 www.youwenfan.com/contentalh/95829.html

实际应用扩展

1. 使用真实数据集

% 加载真实数据集(示例)
data = load('CamVid.mat'); % CamVid道路场景数据集
images = data.images;
labels = data.labels;

% 创建数据存储
imds = imageDatastore(images);
pxds = pixelLabelDatastore(labels, categories, labelIDs);

2. 迁移学习

% 加载预训练模型
pretrainedNet = resnet50;

% 修改最后几层
lgraph = layerGraph(pretrainedNet);
newLayers = [
    convolution2dLayer(1, 64, 'Name', 'new_conv1')
    reluLayer('Name', 'new_relu1')
    transposedConv2dLayer(2, 32, 'Stride', 2, 'Name', 'new_upconv1')
    convolution2dLayer(3, 32, 'Padding', 'same', 'Name', 'new_conv2')
    reluLayer('Name', 'new_relu2')
    convolution2dLayer(1, numClasses, 'Name', 'final_conv')
    softmaxLayer('Name', 'softmax')
    pixelClassificationLayer('Name', 'output')
];

lgraph = replaceLayer(lgraph, 'fc1000', newLayers);

3. 多类分割

% 设置多类分割参数
numClasses = 5; % 例如:背景、道路、车辆、行人、建筑
classNames = {
   'Background', 'Road', 'Vehicle', 'Pedestrian', 'Building'};
labelIDs = [0, 1, 2, 3, 4];

% 修改输出层
outputLayer = pixelClassificationLayer('Name', 'output', ...
    'ClassNames', classNames, ...
    'OutputSize', numClasses);

4. 3D图像分割(医学影像)

% 使用3D U-Net进行体积分割
inputSize = [128, 128, 64, 1]; % 高度、宽度、深度、通道
lgraph = unet3dLayers(inputSize, numClasses);

% 训练3D网络
options = trainingOptions('adam', ...
    'MaxEpochs', 20, ...
    'MiniBatchSize', 1, ... % 3D网络需要更小的批次
    'Plots', 'training-progress');

net = trainNetwork(volumeData, lgraph, options);

性能优化技巧

  1. 混合精度训练

    options = trainingOptions('adam', ...
        'GradientDataType', 'single', ...
        'GradientDecayFactor', 0.9, ...
        'SquaredGradientDecayFactor', 0.999);
    
  2. 学习率调度

    options = trainingOptions('adam', ...
        'LearnRateSchedule', 'piecewise', ...
        'LearnRateDropPeriod', 10, ...
        'LearnRateDropFactor', 0.1);
    
  3. 模型量化

    % 训练后量化模型
    quantizedNet = quantize(net, 'Method', 'Linear');
    
  4. 硬件加速

    • 使用GPU加速:'ExecutionEnvironment', 'gpu'
    • 多GPU训练:'ExecutionEnvironment', 'multi-gpu'

常见问题解决方案

  1. 内存不足
    • 减小批次大小
    • 降低图像分辨率
    • 使用梯度累积
  2. 训练不稳定
    • 添加批归一化层
    • 使用学习率预热
    • 添加正则化(Dropout)
  3. 过拟合
    • 增加数据增强强度
    • 添加Dropout层
    • 使用早停策略
  4. 分割边界不精确
    • 使用CRF后处理
    • 添加边缘感知损失
    • 使用注意力机制

结论

本程序提供了一个完整的基于深度学习的图像分割解决方案,具有以下特点:

  1. 实现了经典的U-Net架构
  2. 包含数据准备、网络训练、评估和可视化全流程
  3. 支持合成数据生成和真实数据应用
  4. 提供多种扩展选项(多类分割、3D分割、迁移学习等)
相关文章
|
存储 缓存 文件存储
如何保证分布式文件系统的数据一致性
分布式文件系统需要向上层应用提供透明的客户端缓存,从而缓解网络延时现象,更好地支持客户端性能水平扩展,同时也降低对文件服务器的访问压力。当考虑客户端缓存的时候,由于在客户端上引入了多个本地数据副本(Replica),就相应地需要提供客户端对数据访问的全局数据一致性。
32699 79
如何保证分布式文件系统的数据一致性
|
前端开发 容器
HTML5+CSS3前端入门教程---从0开始通过一个商城实例手把手教你学习PC端和移动端页面开发第8章FlexBox布局(上)
HTML5+CSS3前端入门教程---从0开始通过一个商城实例手把手教你学习PC端和移动端页面开发第8章FlexBox布局
17754 20
|
设计模式 存储 监控
设计模式(C++版)
看懂UML类图和时序图30分钟学会UML类图设计原则单一职责原则定义:单一职责原则,所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。而单一职责原则就是指一个类或者模块应该有且只有一个改变的原因。bad case:IPhone类承担了协议管理(Dial、HangUp)、数据传送(Chat)。good case:里式替换原则定义:里氏代换原则(Liskov 
36685 19
设计模式(C++版)
|
存储 编译器 C语言
抽丝剥茧C语言(初阶 下)(下)
抽丝剥茧C语言(初阶 下)
|
机器学习/深度学习 人工智能 自然语言处理
带你简单了解Chatgpt背后的秘密:大语言模型所需要条件(数据算法算力)以及其当前阶段的缺点局限性
带你简单了解Chatgpt背后的秘密:大语言模型所需要条件(数据算法算力)以及其当前阶段的缺点局限性
24760 14
|
机器学习/深度学习 弹性计算 监控
重生之---我测阿里云U1实例(通用算力型)
阿里云产品全线降价的一力作,2023年4月阿里云推出新款通用算力型ECS云服务器Universal实例,该款服务器的真实表现如何?让我先测为敬!
36663 15
重生之---我测阿里云U1实例(通用算力型)
|
SQL 存储 弹性计算
Redis性能高30%,阿里云倚天ECS性能摸底和迁移实践
Redis在倚天ECS环境下与同规格的基于 x86 的 ECS 实例相比,Redis 部署在基于 Yitian 710 的 ECS 上可获得高达 30% 的吞吐量优势。成本方面基于倚天710的G8y实例售价比G7实例低23%,总性价比提高50%;按照相同算法,相对G8a,性价比为1.4倍左右。
|
存储 算法 Java
【分布式技术专题】「分布式技术架构」手把手教你如何开发一个属于自己的限流器RateLimiter功能服务
随着互联网的快速发展,越来越多的应用程序需要处理大量的请求。如果没有限制,这些请求可能会导致应用程序崩溃或变得不可用。因此,限流器是一种非常重要的技术,可以帮助应用程序控制请求的数量和速率,以保持稳定和可靠的运行。
29838 52

热门文章

最新文章

下一篇
开通oss服务