1. 程式人生 > >光照不均勻影象分割技巧1——分塊閾值

光照不均勻影象分割技巧1——分塊閾值

本文章由wikiwen撰寫,轉載請註明出處。
文章連結:http://blog.csdn.net/kk55guang2/article/details/78475414
作者:wikiwen

前言

  在數字影象處理中,影象分割是很關鍵的一步,當影象質量較好,光照很均勻的時候只需用全域性閾值的方法就能很完美地完成影象分割任務,但是有些時候會遇到光照不均勻的現象,這個時候就需要用一些技巧才能達到比較好的分割效果,本文要介紹的是一種通過分塊閾值進行分割的方法。

例項

  在進入正題之前,我們先看一個例項,下面圖1和圖3為做硬幣面額識別拍攝的,可以看到,由於硬幣表面的反光以及打光角度的原因,圖片存在嚴重的光照不均現象。
  如果對兩幅影象直接進行全域性閾值可以得到圖2和圖4的結果,可以看到分割的效果很差,比如第一幅,右上角的光照要強一些,而且右上角的硬幣存在一定的反光,灰度值整體偏高,導致最後分割效果很差。第二幅則是左邊部分光照太強,左邊的硬幣分割效果很差。
  本文將用分塊閾值的方法解決這一問題。



圖1 光照不均勻影象1         圖2 全域性閾值處理結果



圖3 光照不均勻影象2         圖4 全域性閾值處理結果

分塊閾值思路

  通過將影象分割成若干塊,分別進行閾值分割,可以在一定程度上解決光照或反射造成的不均勻影響。選擇的塊要足夠小,以便每個塊的光照都近似均勻的,這樣自動閾值時,在高灰度區域就會用高閾值分割,在低灰度區域就會用低閾值分割。
  圖5為分塊結果,示例中分塊與硬幣大小相當,分完塊之後就可以按塊進行全域性閾值法(這裡採用常用的最大類間方差法,otsu法)處理了,但是需要注意的是有的塊中只有背景,這個時候需要進行判斷,排除對這種塊的處理。
  對於這種塊的判斷,筆者嘗試過用otsu方法中提到的可分性度量:

η = σ B 2
σ G 2

  上式中, σ G 2 σ B 2 分別為全域性方差和類間方差。
   筆者在計算出各個塊的可分性度量之後,發現區分效果並不是很好,後來通過分析最大類間方差法,有個想法就是用分割閾值處的類間平均灰度差判斷影象塊的可分性,當影象中只有背景或只有物體時,由於灰度值比較接近,則用otsu法算出的“背景”和“前景”平均灰度差(類間灰度差)會很小,類間平均灰度差  Δ m  的數學表示式如下:
Δ m = | m 1 ( T ) m 2 ( T ) |
m 1 ( k ) = i = 0 k i P ( i / C 1 ) , m 2 ( k ) = i = k + 1 L 1 i P ( i / C 2 )
  如圖5中各塊標註的文字所示,T為分割閾值,d為類間平均灰度差,可以看到當塊中只有背景時,平均灰度差與有物體時相差很大,選取特徵區分效果很好。本示例中,選灰度差20就能將兩種不同的塊很好的區分開。



圖5 分塊情況

  之後僅對既有物體又有背景的塊進行自動閾值處理、二值化、填充孔洞,可以得到圖6的結果,可以看到每個硬幣都被很好的分割出來


圖6 分塊閾值處理結果

程式碼

%功能:對一副影象進行分塊閾值,可解決光照不均分割不足的問題
%通過判斷類間灰度差以排除純背景或純物體的干擾
%作者:wikiwen
%日期:2017/10/24
%平臺:matlab R2014

clc,clear;
close all;

rn=5;cn=5;
I = rgb2gray(imread('d.jpg'));
[R , C]=size(I);%分別返回行和列數
rblk=R/rn;cblk=C/cn;%小塊的行數和列數
x = 0:cblk:C;
y = 0:rblk:R;
M = meshgrid(x,y); %產生網格
N = meshgrid(y,x);  %產生網格
imshow(I);
hold on
plot(x,N,'r'); %畫出水平橫線
plot(M,y,'r'); %畫出垂直豎線

T = zeros(rn,cn);
dif = zeros(rn,cn);
J = false(R,C);%初始化二值圖
X = uint8(zeros(rblk,cblk));
%分塊閾值,並判斷類間灰度差以排除純背景或純物體的干擾
for r=1:rn
    for c=1:cn
        r0=rblk*(r-1)+1;r1=rblk*r;
        c0=cblk*(c-1)+1;c1=cblk*c;
        X = I(r0:r1,c0:c1);
        T(r,c) = graythresh(X);
        [h,~] = histcounts(X,0:255);
        T_int =uint8(T(r,c)*255);
        dif(r,c) = graydiffer(h,T_int);%計算類間灰度差的函式略

        str = ['T=',num2str(T_int),' d=',num2str(dif(r,c))];
        text(c0+cblk/4,r0+rblk/2,str,'color','black');%顯示資訊
        if dif(r,c)>20
            J(r0:r1,c0:c1) = ~im2bw(X,T(r,c));
        end
    end
end
J = imfill(J,'holes');%填充孔洞
figure;
imshow(J);
%功能:計算一幅影象前景和背景類間平均灰度差
%輸入:直方圖資料h,分割閾值T
%輸出:類間平均灰度差
%作者:wikiwen
%日期:2017/10/26
function[differ] = graydiffer(h,T)
    s1 = sum(h(1:T));
    s2 = sum(h(T:255));
    n1 = 1:T;
    n2 = T:255;
    u1 = double(n1)*h(1:T)' / s1; %背景灰度均值
    u2 = double(n2)*h(T:255)' / s2; %前景灰度均值

    differ = uint8(u2-u1);
end