與第一篇博文特徵臉方法不同,LBP(Local Binary Patterns,局部二值模式)是提取局部特徵作爲判別依據的。LBP方法顯著的優點是對光照不敏感,但是依然沒有解決姿態和表情的問題。不過相比於特徵臉方法,LBP的識別率已經有了很大的提升。在[1]的文章裏,有些人臉庫的識別率已經達到了98%+。
1、LBP特徵提取
最初的LBP是定義在像素3x3鄰域內的,以鄰域中心像素爲閾值,將相鄰的8個像素的灰度值與其進行比較,若周圍像素值大於中心像素值,則該像素點的位置被標記爲1,否則爲0。這樣,3x3鄰域內的8個點經比較可產生8位二進制數(通常轉換爲十進制數即LBP碼,共256種),即得到該鄰域中心像素點的LBP值,並用這個值來反映該區域的紋理信息。如下圖所示:
用比較正式的公式來定義的話:
其中代表3x3鄰域的中心元素,它的像素值爲ic,ip代表鄰域內其他像素的值。s(x)是符號函數,定義如下:
LBP的改進版本
(1)圓形LBP算子
基本的 LBP算子的最大缺陷在於它只覆蓋了一個固定半徑範圍內的小區域,這顯然不能滿足不同尺寸和頻率紋理的需要。爲了適應不同尺度的紋理特徵,並達到灰度和旋轉不變性的要求,Ojala等對 LBP 算子進行了改進,將 3×3鄰域擴展到任意鄰域,並用圓形鄰域代替了正方形鄰域,改進後的 LBP 算子允許在半徑爲 R 的圓形鄰域內有任意多個像素點。從而得到了諸如半徑爲R的圓形區域內含有P個採樣點的LBP算子。比如下圖定了一個5x5的鄰域:
上圖內有八個黑色的採樣點,每個採樣點的值可以通過下式計算:
其中爲鄰域中心點,爲某個採樣點。通過上式可以計算任意個採樣點的座標,但是計算得到的座標未必完全是整數,所以可以通過雙線性插值來得到該採樣點的像素值:
(2)LBP等價模式
一個LBP算子可以產生不同的二進制模式,對於半徑爲R的圓形區域內含有P個採樣點的LBP算子將會產生2^P種模式。很顯然,隨着鄰域集內採樣點數的增加,二進制模式的種類是急劇增加的。例如:5×5鄰域內20個採樣點,有220=1,048,576種二進制模式。如此多的二值模式無論對於紋理的提取還是對於紋理的識別、分類及信息的存取都是不利的。同時,過多的模式種類對於紋理的表達是不利的。例如,將LBP算子用於紋理分類或人臉識別時,常採用LBP模式的統計直方圖來表達圖像的信息,而較多的模式種類將使得數據量過大,且直方圖過於稀疏。因此,需要對原始的LBP模式進行降維,使得數據量減少的情況下能最好的代表圖像的信息。
爲了解決二進制模式過多的問題,提高統計性,Ojala提出了採用一種“等價模式”(Uniform Pattern)來對LBP算子的模式種類進行降維。Ojala等認爲,在實際圖像中,絕大多數LBP模式最多隻包含兩次從1到0或從0到1的跳變。因此,Ojala將“等價模式”定義爲:當某個LBP所對應的循環二進制數從0到1或從1到0最多有兩次跳變時,該LBP所對應的二進制就稱爲一個等價模式類。如00000000(0次跳變),00000111(只含一次從0到1的跳變),10001111(先由1跳到0,再由0跳到1,共兩次跳變)都是等價模式類。除等價模式類以外的模式都歸爲另一類,稱爲混合模式類,例如10010111(共四次跳變)。比如下圖給出了幾種等價模式的示意圖。
通過這樣的改進,二進制模式的種類大大減少,而不會丟失任何信息。模式數量由原來的2P種減少爲 P ( P-1)+2種,其中P表示鄰域集內的採樣點數。對於3×3鄰域內8個採樣點來說,二進制模式由原始的256種減少爲58種,這使得特徵向量的維數更少,並且可以減少高頻噪聲帶來的影響。這幾段摘自[2]。
通過上述方法,每個像素都會根據鄰域信息得到一個LBP值,如果以圖像的形式顯示出來可以得到下圖,明顯LBP對光照有較強的魯棒性。
2、LBP特徵匹配
如果將以上得到的LBP值直接用於人臉識別,其實和不提取LBP特徵沒什麼區別,會造成計算量準確率等一系列問題。文獻[1]中,將一副人臉圖像分爲7x7的子區域(如下圖),並在子區域內根據LBP值統計其直方圖,以直方圖作爲其判別特徵。這樣做的好處是在一定範圍內避免圖像沒完全對準的情況,同時也對LBP特徵做了降維處理。
對於得到的直方圖特徵,有多種方法可以判別其相似性,假設已知人臉直方圖爲Mi,待匹配人臉直方圖爲Si,那麼可以通過:
(1)直方圖交叉核方法
該方法的介紹在博文:Histogram intersection(直方圖交叉核,Pyramid Match Kernel)
(2)卡方統計方法
該方法的介紹在博文:卡方檢驗(Chi square statistic)
參考文獻:
[1]Timo Ahonen, Abdenour Hadid:Face Recognition with Local Binary Patterns
[2]目標檢測的圖像特徵提取之(二)LBP特徵
LBP(Local Binary Patterns),即局部二值模式,是一種描述圖像局部空間結構的非參數算子。芬蘭Oulu大學的T.Ojala等人於1996年提出這個算子用來分析圖像紋理特徵,並且描述了它在紋理分類中的強區分能力。LBP算子定義爲一種灰度尺度不變的紋理算子,是從局部鄰域紋理的普通定義得來的。
基本思想是:用中心像素的灰度值作爲閾值,與它的鄰域相比較得到的二進制碼來表述局部紋理特徵。
在紋理分析方面,LBP算子是最好的紋理描述符之一,它的主要優點有以下幾點:
Ø 通過它的定義可知,LBP算子的灰度尺度不隨任何單一變換而變化,因此灰度尺度的魯棒性好,也就是光照條件下的魯棒性好;
Ø 計算速度快。由於它可以通過在小鄰域內進行比較操作得到,使得在複雜的實時條件下分析圖像成爲可能;
Ø 由於LBP算子是一種無參數(Non-Parametric)的方法,在應用過程中不需要對它的分佈進行預先假設。_____________________________________________________________________________________
- %LBP returns the local binary pattern image or LBP histogram of an image.
- % J = LBP(I,R,N,MAPPING,MODE) returns either a local binary pattern
- % coded image or the local binary pattern histogram of an intensity
- % image I. The LBP codes are computed using N sampling points on a
- % circle of radius R and using mapping table defined by MAPPING.
- % See the getmapping function for different mappings and use 0 for
- % no mapping. Possible values for MODE are
- % 'h' or 'hist' to get a histogram of LBP codes
- % 'nh' to get a normalized histogram
- % Otherwise an LBP code image is returned.
- %
- % J = LBP(I) returns the original (basic) LBP histogram of image I
- %
- % J = LBP(I,SP,MAPPING,MODE) computes the LBP codes using n sampling
- % points defined in (n * 2) matrix SP. The sampling points should be
- % defined around the origin (coordinates (0,0)).
- %
- % Examples
- % --------
- % I=imread('rice.png');
- % mapping=getmapping(8,'u2');
- % H1=LBP(I,1,8,mapping,'h'); %LBP histogram in (8,1) neighborhood
- % %using uniform patterns
- % subplot(2,1,1),stem(H1);
- %
- % H2=LBP(I);
- % subplot(2,1,2),stem(H2);
- %
- % SP=[-1 -1; -1 0; -1 1; 0 -1; -0 1; 1 -1; 1 0; 1 1];
- % I2=LBP(I,SP,0,'i'); %LBP code image using sampling points in SP
- % %and no mapping. Now H2 is equal to histogram
- % %of I2.
- function result = lbp(varargin) % image,radius,neighbors,mapping,mode)
- % Version 0.3.2
- % Authors: Marko Heikkil�and Timo Ahonen
- % Changelog
- % Version 0.3.2: A bug fix to enable using mappings together with a
- % predefined spoints array
- % Version 0.3.1: Changed MAPPING input to be a struct containing the mapping
- % table and the number of bins to make the function run faster with high number
- % of sampling points. Lauge Sorensen is acknowledged for spotting this problem.
- % Check number of input arguments.
- error(nargchk(1,5,nargin));
- image=varargin{1};
- d_image=double(image);
- if nargin==1
- spoints=[-1 -1; -1 0; -1 1; 0 -1; -0 1; 1 -1; 1 0; 1 1];
- neighbors=8;
- mapping=0;
- mode='h';
- end
- if (nargin == 2) && (length(varargin{2}) == 1)
- error('Input arguments');
- end
- if (nargin > 2) && (length(varargin{2}) == 1)
- radius=varargin{2};
- neighbors=varargin{3};
- spoints=zeros(neighbors,2);
- % Angle step.
- a = 2*pi/neighbors;
- for i = 1:neighbors
- spoints(i,1) = -radius*sin((i-1)*a);
- spoints(i,2) = radius*cos((i-1)*a);
- end
- if(nargin >= 4)
- mapping=varargin{4};
- if(isstruct(mapping) && mapping.samples ~= neighbors)
- error('Incompatible mapping');
- end
- else
- mapping=0;
- end
- if(nargin >= 5)
- mode=varargin{5};
- else
- mode='h';
- end
- end
- if (nargin > 1) && (length(varargin{2}) > 1)
- spoints=varargin{2};
- neighbors=size(spoints,1);
- if(nargin >= 3)
- mapping=varargin{3};
- if(isstruct(mapping) && mapping.samples ~= neighbors)
- error('Incompatible mapping');
- end
- else
- mapping=0;
- end
- if(nargin >= 4)
- mode=varargin{4};
- else
- mode='h';
- end
- end
- % Determine the dimensions of the input image.
- [ysize xsize] = size(image);
- miny=min(spoints(:,1));
- maxy=max(spoints(:,1));
- minx=min(spoints(:,2));
- maxx=max(spoints(:,2));
- % Block size, each LBP code is computed within a block of size bsizey*bsizex
- bsizey=ceil(max(maxy,0))-floor(min(miny,0))+1;
- bsizex=ceil(max(maxx,0))-floor(min(minx,0))+1;
- % Coordinates of origin (0,0) in the block
- origy=1-floor(min(miny,0));
- origx=1-floor(min(minx,0));
- % Minimum allowed size for the input image depends
- % on the radius of the used LBP operator.
- if(xsize < bsizex || ysize < bsizey)
- error('Too small input image. Should be at least (2*radius+1) x (2*radius+1)');
- end
- % Calculate dx and dy;
- dx = xsize - bsizex;
- dy = ysize - bsizey;
- % Fill the center pixel matrix C.
- C = image(origy:origy+dy,origx:origx+dx);
- d_C = double(C);
- bins = 2^neighbors;
- % Initialize the result matrix with zeros.
- result=zeros(dy+1,dx+1);
- %Compute the LBP code image
- for i = 1:neighbors
- y = spoints(i,1)+origy;
- x = spoints(i,2)+origx;
- % Calculate floors, ceils and rounds for the x and y.
- fy = floor(y); cy = ceil(y); ry = round(y);
- fx = floor(x); cx = ceil(x); rx = round(x);
- % Check if interpolation is needed.
- if (abs(x - rx) < 1e-6) && (abs(y - ry) < 1e-6)
- % Interpolation is not needed, use original datatypes
- N = image(ry:ry+dy,rx:rx+dx);
- D = N >= C;
- else
- % Interpolation needed, use double type images
- ty = y - fy;
- tx = x - fx;
- % Calculate the interpolation weights.
- w1 = (1 - tx) * (1 - ty);
- w2 = tx * (1 - ty);
- w3 = (1 - tx) * ty ;
- w4 = tx * ty ;
- % Compute interpolated pixel values
- N = w1*d_image(fy:fy+dy,fx:fx+dx) + w2*d_image(fy:fy+dy,cx:cx+dx) + ...
- w3*d_image(cy:cy+dy,fx:fx+dx) + w4*d_image(cy:cy+dy,cx:cx+dx);
- D = N >= d_C;
- end
- % Update the result matrix.
- v = 2^(i-1);
- result = result + v*D;
- end
- %Apply mapping if it is defined
- if isstruct(mapping)
- bins = mapping.num;
- for i = 1:size(result,1)
- for j = 1:size(result,2)
- result(i,j) = mapping.table(result(i,j)+1);
- end
- end
- end
- if (strcmp(mode,'h') || strcmp(mode,'hist') || strcmp(mode,'nh'))
- % Return with LBP histogram if mode equals 'hist'.
- result=hist(result(:),0:(bins-1));
- if (strcmp(mode,'nh'))
- result=result/sum(result);
- end
- else
- %Otherwise return a matrix of unsigned integers
- if ((bins-1)<=intmax('uint8'))
- result=uint8(result);
- elseif ((bins-1)<=intmax('uint16'))
- result=uint16(result);
- else
- result=uint32(result);
- end
- end
- end
- %GETMAPPING returns a structure containing a mapping table for LBP codes.
- % MAPPING = GETMAPPING(SAMPLES,MAPPINGTYPE) returns a structure containing a mapping table for
- % LBP codes in a neighbourhood of SAMPLES sampling points. Possible values for MAPPINGTYPE are
- % 'u2' for uniform LBP
- % 'ri' for rotation-invariant LBP
- % 'riu2' for uniform rotation-invariant LBP.
- %
- % Example:
- % I=imread('rice.tif');
- % MAPPING=getmapping(16,'riu2');
- % LBPHIST=lbp(I,2,16,MAPPING,'hist');
- % Now LBPHIST contains a rotation-invariant uniform LBP histogram in a (16,2) neighbourhood.
- %
- function mapping = getmapping(samples,mappingtype)
- % Version 1.0 beta
- % Authors: Marko Heikkil?and Timo Ahonen
- % Editor: LinJianmin - Huaqiao University
- % Email: [email protected]
- table = 0:2^samples-1;
- newMax = 0; %number of patterns in the resulting LBP code
- index = 0;
- if strcmp(mappingtype,'u2') %Uniform 2
- newMax = samples*(samples-1) + 3;
- for i = 0:2^samples-1
- j = bitset(bitshift(i,1,samples),1,bitget(i,samples)); %rotate left
- numt = sum(bitget(bitxor(i,j),1:samples)); %number of 1->0 and 0->1 transitions in binary string
- %x is equal to the number of 1-bits in XOR(x,Rotate left(x))
- if numt <= 2
- table(i+1) = index;
- index = index + 1;
- else
- table(i+1) = newMax - 1;
- end
- end
- end
- if strcmp(mappingtype,'ri') %Rotation invariant
- tmpMap = zeros(2^samples,1) - 1;
- for i = 0:2^samples-1
- rm = i;
- r = i;
- for j = 1:samples-1
- r = bitset(bitshift(r,1,samples),1,bitget(r,samples)); %rotate
- %left
- if r < rm
- rm = r;
- end
- end
- if tmpMap(rm+1) < 0
- tmpMap(rm+1) = newMax;
- newMax = newMax + 1;
- end
- table(i+1) = tmpMap(rm+1);
- end
- end
- if strcmp(mappingtype,'riu2') %Uniform & Rotation invariant
- newMax = samples + 2;
- for i = 0:2^samples - 1
- j = bitset(bitshift(i,1,samples),1,bitget(i,samples)); %rotate left
- numt = sum(bitget(bitxor(i,j),1:samples));
- if numt <= 2
- table(i+1) = sum(bitget(i,1:samples));
- else
- table(i+1) = samples+1;
- end
- end
- end
- mapping.table=table;
- mapping.samples=samples;
- mapping.num=newMax;