1. 程式人生 > 其它 >【影象分割】基於matlab超畫素影象分割【含Matlab原始碼 720期】

【影象分割】基於matlab超畫素影象分割【含Matlab原始碼 720期】

一、簡介

1 概念
超畫素由一系列位置相鄰且顏色、亮度、紋理等特徵相似的畫素點組成的小區域。這些小區域大多保留了進一步進行影象分割的有效資訊,且一般不會破壞影象中物體的邊界資訊。
超畫素是吧一幅畫素級(pixel-level)的圖,劃分成區域級(district-level)的圖,是對基本資訊元素進行的抽象。

(a)是原始影象,(b)是基於人類視角的分割圖(groundtruth),(c)是超畫素分割的影象,(d)是基於(c)進行分割的影象。
超畫素最大的功能之一是作為影象處理其他演算法的預處理,在不犧牲太大精確度的情況下降維。
超畫素最直觀的解釋是把一些具有相似特性的畫素“聚合”起來,形成一個更具有代表性的大“元素”。而這個新元素,將作為其他影象處理演算法的基本單位。這樣可以降低維度,剔除一些異常畫素點。
理論上,任何影象分割演算法的過度分割(over-segmentation)即可生成超畫素。
影象分割中的超畫素是指具有相似紋理、顏色、亮度等特徵的相鄰相似構成的具有一定意義的不規則的畫素塊。它利用畫素之間特徵的相似性將畫素分組,用少量的超畫素代替大量的畫素來表達影象特徵,很大程度上降低了影象處理的複雜度,所以通常作為分割演算法的預處理步驟。

2 超畫素判別條件
(1)Undersegmentation Error

(2)如上圖所示,白色是影象中的一個物體,紅線是一個個超畫素的輪廓,而粉紅色的區域就是undersegmentation區域,這部分割槽域越大越不好。
Boundary Recall

如上圖所示,黑色虛線及實線是影象中物體的輪廓,紅線是超畫素的邊界。一個好的超畫素演算法,應該覆蓋影象中物體的輪廓。在給予一定緩衝(粉紅色區域)的情況下,超畫素邊緣可以覆蓋影象物體邊緣(黑色實線)越多越好。
(3)Compactness score
衡量超畫素是否“緊實”。

3 超畫素初始化的方法
種子畫素初始化
SLIC利用了簡單的聚類(貪婪)演算法,初始時,每一個聚類的中心被平均的分佈在影象中,而超畫素的個數,可以基本由這些中心點來決定。每一步迭代,種子畫素合併周圍的畫素,形成超畫素。

矩形區域初始化
SEEDS的初始化是把影象平均分割成很多矩形,初始超畫素即為這些矩形。每一步迭代,超畫素的邊緣不斷變化,直到匯合。

4 超畫素演算法

5 SLIC演算法
SLIC(simple linear iterative clustering),即簡單的線性迭代聚類。它是2010年提出的一種思想簡單、實現方便的演算法,將彩色影象轉換為CIELAB顏色空間和XY座標下的5維特徵向量,然後對5維特徵向量構造距離度量標準,對影象畫素進行區域性聚類的過程。SLIC演算法能生成緊湊近似均勻的超畫素,在運算速度,物體輪廓保持、超畫素形狀方面具有較高的綜合評價,比較符合人們期望的分割效果。

5.1 SLIC優點:

生成的超畫素如同細胞一般緊湊整齊,鄰域特徵比較容易表達。這樣基於畫素方法可以比較容易的改造為基於超畫素的方法。
不僅可以分割彩色影象,也可以相容分割灰度圖。
需要設定的引數非常少,預設情況下只需要設定一個預分割的超畫素的數量。
相比其他的超畫素的分割方法,SLIC在執行速度、生成超畫素的緊湊度、輪廓保持方面都比較理想。

5.2 演算法步驟:

初始化種子點(聚類中心):按照設定的超畫素的個數,在影象內均勻的分配種子點。假設影象總共有N個畫素點,預分割為K個相同尺寸的超畫素,那麼每個超畫素的大小為N/K,則相鄰種子點的距離(步長)近似為S=sqrt(N/K)。
在種子點的n*n領域內重新選擇種子點(一般取n=3):計算該領域內所有畫素點的梯度值,將種子點移到該領域內梯度最小的地方。避免種子點落在梯度較大的輪廓邊界上,以免影響後續聚類效果。
在每個種子點周圍的領域內為每個畫素點分配類別標籤(即屬於哪個聚類中心):SLIC的搜尋範圍是2S2S,期望的超畫素尺寸為SS,這樣可以加速演算法收斂。
距離度量:包括顏色距離和空間距離。對每個搜尋到的畫素點,分別計算它和該種子點的距離。

二、原始碼

% 能夠確定超畫素位置的核心程式是  EnforceLabelConnectivity
% 11-123頁碼 
clc
clear
close all;
tic
img = imread('bee.jpg');
imshow(img)
title('original')
%設定超畫素個數
K = 500;
%設定超畫素緊湊係數
m_compactness = 100;

%%
img = DeSample(img,2);
img_size = size(img);
%轉換到LAB色彩空間
cform = makecform('srgb2lab');       %rgb空間轉換成lab空間 matlab自帶的用法,Create color transformation structure
img_Lab = applycform(img, cform);    %rgb轉換成lab空間
figure;
imshow(img_Lab)
title('img_lab')

%%
%得到超畫素的LABXY種子點資訊     
img_sz = img_size(1)*img_size(2);
superpixel_sz = img_sz/K;  % 每個超畫素的畫素點數
STEP = uint32(sqrt(superpixel_sz)); % 開方的邊長
xstrips = uint32(img_size(2)/STEP);  % x方向 的超畫素個數
ystrips = uint32(img_size(1)/STEP);  % y方向 的超畫素個數
xstrips_adderr = double(img_size(2))/double(xstrips);  
ystrips_adderr = double(img_size(1))/double(ystrips);
numseeds = xstrips*ystrips;   % 實際的超畫素個數
%種子點xy資訊初始值為晶格中心亞畫素座標
%種子點Lab顏色資訊為對應點最接近畫素點的顏色通道值
kseedsx = zeros(numseeds, 1);
kseedsy = zeros(numseeds, 1);
kseedsl = zeros(numseeds, 1);
kseedsa = zeros(numseeds, 1);
kseedsb = zeros(numseeds, 1);

n = 1;
for y = 1: ystrips   % 第y個超畫素
    for x = 1: xstrips   % 第 x 個超畫素
        kseedsx(n, 1) = (double(x)-0.5)*xstrips_adderr; % 第x個種子點中心座標,非準確描述
        kseedsy(n, 1) = (double(y)-0.5)*ystrips_adderr; % 第y個種子點中心座標,非準確描述
        % 種子點中心對應LAB圖上位置的 三通道值
        kseedsl(n, 1) = img_Lab(fix(kseedsy(n, 1)), fix(kseedsx(n, 1)), 1);  % fix 417.1296 變417
        kseedsa(n, 1) = img_Lab(fix(kseedsy(n, 1)), fix(kseedsx(n, 1)), 2); 
        kseedsb(n, 1) = img_Lab(fix(kseedsy(n, 1)), fix(kseedsx(n, 1)), 3);
        n = n+1;
    end
end

n = 1;
%根據種子點計算超畫素分割槽
klabels = PerformSuperpixelSLIC(img_Lab, kseedsl, kseedsa, kseedsb, kseedsx, kseedsy, STEP, m_compactness);
%合併小的分割槽
[supmtrx,supmtry,nlabels] = EnforceLabelC(img_Lab, klabels, K);
% 這裡的supmtrx,supmtry的每列分別是對應標籤區域的全部x座標和y座標
function klabels = PerformSuperpixelSLIC(img_Lab, kseedsl, kseedsa, kseedsb, kseedsx, kseedsy, STEP, compactness)

[m_height, m_width, m_channel] = size(img_Lab);
[numseeds xxxxx]= size(kseedsl);
img_Lab = double(img_Lab);
%畫素標籤格式為(x, y) (行, 列)
klabels = zeros(m_height, m_width);
%聚類尺寸
clustersize = zeros(numseeds,1);
inv = zeros(numseeds,1);
sigmal = zeros(numseeds,1);
sigmaa = zeros(numseeds,1);
sigmab = zeros(numseeds,1);
sigmax = zeros(numseeds,1);
sigmay = zeros(numseeds,1);
invwt = 1/( (double(STEP)/double(compactness)) *(double(STEP)/double(compactness)) );
%invwt = double(compactness)/double(STEP);
distvec = 100000*ones(m_height, m_width);
numk = numseeds;
for itr = 1: 10   %迭代次數
    sigmal = zeros(numseeds, 1);
    sigmaa = zeros(numseeds, 1);
    sigmab = zeros(numseeds, 1);
    sigmax = zeros(numseeds, 1);
    sigmay = zeros(numseeds, 1);
    clustersize = zeros(numseeds, 1);
    inv = zeros(numseeds, 1);
    distvec = double(100000*ones(m_height, m_width));
    %根據當前種子點資訊計算每一個畫素的歸屬
    for n = 1: numk
        y1 = max(1, kseedsy(n, 1)-STEP);
        y2 = min(m_height, kseedsy(n, 1)+STEP);
        x1 = max(1, kseedsx(n, 1)-STEP);
        x2 = min(m_width, kseedsx(n, 1)+STEP);
        %按畫素計算距離
        for y = y1: y2
            for x = x1: x2
                %dist_lab = abs(img_Lab(y, x, 1)-kseedsl(n))+abs(img_Lab(y, x, 2)-kseedsa(n))+abs(img_Lab(y, x, 3)-kseedsb(n));
                % lab圖 點到種子點 定義距離差,判斷相似度
                dist_lab = (img_Lab(y, x, 1)-kseedsl(n, 1))^2+(img_Lab(y, x, 2)-kseedsa(n, 1))^2+(img_Lab(y, x, 3)-kseedsb(n, 1))^2;
                % 改成平方啊 !!!  @@@  !!!  @@@   !!!
                dist_xy = (double(y)-kseedsy(n, 1))*(double(y)-kseedsy(n, 1)) + (double(x)-kseedsx(n, 1))*(double(x)-kseedsx(n, 1));
                %dist_xy = abs(y-kseedsy(n)) + abs(x-kseedsx(n));
                
                %距離 = lab色彩空間距離 + 空間距離權重×空間距離
                dist = dist_lab + dist_xy*invwt;
                %在周圍最多四個種子點中找到最相似的 標記後存入klabels
                %m = (y-1)*m_width+x;
                if (dist<distvec(y, x))
                    distvec(y, x) = dist;  % 不斷變小
                    klabels(y, x) = n;  % n是標籤,也就是值畫素屬於哪個種子點
                end
            end
        end
    end
    %完成一遍分類後,重新計算種子點位置 使其向梯度最小地方移動
    ind = 1;
    for r = 1: m_height
        for c = 1: m_width
            sigmal(klabels(r, c),1) = sigmal(klabels(r, c),1)+img_Lab(r, c, 1);  % 畫素塊內所有的通道值相加
            sigmaa(klabels(r, c),1) = sigmaa(klabels(r, c),1)+img_Lab(r, c, 2);
            sigmab(klabels(r, c),1) = sigmab(klabels(r, c),1)+img_Lab(r, c, 3);
            sigmax(klabels(r, c),1) = sigmax(klabels(r, c),1)+c;    % 畫素塊內所有的橫座標相加
            sigmay(klabels(r, c),1) = sigmay(klabels(r, c),1)+r;     % 畫素塊內所有的縱座標相加
            clustersize(klabels(r, c),1) = clustersize(klabels(r, c),1)+1;   % 畫素塊內所有個數相加
        end
    end
    for m = 1: numseeds  % 第m個種子點
        if (clustersize(m, 1)<=0)
            clustersize(m, 1) = 1;
        end
        inv(m, 1) = 1/clustersize(m, 1);
    end
    function [supmtrx,supmtry,nlabels] = EnforceLabelC(img_Lab, labels, K)

dx = [-1, 0, 1, 0];  %四鄰域
dy = [0, -1, 0, 1];
[m_height, m_width, m_channel] = size(img_Lab);
[M, N] = size(labels);
numlabel = max(max(labels));
SUPSZ = (m_height*m_width)/K;   %標準區域面積
nlabels = (-1)*ones(M, N);

label = 1;
adjlabel = 1;
xvec = zeros(m_height*m_width, 1);
yvec = zeros(m_height*m_width, 1);
supmtrx = zeros(2*floor(SUPSZ), numlabel);
supmtry = zeros(2*floor(SUPSZ), numlabel);
m = 1;
n = 1;

for j = 1: m_height
    for k = 1: m_width
        %逐點尋找未標記的區域 小於0 才執行
        if (0>nlabels(m, n))
            %從第一個未標記的(m,n)起,確定一個新區域,用label標記該區域的起點,用蝶形前進
            nlabels(m, n) = label;
            %開始一個新的分割 記錄起點座標
            xvec(1, 1) = k;
            yvec(1, 1) = j;
            supmtrx(1, label) = k;
            supmtry(1, label) = j;
            %如果起點與某個已知區域相連 用adjlabel記錄該區域編號 如果當前區域過小則與相鄰區域合併
            for i = 1: 4
                x = xvec(1, 1)+dx(1, i);
                y = yvec(1, 1)+dy(1, i);
                if (x>0 && x<=m_width && y>0 && y<=m_height)
                    if (nlabels(y, x)>0)
                        adjlabel = nlabels(y, x);  % 一般是左臨或上鄰的標籤
                    end
                end
            end

三、執行結果




四、備註

版本:2014a
完整程式碼或代寫加1564658423