基於閾值分割的圖像分割-最小誤差-區域生長-標記分水嶺(matlab代碼)

1
基於閾值分割的圖像分割

1.1
閾值分割基本原理

閾值分割因爲具有簡單、高效、實用的特點在圖像分割領域得到了廣泛的使用。閾值分割適用於灰度級存在明顯差異情況下的前景背景分割。使用一個固定灰度值T作爲閾值將前景背景區域進行分割,遍歷整幅圖像的像素點,灰度值小於或等於閾值T的像素點設置爲1,用白色表示;將灰度值大於閾值T的像素點設置爲0,用黑色表示。分割後的圖像爲二值化圖像。具體的過程可以用以下公式描述:
在這裏插入圖片描述
閾值分割方法能否準確快速的將圖像的前景背景區域分割,其中的核心問題是閾值的選取。閾值的選取有許多的方法:根據在整幅圖像中使用同一閾值或者將整幅圖像分割成不同區域,在不同區域內使用不同閾值可以將閾值分割方法分爲全局閾值方法和局部閾值方法;根據使用閾值的個數可以將閾值分割方法分爲單閾值或多閾值方法。

1.2
最小誤差法(基於傳統閾值分割)

1.2.1最小誤差法原理

最小誤差閾值分割法是根據圖像中背景和目標像素的概率分佈密度來實現的,其思想是找到一個閾值,並根據該閾值進行劃分,計算出目標點誤分爲背景的概率和背景點誤分爲目標點的概率,得出總的誤差劃分概率。當總的誤差劃分概率最小時,便得到所需要的最佳閾值。

在這裏插入圖片描述表示一副大小爲在這裏插入圖片描述的圖像在座標在這裏插入圖片描述的像素點灰度值,在這裏插入圖片描述。圖像灰度概率分佈用一維直方圖h(x)表示。設圖像中感興趣的目標點的灰度也爲正態分佈,密度爲f1(x)),均值和方差分別爲miu1和sigma1;圖像背景點的灰度也爲正態分佈,密度爲f1(x),均值和方差分別爲miu2 sigma2。因此,整個密度函數可看成是兩個單峯密度函數的混合,即雙峯密度函數,如圖2所示。
在這裏插入圖片描述

圖 2 雙峯密度函數
在這裏插入圖片描述
在這裏插入圖片描述

1.2.2最小誤差法實現步驟
在這裏插入圖片描述

圖 3 最小誤差閾值算法流程圖

根據圖20可得最小誤差閾值法的算法步驟:

步驟1:假設目標和背景灰度值得密度爲,。計算混合概率密度。

步驟2:選定閾值T,計算總的誤差概率,對進行求導。

步驟3:根據準則函數,計算使其最小時的T,作爲最佳閾值。

1.3
區域生長(基於區域信息分割)

圖像分割算法的原理是指根據圖像的灰度值不連續性與相似性來實現的。不連續性是基於圖像的灰度不連續變化來完成圖像的分割,例如圖像的邊緣。相似性是根據指定的準則把圖像分割成相似以及不相似的區域。基於區域生長的圖像分割算法就是利用了圖像灰度值的相似性特徵來實現的。

3.3.1區域生長法原理

區域生長算法的原理就是求圖像中相似的像素的最大連通集合。把相似灰度值的像素點集合,然後依次檢測該像素點周圍的8個鄰域像素點,把灰度值相近的點加入到之前的集合中,如果不相似則跳過該點。然後依次瀏覽該圖像中的其他的像素點,直到圖像中所有的像素點都被檢查完畢爲止,這樣獲得的區域就是按照區域生長算法得到的新區域。

令R表示整幅圖像區域,那麼圖像分割的過程可以看作把區域R劃分爲n個子區域的過程,並且劃分的子區域需要滿足以下條件:
在這裏插入圖片描述

區域生長算法是根據待處理目標的特徵把像素點或者子區域按照一定的準則聚合成更大區域,並且聚合成的更大區域也滿足上述a-e的條件。

這是一個迭代過程,每一步重新計算被擴大區域的物體成員隸屬關係並消除弱邊界。當沒有可以消除的弱邊界時,區域合併過程結束。這時,圖像分割也就完成。檢查這個過程會使人感覺這是一個物體內部的區域不斷增長直到其邊界對應於物體的真正邊界爲止的過程。

區域生長是一種串行區域分割的圖像分割方法,其優點是基本思想相對簡單,通常能將具有相同特徵的聯通區域分割出來,並能提供很好的邊界信息和分割結果。在沒有先驗知識可以利用時,可以取得最佳的性能,可以用來分割比較複雜的圖像,如自然景物。但是,區域生長法是一種迭代的方法,對空間與時間的消耗都比較大,噪聲和灰度不均勻可能會導致空洞和過分割,並且在對圖像中的陰影效果處理上往往不是很好。

1.3.2區域生長法實現步驟

區域生長算法中需要確定三個條件:生長條件,停止條件和種子點。種子點可以是一個節點,也可以是一段連續區域的集合,解決不同的問題需要根據具體的實際情況來確定種子點的多少。

區域生長的條件是根據圖像中像素點的灰度值大小變化率來確定的,區域生長的停止條件固定了區域停止生長時應該滿足的條件。

可見區域生長法主要由以下三個步驟組成:

1)選擇合適的種子點

2)確定相似性準則(生長準則)

3)確定生長停止條件

令表f(x,y)示一個輸入圖像陣列;s(x,y)表示一個種子陣列,陣列中種子點位置爲1,其他位置爲0;Q表示在每個位置處所用的屬性。假設陣列f和陣列S的尺寸相同。基於8鄰域(8連接)的一個基本區域生長算法可以說明如下。

1) 在s(x,y)中尋找所有連通分量,並把每個連通分量腐蝕爲一個像素;把找到的所有這種像素標記爲1,把S中的所有其他像素標記爲0。

2) 在座標對(x,y)處形成圖像fq:如果輸入圖像在該座標處滿足給定的屬性Q,則令fq(x,y)=1,否則令fq(x,y)=0。

3) 令g是這樣形成的圖像:即把fq中爲8連通種子點的所有1值點,添加到S中的每個種子點。

4) 用不同的區域標記(如1,2,3)標出g中的每個連通分量。這就是由區域生長得到的分割圖像。

在區域生長算法中需要設置一個變量max_dist來保存當前圖像中已經分割好區域中兩灰度值差值最大的距離。算法開始執行時,依次檢測圖像中的像素點灰度值。設置另外一個變量來保存當前區域已經分割好的區域灰度值的均值,然後設置當前像素點的灰度值,將兩者之差的絕對值賦值給D,如果D小於等於max_dist,就把該點加入到已分割的區域中,否則繼續檢查下一個點。

1.4
標記分水嶺(基於混合信息分割)

數學形態學起源於巖相學對岩石結構的定量描述工作,近年來在數字圖像處理和機器視覺領域中得到了廣泛的應用,已經成爲一種獨特的數字圖像分析方法和理論。目前,對於利用形態學進行圖像分割,分水嶺算法一直是研究的熱點,這是由於分水嶺算法能夠準確地獲得前景物體的邊緣,爲後期操作提供較好的預分割圖像,並且具有許多優點諸如實現簡單、具有完整閉合的單像素分割線、易於並行化處理等。

1.4.1標記符分水嶺法原理

在使用分水嶺算法進行圖像分割的時候,如果直接應用往往會發現存在很多的局部極大值,並且這些極大值點的數目多於目標顆粒的數目,而這種現象也是導致分水嶺算法出現過分割的主要原因。標記符控制的分水嶺算法的主要思想是利用一些附加的方法,在目標顆粒的內部和外部分別尋找標記符,從而來引導分水嶺進行分割,進而防止過分割的產生。

標記符是指屬於原圖像的一個連接分量,包括內部標記符集合和外部標記符集合。其中,內部標記符集合是指標記符處在每一個感興趣對象的內部,外部標記符集合是指標記符包含在背景中,通過標記符用來修改梯度圖像,計算內部和外部標記符集合常用的方法有線性濾波、非線性濾波及形態學處理等等。

基於標記控制的分水嶺方法基本思想就是事先分別提取出代表目標區域的內部標記和背景區域的外部標記,然後再利用這些標記去修改原始梯度圖,最後再進行分水嶺算法。通過該方法極大地限制了局部極小值的個數,很好地控制了過分割現象的發生。

1.4.2標記分水嶺法實現步驟

標記符控制分水嶺算法的具體方法描述如下:

1) 對原始圖像進行預處理操作。通過對比度增強、直方圖匹配、形態學去噪等操作改善圖像的顯示效果,去除干擾噪聲。

2) 距離變換。由於經過形態學處理後的圖像爲二值圖像,因此首先應進行距離變換。背景圖像可以用一個大小和原圖像相同的二維數組來表示,記爲在這裏插入圖片描述,其中aij=0的像素點對應背景,aij=1的點對應目標。設在這裏插入圖片描述爲背景點集合,則距離變換就是對A中所有的像素點求dij:

在這裏插入圖片描述

式中,在這裏插入圖片描述,從而得到歐式距離變換圖像Dmxn。

3) 藉助數學形態學中的方法,得到內部標記點及內部標記圖像fgm,消除過分割。

4) 利用一次分水嶺運算得到外部標記符及外部標記圖像fbw;然後基於獲取到的內外標記,利用強制最小技術對原梯度圖像進行修改,修改後的梯度圖像可表示爲:

在這裏插入圖片描述

5) 接下來對圖像進行分水嶺變換,最終得到理想的分割效果,分水嶺變換可表示爲:
在這裏插入圖片描述
標記分水嶺

function Watershed_Fun(fileName)

rgb = imread(fileName);
if ndims(rgb) == 3
    I = rgb2gray(rgb);
else    
    I = rgb;
end
sz = size(I);
if sz(1) ~= 256
    I = imresize(I, 256/sz(1));
    rgb = imresize(rgb, 256/sz(1));
end
hy = fspecial('sobel');
hx = hy';
Iy = imfilter(double(I), hy, 'replicate');
Ix = imfilter(double(I), hx, 'replicate');
gradmag = sqrt(Ix.^2 + Iy.^2);
se = strel('disk', 3);
Io = imopen(I, se);
Ie = imerode(I, se);
Iobr = imreconstruct(Ie, I);
Ioc = imclose(Io, se);
Iobrd = imdilate(Iobr, se);
Iobrcbr = imreconstruct(imcomplement(Iobrd), imcomplement(Iobr));
Iobrcbr = imcomplement(Iobrcbr);
fgm = imregionalmax(Iobrcbr);
se2 = strel(ones(3,3));
fgm2 = imclose(fgm, se2);
fgm3 = imerode(fgm2, se2);
fgm4 = bwareaopen(fgm3, 15);
bw = im2bw(Iobrcbr, graythresh(Iobrcbr));
D = bwdist(bw);
DL = watershed(D);
bgm = DL == 0;
gradmag2 = imimposemin(gradmag, bgm | fgm4);
L = watershed(gradmag2);
Lrgb = label2rgb(L, 'jet', 'w', 'shuffle');

[pathstr, name, ext] = fileparts(fileName);
filefolder = fullfile(pwd, '實驗結果', [name, '_實驗截圖']);
if ~exist(filefolder, 'dir')
    mkdir(filefolder);
end
h1 = figure(1);
set(h1, 'Name', '圖像灰度化', 'NumberTitle', 'off');
subplot(1, 2, 1); imshow(rgb, []); title('原圖像');
subplot(1, 2, 2); imshow(I, []); title('灰度圖像');
fileurl = fullfile(filefolder, '1');
set(h1,'PaperPositionMode','auto');
print(h1,'-dtiff','-r200',fileurl);
h2 = figure(2);
set(h2, 'Name', '圖像形態學操作', 'NumberTitle', 'off');
subplot(1, 2, 1); imshow(Iobrcbr, []); title('圖像形態學操作');
subplot(1, 2, 2); imshow(bw, []); title('圖像二值化');
fileurl = fullfile(filefolder, '2');
set(h2,'PaperPositionMode','auto');
print(h2,'-dtiff','-r200',fileurl);
h3 = figure(3);
set(h3, 'Name', '圖像梯度顯示', 'NumberTitle', 'off');
subplot(1, 2, 1); imshow(rgb, []); title('待處理圖像');
subplot(1, 2, 2); imshow(gradmag, []); title('梯度圖像');
fileurl = fullfile(filefolder, '3');
set(h3,'PaperPositionMode','auto');
print(h3,'-dtiff','-r200',fileurl);
h4 = figure(4); imshow(rgb, []); hold on;
himage = imshow(Lrgb);
set(h4, 'Name', '圖像分水嶺分割', 'NumberTitle', 'off');
set(himage, 'AlphaData', 0.3);
hold off;
fileurl = fullfile(filefolder, '4');
set(h4,'PaperPositionMode','auto');
print(h4,'-dtiff','-r200',fileurl);

最小誤差

clc; clear all; close all;
warning off all;
% 讀取圖像
filename = fullfile(pwd, 'images/00.jpg');
Img = imread(filename);
% 灰度化
if ndims(Img) == 3
    I = rgb2gray(Img);
else
    I = Img;
end
% 直接二值化
bw_direct = im2bw(I);
figure; imshow(bw_direct); title('直接二值化分割');
% 圈選胃區域空氣
c = [1524 1390 1454 1548 1652 1738 1725 1673 1524];
r = [1756 1909 2037 2055 1997 1863 1824 1787 1756];
bw_poly = roipoly(bw_direct, c, r);
figure;
imshow(I, []);
hold on;
plot(c, r, 'r-', 'LineWidth', 2);
hold off;

% 
J = I;
J(bw_poly) = 255;
% 圖像增強
J = mat2gray(J);
J = imadjust(J, [0.532 0.72], [0 1]);
J = im2uint8(mat2gray(J));
figure; imshow(J, []); title('圖像增強處理');
% 直方圖統計
[counts, gray_style] = imhist(J);
% 亮度級別
gray_level = length(gray_style);
% 計算各灰度概率
gray_probability  = counts ./ sum(counts);
% 統計像素均值
gray_mean = gray_style' * gray_probability;
% 初始化
gray_vector = zeros(gray_level, 1);
w = gray_probability(1);
mean_k = 0;
gray_vector(1) = realmax;
ks = gray_level-1;
for k = 1 : ks
    % 迭代計算
    w = w + gray_probability(k+1);
    mean_k = mean_k + k * gray_probability(k+1);
    % 判斷是否收斂
    if (w < eps) || (w > 1-eps)
        gray_vector(k+1) = realmax;
    else
        % 計算均值
        mean_k1 = mean_k / w;
        mean_k2 = (gray_mean-mean_k) / (1-w);
        % 計算方差
        var_k1 = (((0 : k)'-mean_k1).^2)' * gray_probability(1 : k+1);
        var_k1 = var_k1 / w;
        var_k2 = (((k+1 : ks)'-mean_k2).^2)' * gray_probability(k+2 : ks+1);
        var_k2 = var_k2 / (1-w);
        % 計算目標函數
        if var_k1 > eps && var_k2 > eps
            gray_vector(k+1) = 1+w * log(var_k1)+(1-w) * log(var_k2)-2*w*log(w)-2*(1-w)*log(1-w);
        else
            gray_vector(k+1) = realmax;
        end
    end
end
% 極值統計
min_gray_index = find(gray_vector == min(gray_vector));
min_gray_index = mean(min_gray_index);
% 計算閾值
threshold_kittler = (min_gray_index-1)/ks;
% 閾值分割
bw__kittler = im2bw(J, threshold_kittler);
% 顯示
figure; imshow(bw__kittler, []); title('最小誤差法分割');
% 形態學後處理
bw_temp = bw__kittler;
% 反色
bw_temp = ~bw_temp;
% 填充孔洞
bw_temp = imfill(bw_temp, 'holes');
% 去噪
bw_temp = imclose(bw_temp, strel('disk', 5));
bw_temp = imclearborder(bw_temp);
% 區域標記
[L, num] = bwlabel(bw_temp);
% 區域屬性
stats = regionprops(L);
Ar = cat(1, stats.Area);
% 提取目標並清理
[Ar, ind] = sort(Ar, 'descend');
bw_temp(L ~= ind(1) & L ~= ind(2)) = 0;
% 去噪
bw_temp = imclose(bw_temp, strel('disk',20));
bw_temp = imfill(bw_temp, 'holes');
figure;
subplot(1, 2, 1); imshow(bw__kittler, []); title('待處理二值圖像');
subplot(1, 2, 2); imshow(bw_temp, []); title('形態學後處理圖像');
% 提取肺邊緣
ed = bwboundaries(bw_temp);
% 顯示
figure;
subplot(2, 2, 1); imshow(I, []); title('原圖像');
subplot(2, 2, 2); imshow(J, []); title('增強圖像');
subplot(2, 2, 3); imshow(bw_temp, []); title('二值化圖像');
subplot(2, 2, 4); imshow(I, []); hold on;
for k = 1 : length(ed)
    % 邊緣
    boundary = ed{k};
    plot(boundary(:,2), boundary(:,1), 'g', 'LineWidth', 2);
end
title('邊緣顯示標記');
figure;
subplot(1, 2, 1); imshow(bw_temp, []); title('二值圖像');
subplot(1, 2, 2); imshow(I, []); hold on;
for k = 1 : length(ed)
    % 邊緣
    boundary = ed{k};
    plot(boundary(:,2), boundary(:,1), 'g', 'LineWidth', 2);
end
title('邊緣顯示標記');

區域生長

clc; clear all; close all;
I = imread(fullfile(pwd, 'images/00.jpg'));
X = imadjust(I, [0.2 0.8], [0 1]);
% 閾值分割
bw = im2bw(X, graythresh(X));
[r, c] = find(bw);
rect = [min(c) min(r) max(c)-min(c) max(r)-min(r)];
Xt = imcrop(X, rect);
% 自動獲取種子點
seed_point = round([size(Xt, 2)*0.15+rect(2) size(Xt, 1)*0.4+rect(1)]);
% 區域生長分割
X = im2double(im2uint8(mat2gray(X)));
X(1:rect(2), :) = 0;
X(:, 1:rect(1)) = 0;
X(rect(2)+rect(4):end, :) = 0;
X(:, rect(1)+rect(3):end) = 0;
[J, seed_point, ts] = Regiongrowing(X, seed_point);
figure(1);
subplot(1, 2, 1); imshow(I, []);
hold on;
plot(seed_point(1), seed_point(2), 'ro', 'MarkerSize', 10, 'MarkerFaceColor', 'r');
title('種子點自動選擇');
hold off;
subplot(1, 2, 2); imshow(J, []); title('區域生長圖像');
% 形態學後處理
bw = imfill(J, 'holes');
bw = imopen(bw, strel('disk', 5));
% 提取邊緣
ed = bwboundaries(bw);
figure;
subplot(1, 2, 1); imshow(bw, []); title('形態學後處理圖像');
subplot(1, 2, 2); imshow(I); 
hold on;
for k = 1 : length(ed)
    % 邊緣
    boundary = ed{k};
    plot(boundary(:,2), boundary(:,1), 'g', 'LineWidth', 2);
end
hold off;
title('邊緣標記圖像');
function [J, seed_point, ts] = Regiongrowing(I, seed_point)
% 統計耗時
t1 = cputime;
% 參數檢測
if nargin < 2
    % 顯示並選擇種子點
    figure; imshow(I,[]);  hold on;
    seed_point = ginput(1);   
    plot(seed_point(1), seed_point(2), 'ro', 'MarkerSize', 10, 'MarkerFaceColor', 'r');
    title('種子點選擇');
    hold off;
end
% 變量初始化
seed_point = round(seed_point);
x = seed_point(2);
y = seed_point(1);
I = double(I);
rc = size(I);
J = zeros(rc(1), rc(2));
% 參數初始化
seed_pixel = I(x,y);
seed_count = 1;
pixel_free = rc(1)*rc(2); 
pixel_index = 0;
pixel_list = zeros(pixel_free, 3);
pixel_similarity_min = 0;
pixel_similarity_limit = 0.1;
% 鄰域
neighbor_index = [-1 0;
        1 0;
        0 -1;
        0 1];
% 循環處理
while pixel_similarity_min < pixel_similarity_limit && seed_count < rc(1)*rc(2)   
    % 增加鄰域點
    for k = 1 : size(neighbor_index, 1)
        % 計算相鄰位置
        xk = x + neighbor_index(k, 1); 
        yk = y + neighbor_index(k, 2);
        % 區域生長
        if xk>=1 && yk>=1 && xk<=rc(1) && yk<=rc(2) && J(xk,yk) == 0
            % 滿足條件
            pixel_index = pixel_index+1;
            pixel_list(pixel_index,:) = [xk yk I(xk,yk)]; 
            % 更新狀態
            J(xk, yk) = 1;
        end
    end
    % 更新空間
    if pixel_index+10 > pixel_free 
        pixel_free = pixel_free+pixel_free;
        pixel_list(pixel_index+1:pixel_free,:) = 0;
    end
    % 統計迭代
    pixel_similarity = abs(pixel_list(1:pixel_index,3) - seed_pixel);
    [pixel_similarity_min, index] = min(pixel_similarity);
    % 更新狀態
    J(x,y) = 1; 
    seed_count = seed_count+1;
    seed_pixel = (seed_pixel*seed_count + pixel_list(index,3))/(seed_count+1);
    % 存儲位置
    x = pixel_list(index,1); 
    y = pixel_list(index,2);
    pixel_list(index,:) = pixel_list(pixel_index,:);
    pixel_index = pixel_index-1;
end
% 返回結果
J = mat2gray(J);
J = im2bw(J, graythresh(J));
% 統計耗時
t2 = cputime;
ts = t2 - t1;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章