LBP特徵提取
原理:
(一)LBP特徵的描述
原始的LBP算子定義爲在33的窗口內,以窗口中心像素爲閾值,將相鄰的8個像素的灰度值與其進行比較,若周圍像素值大於中心像素值,則該像素點的位置被標記爲1,否則爲0。這樣,33鄰域內的8個點經比較可產生8位二進制數(通常轉換爲十進制數即LBP碼,共256種),即得到該窗口中心像素點的LBP值,並用這個值來反映該區域的紋理信息。如下圖所示:
(二)LBP的改進版本:
原始的LBP提出後,研究人員不斷對其提出了各種改進和優化。
(1)圓形LBP算子:
基本的 LBP 算子的最大缺陷在於它只覆蓋了一個固定半徑範圍內的小區域,這顯然不能滿足不同尺寸和頻率紋理的需要。爲了適應不同尺度的紋理特徵,並達到灰度和旋轉不變性的要求,Ojala 等對 LBP 算子進行了改進,將 3×3 鄰域擴展到任意鄰域,並用圓形鄰域代替了正方形鄰域,改進後的 LBP 算子允許在半徑爲 R 的圓形鄰域內有任意多個像素點。從而得到了諸如半徑爲R的圓形區域內含有P個採樣點的LBP算子;
(2)LBP旋轉不變模式
從 LBP 的定義可以看出,LBP 算子是灰度不變的,但卻不是旋轉不變的。圖像的旋轉就會得到不同的 LBP值。
Maenpaa等人又將 LBP 算子進行了擴展,提出了具有旋轉不變性的 LBP 算子,即不斷旋轉圓形鄰域得到一系列初始定義的 LBP 值,取其最小值作爲該鄰域的 LBP 值。
圖 2.5 給出了求取旋轉不變的 LBP 的過程示意圖,圖中算子下方的數字表示該算子對應的 LBP 值,圖中所示的 8 種 LBP模式,經過旋轉不變的處理,最終得到的具有旋轉不變性的 LBP 值爲 15。也就是說,圖中的 8 種 LBP 模式對應的旋轉不變的 LBP 模式都是00001111。
(3)LBP等價模式
一個LBP算子可以產生不同的二進制模式,對於半徑爲R的圓形區域內含有P個採樣點的LBP算子將會產生2P種模式。很顯然,隨着鄰域集內採樣點數的增加,二進制模式的種類是急劇增加的。例如: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種,這使得特徵向量的維數更少,並且可以減少高頻噪聲帶來的影響。
代碼:
原始的LBP算子
//原始的LBP算子
void Original_LBP(const QImage &image,QImage &otp)
{
int width = image.width();
int height = image.height();
QImage* deal_image = new QImage((width-2),(height-2),QImage::Format_ARGB32);
Init_Image(*deal_image,0);
int i = 0,j = 0;
for(i = 1; i<height-1; i++)
{
for(j = 1; j<width-1; j++)
{
uchar center = (uchar)qGray(image.pixel(j,i));
uchar code = 0;
uchar f1 = (uchar)qGray(image.pixel(j - 1, i - 1));
uchar f2 = (uchar)qGray(image.pixel(j - 1, i));
uchar f3 = (uchar)qGray(image.pixel(j - 1, i + 1));
uchar f4 = (uchar)qGray(image.pixel(j, i + 1));
uchar f5 = (uchar)qGray(image.pixel(j+ 1, i + 1));
uchar f6 = (uchar)qGray(image.pixel(j + 1, i));
uchar f7 = (uchar)qGray(image.pixel(j + 1, i - 1));
uchar f8 = (uchar)qGray(image.pixel(j, i - 1));
code |= (f1 > center) << 7;
code |= (f2 > center) << 6;
code |= (f3 > center) << 5;
code |= (f4 > center) << 4;
code |= (f5 > center) << 3;
code |= (f6 > center) << 2;
code |= (f7 > center) << 1;
code |= (f8 > center) << 0;
deal_image->setPixel(j-1,i-1,qRgb(code,code,code));
}
}
otp = *deal_image;
}
通常的理解的效率低LBP:
void usual_LBP(QImage &image,QImage &otp,int R,int P)
{
int width = image.width();
int height = image.height();
QImage* out = new QImage(width-2*R,height-2*R,QImage::Format_ARGB32);
Init_Image(*out,0);
int i = 0, j = 0;
double x=0,y=0;
double All_p = (double)P;
int center = 0;
uchar lbp = 0;
//計算領域值
QVector<double> neighbors_x;
QVector<double> neighbors_y;
//計算LBP領域
for(i = 0; i<P; i++)
{
x = R*cos(2.0*PI*i/All_p);
y = -R*sin(2.0*PI*i/All_p);
neighbors_x.push_back(x);
neighbors_y.push_back(y);
}
//循環每個像素
for(i = R; i<height-R-1; i++)
{
for(j = R; j<width-R-1; j++)
{
//中點像素值(目標)
center = (uchar)qGray(image.pixel(j,i));
lbp = 0;
//LBP領域與中點的判斷
for(int k = 0; k<neighbors_x.size(); k++)
{
//P個點的座標
y = i + neighbors_y[k];
x = j + neighbors_x[k];
//調用雙線性插值
uchar gray = (uchar)InterpBilinear(image,x,y);
//按順序累加
lbp |= (gray>center) <<k;
}
out->setPixel(j-R,i-R,qRgb(lbp,lbp,lbp));
}
}
otp = *out;
}
效率高的LBP:
void LBP(QImage &image, QImage &otp, int R, int P)
{
int width = image.width();
int height = image.height();
QImage* out = new QImage(width-2*R,height-2*R,QImage::Format_ARGB32);
Init_Image(*out,0);
int i = 0, j = 0;
float x=0,y=0;
float All_p = (float)P;
int center = 0;
int lbp = 0;
for(int k = 0; k<P;k++)
{
//圓的參數方程
x = R*cos(2.0*PI*k/All_p);
y = (-R)*sin(2.0*PI*k/All_p);
//對採樣點偏移量分別進行上下取整
int fx = (int)x;
int cx = fx+1;
int fy = (int)y;
int cy = fy + 1;
//將座標偏移量映射到0-1之間
float ty = y - fy;
float tx = x - fx;
//根據0-1之間的x,y的權重計算公式計算權重,權重與座標具體位置無關,與座標間的差值有關
float w1 = (1-tx) * (1-ty);
float w2 = tx * (1-ty);
float w3 = (1-tx) * ty;
float w4 = tx * ty;
//循環處理每個像素
for(i = R; i<height-R-1;i++)
{
for(j = R; j<width-R-1;j++)
{
//獲得中心像素點的灰度值
lbp = qGray(out->pixel(j-R,i-R));
center = qGray(image.pixel(j,i));
float f1 = qGray(image.pixel(j+fx,i+fy));
float f2 = qGray(image.pixel(j+fx,i+cy));
float f3 = qGray(image.pixel(j+cx,i+fy));
float f4 = qGray(image.pixel(j+cx,i+cy));
//根據雙線性插值公式計算第k個採樣點的灰度值
int neighbor = (f1 * w1) + (f3 * w2) + (f2 * w3) + (f4 * w4);
//LBP特徵圖像的每個鄰居的LBP值累加,累加通過與操作完成,對應的LBP值通過移位取得
lbp |= (neighbor>center) << k;
//cout<<lbp<<endl;
out->setPixel(j-R,i-R,qRgb(lbp,lbp,lbp));
}
}
}
otp = *out;
}