1. 程式人生 > >opencv學習之(三)-LBP演算法的研究及其實現

opencv學習之(三)-LBP演算法的研究及其實現

一,原始LBP演算法

LBP的基本思想是對影象的畫素和它區域性周圍畫素進行對比後的結果進行求和。把這個畫素作為中心,對相鄰畫素進行閾值比較。如果中心畫素的亮度大於等於他的相鄰畫素,把他標記為1,否則標記為0。你會用二進位制數字來表示每個畫素,比如11001111。因此,由於周圍相鄰8個畫素,你最終可能獲取2^8個可能組合,被稱為區域性二值模式,有時被稱為LBP碼。第一個在文獻中描述的LBP運算元實際使用的是3*3的鄰域

33

一個更加正式的LBP操作可以被定義為

                     34

其中35 是中心畫素,亮度是36 ;而 37則是相鄰畫素的亮度。s是一個符號函式:

        38

這種描述方法使得你可以很好的捕捉到影象中的細節。實際上,研究者們可以用它在紋理分類上得到最先進的水平。正如剛才描述的方法被提出後,固定的近鄰區域對於尺度變化的編碼失效。所以,使用一個變數的擴充套件方法,在文獻[AHP04]中有描述。主意是使用可變半徑的圓對近鄰畫素進行編碼,這樣可以捕捉到如下的近鄰:

            39

對一個給定的點40   ,他的近鄰點 41 可以由如下計算:

        42

其中,R是圓的半徑,而P是樣本點的個數。

這個操作是對原始LBP運算元的擴充套件,所以有時被稱為擴充套件LBP(又稱為圓形LBP)。如果一個在圓上的點不在影象座標上,我們使用他的內插點。電腦科學有一堆聰明的插值方法,而OpenCV使用雙線性插值。

         43


二.原始LBP演算法的實現

附上程式碼:

// LBP.cpp : 定義控制檯應用程式的入口點。
//


/***********************************************************************
 * OpenCV 2.4.4 測試例程
 * 杜健健 提供
 ***********************************************************************/

#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include  <cv.h> 
#include  <highgui.h>
#include  <cxcore.h>
 
using namespace std;
using namespace cv;
 
//原始的LBP演算法
//使用模板引數

template <typename _Tp> static
void olbp_(InputArray _src, OutputArray _dst) {
    // get matrices
    Mat src = _src.getMat();
    // allocate memory for result
    _dst.create(src.rows-2, src.cols-2, CV_8UC1);
    Mat dst = _dst.getMat();
    // zero the result matrix
    dst.setTo(0);

	cout<<"rows "<<src.rows<<" cols "<<src.cols<<endl;
	cout<<"channels "<<src.channels();
	getchar();
    // calculate patterns
    for(int i=1;i<src.rows-1;i++) {
		cout<<endl;
        for(int j=1;j<src.cols-1;j++) {
			
            _Tp center = src.at<_Tp>(i,j);
			//cout<<"center"<<(int)center<<"  ";
            unsigned char code = 0;
            code |= (src.at<_Tp>(i-1,j-1) >= center) << 7;
            code |= (src.at<_Tp>(i-1,j  ) >= center) << 6;
            code |= (src.at<_Tp>(i-1,j+1) >= center) << 5;
            code |= (src.at<_Tp>(i  ,j+1) >= center) << 4;
            code |= (src.at<_Tp>(i+1,j+1) >= center) << 3;
            code |= (src.at<_Tp>(i+1,j  ) >= center) << 2;
            code |= (src.at<_Tp>(i+1,j-1) >= center) << 1;
            code |= (src.at<_Tp>(i  ,j-1) >= center) << 0;

            dst.at<unsigned char>(i-1,j-1) = code;
			//cout<<(int)code<<" ";
			//cout<<(int)code<<endl;
        }
    }
}

//基於舊版本的opencv的LBP演算法opencv1.0
void LBP (IplImage *src,IplImage *dst)
{
	int tmp[8]={0};
	CvScalar s;

	IplImage * temp = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U,1);
	uchar *data=(uchar*)src->imageData;
	int step=src->widthStep;

	cout<<"step"<<step<<endl;

	for (int i=1;i<src->height-1;i++)
	  for(int j=1;j<src->width-1;j++)
	  {
		  int sum=0;
		  if(data[(i-1)*step+j-1]>data[i*step+j])
			tmp[0]=1;
		  else
			tmp[0]=0;
		  if(data[i*step+(j-1)]>data[i*step+j])
			tmp[1]=1;
		  else
			tmp[1]=0;
		  if(data[(i+1)*step+(j-1)]>data[i*step+j])
			tmp[2]=1;
		  else
			tmp[2]=0;
		  if (data[(i+1)*step+j]>data[i*step+j])
			tmp[3]=1;
	  else
			tmp[3]=0;
		  if (data[(i+1)*step+(j+1)]>data[i*step+j])
			tmp[4]=1;
		  else
			tmp[4]=0;
		  if(data[i*step+(j+1)]>data[i*step+j])
			tmp[5]=1;
		  else
			tmp[5]=0;
		  if(data[(i-1)*step+(j+1)]>data[i*step+j])
			tmp[6]=1;
		  else
			tmp[6]=0;
		  if(data[(i-1)*step+j]>data[i*step+j])
			tmp[7]=1;
		  else
			tmp[7]=0;	
		  //計算LBP編碼
			s.val[0]=(tmp[0]*1+tmp[1]*2+tmp[2]*4+tmp[3]*8+tmp[4]*16+tmp[5]*32+tmp[6]*64+tmp[7]*128);
		
		cvSet2D(dst,i,j,s);寫入LBP影象
	  }
}



int _tmain(int argc, _TCHAR* argv[])
{
	//IplImage* face = cvLoadImage("D://input//yalefaces//01//s1.bmp",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
	IplImage* face = cvLoadImage("D://input//lena.jpg",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
	//IplImage* lbp_face =   cvCreateImage(cvGetSize(face), IPL_DEPTH_8U,1);

	IplImage* Gray_face = cvCreateImage( cvSize( face->width,face->height ), face->depth, 1);//先分配影象空間
    cvCvtColor(face, Gray_face ,CV_BGR2GRAY);//把載入影象轉換為灰度圖
	IplImage* lbp_face =   cvCreateImage(cvGetSize(Gray_face), IPL_DEPTH_8U,1);//先分配影象空間

	cvNamedWindow("Gray Image",1);
	cvShowImage("Gray Image",Gray_face);

	//Mat face2 = imread("D://input//buti.jpg",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
	Mat face2 = imread("D://input//yalefaces//01//s1.bmp",CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
	//Mat Gray_face2 = Mat::zeros(face2.size(),IPL_DEPTH_8U,1);

	//cvCvtColor(face2,Gray_face2,CV_BGR2RAY);
	Mat lbp_face2 = Mat::zeros(face2.size(),face2.type()) ;
	//Mat::copyTo(lbp_face,face);


	//顯示原始的輸入影象
	cvNamedWindow("Src Image",CV_WINDOW_AUTOSIZE);
	cvShowImage("Src Image",face);
	//imshow("Src Image",face);

	//計算輸入影象的LBP紋理特徵
    LBP(Gray_face,lbp_face);
	//olbp_<uchar>((Mat)face,(Mat)lbp_face);//有問題的呼叫
	olbp_<uchar>(face2,lbp_face2);

	
	//顯示第一幅影象的LBP紋理特徵圖
	cvNamedWindow("LBP Image",CV_WINDOW_AUTOSIZE);
	cvShowImage("LBP Image",lbp_face);
	//顯示第二幅圖 的LBP紋理特徵圖-一張yaleface人臉庫中的人臉LBP特徵圖
	namedWindow("LBP Image2",1);
	imshow("LBP Image2",lbp_face2);
	waitKey();

	//cvReleaseImage(&face);
	cvDestroyWindow("Src Image");
 
	return 0;

}



三.示例結果,LBP紋理特徵

原始影象lena.jpg

變換成灰度圖後:


提取圖片的LBP特徵:


提取人臉影象的LBP特徵;


四.注意事項

1 兩個函式都只能對灰度影象就行處理,所以,在使用這兩個函式時,必須先把原始影象轉換成灰度影象方可

2 關於早期只顯示影象1/3或者1/4區域的LBP紋理特徵問題的解決方法:

這個是因為你的輸入影象不是灰度圖的緣故,需要把彩色圖,多通道的影象轉換成單通道的影象,再作為引數傳入函式,才能得到完整影象的LBP紋理特徵。

3 載入灰度影象的方法:

把函式cvLoadImage()函式的第二個引數,還有imread() 的第二個引數設定成:CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR

就可以了。哦也,這個可是我在網上找了好久才解決的,分享一下,歡迎大家多多指點。

五.遇到的問題

就是使用Mat結構儲存彩色影象,多通道影象後,怎麼把它轉換成單通道的灰度圖。
我網上找了好多資料,沒發現有相關可以參考的函式可以直接呼叫。有一個提到可以使用IplImage和Mat相互轉化。我想用這種方法,就是先轉換再呼叫cvCvtColor() 進行灰度圖的轉化。但沒有試過,不知道可不可以。
如果有同學知道怎麼弄,歡迎告訴我一下,不勝感激

六.參考

opencv2.4.4中的facerec文件

等等。

相關推薦

opencv學習-LBP演算法研究及其實現

一,原始LBP演算法 LBP的基本思想是對影象的畫素和它區域性周圍畫素進行對比後的結果進行求和。把這個畫素作為中心,對相鄰畫素進行閾值比較。如果中心畫素的亮度大於等於他的相鄰畫素,把他標記為1,否則標記為0。你會用二進位制數字來表示每個畫素,比如11001111。因此,由於

OpenCV學習筆記影象畫素的提取

     提取影象的畫素及畫素索引 Mat src, dst; src = imread("mountainandwater.jpg"); //讀取影象 if (src.empty()) { qDebug()<<"can

WorkerMan 入門學習基礎教程-Timer類的使用

timer類 定時 基礎教程 連接 worker loader 入門 入門學習 json 1、ServerTimer.php 代碼: <?php /** * 定時器學習 */ require_once __DIR__ . ‘/Workerman/Autoload

OpenCV學習筆記31KAZE 演算法原理與原始碼分析KAZE的原始碼優化及與SIFT的比較

  KAZE系列筆記: 1.  OpenCV學習筆記(27)KAZE 演算法原理與原始碼分析(一)非線性擴散濾波 2.  OpenCV學習筆記(28)KAZE 演算法原理與原始碼分析(二)非線性尺度空間構建 3.  Op

OpenCV學習筆記30KAZE 演算法原理與原始碼分析KAZE特徵的效能分析與比較

      KAZE系列筆記: 1.  OpenCV學習筆記(27)KAZE 演算法原理與原始碼分析(一)非線性擴散濾波 2.  OpenCV學習筆記(28)KAZE 演算法原理與原始碼分析(二)非線性尺度空間構

Python + OpenCV 學習筆記>>> Numpy 陣列操作

將影象畫素迭代取反: import cv2 as cv import numpy as np def access_pixels(image): print(image.shape) height = image.shape[0]

opencv學習筆記:幾種去噪濾波器的實現

現在在上數字影象處理的課程,最近的一次作業要求不用OpenCV自帶的濾波器函式來實現幾種濾波器,以實現對加入椒鹽噪聲的影象的去噪。也是對markdown編輯器的一次練習。 椒鹽噪聲 椒鹽噪聲是一種很簡單的噪聲,即隨機將影象中一定數量的畫素點設定為0(黑)

人臉識別經典演算法實現——LBP演算法

第三種演算法稱之為LBP演算法,這個演算法的思路與PCA和Fisher有很大不同,他是考慮區域性特徵運算元,並不是全域性考慮。 這種演算法定義了一種LBP特徵,這種特徵與我們經常見到的Haar特徵、HoG特徵沒有啥太大不同,都是特徵運算元,只是演算法不同。因此,我們按照理解

Android驅動硬體訪問服務學習Android加入HAL層訪問硬體

硬體平臺:tiny4412系統:Android  5.0.2編譯器: arm-linux-gcc-4.5.1 當時我們把對硬體的操作放在了JNI層,但是Android並不是這樣,google提出HAL層,即硬體封裝層 這一節我們把硬體的操作封裝裝HAL層。 andr

opencv學習系列--- 細化演算法

演算法思想: 公式: y = p0*2^0 + p1*2^1+ p2*2^2 + p3*2^3 + p4*2^4 + p5*2^5 + p6*2^6 +p7*2^7          前輩們對此作出了總結,得出每個點周圍8領域的256種情況,放在一個char da

C#委託、事件學習——熱水器燒水案例

using System; namespace DelegateExample { public class Heater { private int temperature; public string type = "

裝置樹學習Clock

開發板:tiny4412SDK + S702 + 4GB Flash  要移植的核心版本:Linux-4.4.0 (支援device tree)  u-boot版本:友善之臂自帶的 U-Boot 2010.12  busybox版本:busybox 1.25 目標:

Netty學習--- 客戶端 服務端實現雙向通訊

客戶端-服務端:客戶端傳送資料到服務端 上篇文章提到,讀寫處理邏輯是在 Bootstrap的handler()方法指定的,上節課寫的如下程式碼: .handler(new ChannelInitializer<Channel>() {

NG機器學習總結-線性迴歸以及python實現

在前面已經簡單介紹了迴歸問題(預測房價),其實在統計學中,線性迴歸(Linear Regression)是利用被稱為線性迴歸方程的最小平方函式(Cost Function)對一個或多個自變數和因變數之間關係進行建模的一種迴歸分析。這種函式式一個或多個被稱為迴歸係數的模型引數的

訊息佇列-ActiveMQ學習筆記-釋出-訂閱訊息模式實現

釋出-訂閱訊息模式與點對點模式類似,只不過在session建立訊息佇列時,由session.createQuene()變為session.createTopic()。 訊息釋出者程式碼: package com.feiyang.activemq2; import java

機器學習整合學習AdaBoost演算法scikit-learn庫

一、AdaBoost類庫概述         scikit-learn中AdaBoost類庫比較直接,就是AdaBoostClassifier和AdaBoostRegressor兩個,從名字就可以看出AdaBoostClassifier用於分類,AdaBoostRegr

C#可擴展編程MEF學習筆記:導出類的方法和屬性

學習 說了 如何 mod ati dem ont num imp 前面說完了導入和導出的幾種方法,如果大家細心的話會註意到前面我們導出的都是類,那麽方法和屬性能不能導出呢???答案是肯定的,下面就來說下MEF是如何導出方法和屬性的。   還是前面的代碼,第二篇中已經提供了下

流媒體技術學習筆記Nginx-Rtmp-Module統計某頻道在線觀看流的客戶數

sele lec rest uri class origin 客戶 擴展 raw 獲得訂閱者人數,可以方便地顯示觀看流的客戶數。 查看已經安裝好的模塊 /usr/local/nginx/sbin/nginx -V 安裝從源編譯Nginx和Nginx-RTMP所

Openresty 學習筆記擴展庫neturl

編寫 hub clas 擴展庫 HR 寫文件 http www. 加密 github地址:https://github.com/golgote/neturl 最近在搞一個視頻加密播放,中間使用要用lua 匹配一個域名,判斷該域名是否正確 PS:使用PHP很好做,lua 的沒

人臉識別人臉對齊--AAM演算法原文: http://blog.csdn.net/colourfulcloud/article/details/9774017 AAM(Active Appear

原文: http://blog.csdn.net/colourfulcloud/article/details/9774017 AAM(Active Appearance Model)主動外觀模型主要分為兩個階段,模型建立階段和模型匹配階段。其中模型建立階段包括了對訓練樣本分別建立形狀模型(