Matlab 簡單圖像分割實戰

一、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分類,不要被嚇到了,實現可能會難一點,但是超級容易理解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章