Matlab 简单图像分割实战

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/qq_40515692/article/details/102749271

一、Matlab安装及题目

最近有一个数字图像处理的实验课,我们组准备选一个有关图像分割的题目。这里把我们组的一些思路及首先记录下。

首先自然是matlab的安装了,网上有很多的安装包,但是大部分都是百度网盘的,我超级不喜欢百度网盘。所以我直接给一个matlab7.0浏览器下载的链接:
https://dl.pconline.com.cn/download/360588.html

解压安装后,对于window10操作系统,请右键Matlab.exe文件,选择属性,兼容性,以兼容模式运行该程序:

在这里插入图片描述
Matlab7.0是比较老的版本了,没有自动补全等功能,如果是长期使用还是推荐取网上下载新版本。

然后题目如下:在这里插入图片描述

二、使用HSV色彩空间进行颜色阈值分割

一种简单的方法是使用颜色的数值不同进行划分,颜色相近的点分到一张图片里面,那么我们直接用RGB三通道划分吗?自然可以,但是我们先尽可能考虑简单情况吧(你也可以说我太菜 / W \)

三维的划分不容易,一维的容易不少,我们可以使用灰度图,然后弄出它的直方图再说。

不过可以注意到,我们要划分的图像,大都颜色近似。那么可以用一种可能更好的方式,这里我们就要介绍HSV色彩空间了。它如下图所示:

在这里插入图片描述在这里插入图片描述
这个模型中颜色的参数分别是:色调(H),饱和度(S),亮度(V)。
H用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°, 蓝色为240°。它们的补色是:黄色为60°,青色为180°, 品红为300°;

因为HSV非常符合人的观察模式,S和V通道对颜色的归类影响不太大,所以可以直接用H通道。

因此我们将原本的灰度图的直方图变成H通道的直方图。

这里我们先实现一个函数(请无视函数名),传入参数为图像I,
第一步、读取图片,得到h通道。
第二步、绘制HSV彩带方便对比查看。(可选)
第三步、计算频率,准备绘制直方图。
第四步、特殊处理,作用就是放大一些凸点。(可选)

function [hsv,res]=Untitled(I)
% 1.读取图片并转换为HSV图像模型
hsv = rgb2hsv(I);%RGB转hsv
h = hsv(:,:,1);
h = h(:)*360;	% 因为h通道为0-1,所以乘360

% 2.画hsv颜色分量
for i=1:360
    tempx = 1-abs(mod(i/60,2)-1);
    if i<60
        plot(i,0,'*','color',[1 tempx 0],'MarkerSize',20);
    elseif i<120
        plot(i,0,'*','color',[tempx 1 0],'MarkerSize',20);
    elseif i<180
        plot(i,0,'*','color',[0 1 tempx],'MarkerSize',20);
    elseif i<240
        plot(i,0,'*','color',[0 tempx 1],'MarkerSize',20);
    elseif i<300
        plot(i,0,'*','color',[tempx 0 1],'MarkerSize',20);
    else
        plot(i,0,'*','color',[1 0 tempx],'MarkerSize',20);
    end   
    hold all;
end

% 3.画hsv频率曲线
res = linspace(0,0,361);
for i=1:length(h)
    if res(round(h(i))+1) < 10000	% 限制一下
        res(round(h(i))+1) =  res(round(h(i))+1) + 1;
    end
end

% 4.特殊处理,放大odd像素
for i=2:360
    if res(i) > res(i+1)+700 && res(i) > res(i-1)+700
        res(i) = 5*res(i);
        if res(i) > 10000
            res(i) = 10000;
        end
    end
end

plot(res,'LineWidth', 2);
grid on;

记得文件名和函数名一致,然后我们来测试一下。
在command window输入下面的代码,选择图片,然后调用函数。

[fn,pn,fi]=uigetfile({'*.jpg;*.tif;*.png;*.gif;*.bmp','All Image Files';...
         '*.*','All Files' },'mytitle',...
         'C:\Work\myfile.jpg');
I = imread([pn fn]);
[hsv,res]=Untitled(I);

在这里插入图片描述
可以从直方图看到,明显看到这一张照片的绿色和蓝色还有红色比较多。我输入的图片如下:
在这里插入图片描述
之前的特殊处理的用处就是对于像蓝色这样的像素点比绿色少很多,所以对这样的像素放大。
这样我们就得到了一张直方图,怎么分呢?通过人眼,应该已经可以大致划几条竖线分割了吧。
比如这样(虽然有够难看的),分成四部分,那么用matlab怎么实现呢?
在这里插入图片描述

三、简单分割实现

一个简单的方法就是画一条横线,把超过这条横线的区间记录下来,根据这个区间进行划分。
我们再定义一个函数,传入上面函数得到的hsv,res以及一个阈值flag,我们那一条横线的值就是flag了。
第一步、根据设定的flag分类,获取区间传入res2中,就是计算那些我画的小红点了。
在这里插入图片描述
第二步、就是对区间相距太近的进行合并。
第三步、从左到右计算每一个区间右边界和下一个区间的左边界取中值。
比如:处理前的区间是0 1和30 31,那么就化为0 (1+30)/2和(1+30)/2 31,所以结果如下所示:
res2 =

 0     1
30    31
60    61
67    68
85    90

res2 =

 0    16
23    46
53    64
66    77
81   360

第四步、根据上面的结果绘制分割图。代码如下:

function []=Step2(hsv,res,flag)
temp_hsv = hsv;
% 1.根据设定的频率系数,分类,获取区间传入res2中
left = 0;
flag_temp = 0;  % 0表示还没有进入区间
res2 = [];
for i=1:length(res)
    if res(i) > flag
        if flag_temp == 0
            left = i;
            flag_temp = 1;
        end
    else 
        if flag_temp == 1
            res2 = [res2;left-1,i-1];
            flag_temp = 0;
        end
    end
end

% 间距小的合并
i = 1;
res3 = [];
while i<=length(res2(:,1))-1
    % 小于12的间隔进行合并
    temp_left = res2(i,1);
    while i<=length(res2(:,1))-1 && res2(i+1,1) - res2(i,2) < 5
        i=i+1;
    end
    res3 = [res3;temp_left,res2(i,2)];
    i=i+1;
end
res2 = res3;

% 取中值划分
for i=1:length(res2(:,1))
    if i==1
        res2(i,1) = 0;
        res2(i,2) = round((res2(i,2)+res2(i+1,1))/2);
    elseif i==length(res2(:,1))
        res2(i,1) = round((res2(i-1,2)+res2(i,1))/2);
        res2(i,2) = 360;
    else
        res2(i,1) = round((res2(i-1,2)+res2(i,1))/2);
        res2(i,2) = round((res2(i,2)+res2(i+1,1))/2);
    end
end

% 3. 开始分割
figure;
for i=1:length(res2(:,1))
    hsv = temp_hsv;
    temp_interval = res2(i,:);
    sum = 0;
    for row=1:length(hsv(:,1,:))
        for col=1:length(hsv(1,:,:))
            temp_num = round(hsv(row,col,1)*360);
            if temp_interval(1) <= temp_num && temp_num <= temp_interval(2)
                ;   % 选中的像素处理
            else
                hsv(row,col,1) = 0;     % 未选中像素处理,白色
                hsv(row,col,2) = 0;
                hsv(row,col,3) = 1;
            end
        end
    end
    NEW = hsv2rgb(hsv);
    % subplot(1,length(res2(:,1)),i);
    figure(i); 
    imshow(NEW);
end

结果如下,虽然还是不太理想,但是还阔以:
在这里插入图片描述
那有没有更好的方法呢?答案是有的,下一篇文章讲解OpenCv方法实现图像分割,用到的技术是超像素SLIC方法、kmean分类,不要被吓到了,实现可能会难一点,但是超级容易理解。

猜你喜欢

转载自blog.csdn.net/qq_40515692/article/details/102749271