1. 程式人生 > >基於 OpenCV 的 LBP + SVM 人臉識別

基於 OpenCV 的 LBP + SVM 人臉識別

本文中對人臉的LBP特徵的提取,採用了LBP的圓形運算元,通過對ORL92112人臉庫中的樣本進行識別,據統計,訓練集與測試集的準確率均達到了100%;

經LBP處理後的影象如下圖所示:

如上圖所示,左側影象為原影象,右側影象為提取出的LBP影象;利用LBP圓形運算元,可以非常清晰描述出人臉特徵;

故,可以利用LBP運算元對人臉特徵進行提取並識別,而且在處理過程中,不受影象的光照、旋轉、角度等因素的影響;

演算法的處理程式碼如下所述:

LBP演算法標頭檔案:

head.h:

#ifndef _HEAD_H
#define _HEAD_H

#include <opencv2/opencv.hpp>
#include <iostream>
#include <cassert>
#include <vector>
#include <numeric>
#include <algorithm>
#include <functional>
#include <iterator>

#endif		// _HEAD_H
LBP.h
#ifndef _LBP_H
#define _LBP_H

#include "head.h"

typedef std::vector<double> VecDouble;
typedef std::vector<int> VecInt;
typedef std::vector<float> VecFloat;

class LBP
{
public:
	LBP();
	~LBP();

public:
	
	enum LBP_TYPE
	{
		LBP_UNIFORM = 0,		// uniform LBP
		LBP_NORMAL = 1,			// lbp
		LBP_CIRCLE = 2			// circular operator of lbp
	};

public:
	// 傳統的 LBP 演算法
	void calLBP(IplImage* srcImg, IplImage* dstImg);
	// LBP 圓形運算元演算法
	void calCirLBP(IplImage* srcImg, IplImage* dstImg, int radius, int neighbor);
	// uniform LBP 演算法
	void calUniformLBP(IplImage* src, IplImage* dst);

public:
	// 設定半徑
	void setRadius(int radius) { m_radius = radius; }
	// 設定領域數
	void setNeighbors(int neighbor) { m_neighbor = neighbor; }
	// 計算特徵值
	void calLBPFeatures(IplImage* srcImg, IplImage* dstImg, VecDouble& hist, LBP_TYPE lbpType);

private:
	int m_radius;
	int m_neighbor;

};

#endif  // _LBP_H

LBP.cpp
#include "stdafx.h"
#include "LBP.h"
#include <iostream>
using namespace std;

LBP::LBP()
	: m_radius(0)
	, m_neighbor(0)
{

}

LBP::~LBP()
{

}
//基於舊版本的opencv的LBP演算法opencv1.0  
// 3 x 3 矩陣如下所示
// [ 1, 2, 3]
// [ 8, ij,4]
// [ 7, 6, 5]

void LBP::calLBP(IplImage* srcImg, IplImage* dstImg)
{
	// 原影象為單通道影象,目標影象為單通道影象
	assert(srcImg != NULL && srcImg->nChannels == 1);
	assert(dstImg != NULL && dstImg->nChannels == 1);

	unsigned tmp[8] = { 0 };

	// 遍歷影象
	for (int rows = 1; rows < srcImg->height - 1; ++rows)
	{
		for (int cols = 1; cols < srcImg->width - 1; ++cols)
		{
			int sum = 0;
			double center = cvGetReal2D(srcImg, rows, cols);
			
			// 順時針遍歷
			double val = 0.0;
			// 左上角
			val = cvGetReal2D(srcImg, rows - 1, cols - 1);
			val > center ? tmp[0] = 1 : tmp[0] = 0;
			// 正上方
			val = cvGetReal2D(srcImg, rows, cols - 1);
			val > center ? tmp[1] = 1 : tmp[1] = 0;
			// 右上角
			val = cvGetReal2D(srcImg, rows + 1, cols - 1);
			val > center ? tmp[2] = 1 : tmp[2] = 0;
			// 右側
			val = cvGetReal2D(srcImg, rows + 1, cols);
			val > center ? tmp[3] = 1 : tmp[3] = 0;
			// 右下角
			val = cvGetReal2D(srcImg, rows + 1, cols + 1);
			val > center ? tmp[4] = 1 : tmp[4] = 0;
			// 下方
			val = cvGetReal2D(srcImg, rows, cols + 1);
			val > center ? tmp[5] = 1 : tmp[5] = 0;
			// 左下角
			val = cvGetReal2D(srcImg, rows - 1, cols + 1);
			val > center ? tmp[6] = 1 : tmp[6] = 0;
			// 左側
			val = cvGetReal2D(srcImg, rows - 1, cols);
			val > center ? tmp[7] = 1 : tmp[7] = 0;

			// 計算 LBP 編碼
			for (int i = 0; i < 8; ++i)
			{
				sum += tmp[i] * pow(2, i);
			}
			cvSetReal2D(dstImg, rows, cols, sum);
		}

	}// end for

}

// uniform LBP,一致區域性二值模式
void LBP::calUniformLBP(IplImage *src, IplImage *dst)
{
	assert(src != NULL && src->nChannels == 1);
	assert(dst != NULL && dst->nChannels == 1);

	int tmp[8] = { 0 };

	int rows = src->height - 1;
	int cols = src->width - 1;

	for (int i = 1; i < rows; ++i)
	{
		for (int j = 1; j < cols; ++j)
		{
			int sum = 0;
			double center = cvGetReal2D(src, i, j);

			// 順時針遍歷
			double val = 0.0;
			val = cvGetReal2D(src, i - 1, j - 1);		// 左上角
			val > center ? tmp[0] = 1 : tmp[0] = 0;
			val = cvGetReal2D(src, i, j - 1);			// 正上方
			val > center ? tmp[1] = 1 : tmp[1] = 0;
			val = cvGetReal2D(src, i + 1, j - 1);		// 右上角
			val > center ? tmp[2] = 1 : tmp[2] = 0;
			val = cvGetReal2D(src, i + 1, j);			// 右側
			val > center ? tmp[3] = 1 : tmp[3] = 0;
			val = cvGetReal2D(src, i + 1, j + 1);		// 右下角
			val > center ? tmp[4] = 1 : tmp[4] = 0;
			val = cvGetReal2D(src, i, j + 1);			// 正下方
			val > center ? tmp[5] = 1 : tmp[5] = 0;
			val = cvGetReal2D(src, i - 1, j + 1);		// 左下角
			val > center ? tmp[6] = 1 : tmp[6] = 0;
			val = cvGetReal2D(src, i - 1, j);			// 左側
			val > center ? tmp[7] = 1 : tmp[7] = 0;

			//計算0、1翻轉次數
			for (int k = 0; k < 8; k++)
			{
				if (k != 7)
				{
					sum += abs(tmp[k] - tmp[k + 1]);
				}
				else
				{
					sum += abs(tmp[k] - tmp[0]);
				}
			}
			//通過翻轉次數判斷具體特徵值
			if (sum <= 2)
			{
				for (int i = 0; i < 8; ++i)
				{
					sum += tmp[i] * pow(2, (7 - i));
				}

			}
			else
			{
				sum = 5; //將不滿足的取5
			}
			cvSet2D(dst, i, j, cvScalar(sum));
		}
	}
}

// 圓形 LBP 運算元
void LBP::calCirLBP(IplImage* src, IplImage* dst, int radius, int neighbors)
{
	// 處理的影象為單通道影象
	assert(src->nChannels == 1);

	for (int i = 0; i < neighbors; ++i)
	{
		// 正弦弧度
		double sRadian = sin(2.0 * CV_PI * i / static_cast<double>(neighbors));
		// 餘弦弧度
		double cRadian = cos(2.0 * CV_PI * i / static_cast<double>(neighbors));

		// 取樣點的計算
		double x = static_cast<double>(-radius * sRadian);
		double y = static_cast<double>(radius * cRadian);

		// 下取整的值
		int fx = static_cast<int>(floor(x));
		int fy = static_cast<int>(floor(y));
		// 上取整的值
		int cx = static_cast<int>(ceil(x));
		int cy = static_cast<int>(ceil(y));
		// 小數部分
		double tx = x - fx;
		double ty = y - fy;

		// 設定插值權重
		double w1 = (1 - tx) * (1 - ty);
		double w2 = tx * (1 - ty);
		double w3 = (1 - tx) * ty;
		double w4 = tx * ty;


		// 迴圈處理影象資料
		for (int rows = radius; rows < src->height - radius; ++rows)
		{
			for (int cols = radius; cols < src->width - radius; ++cols)
			{
				// 計算插值
				double t1 = w1 * cvGetReal2D(src, rows + fy, cols + fx);
				double t2 = w2 * cvGetReal2D(src, rows + fy, cols + cx);
				double t3 = w3 * cvGetReal2D(src, rows + cy, cols + fx);
				double t4 = w4 * cvGetReal2D(src, rows + cy, cols + cx);
				double t = t1 + t2 + t3 + t4;

				double val = cvGetReal2D(src, rows, cols);
				double epsilon = std::numeric_limits<double>::epsilon();

				uchar c = ((t > val) || abs(t - val) < epsilon);
				uchar tmp = c * pow(2, i);
				double v = cvGetReal2D(dst, rows - radius, cols - radius);
				v += tmp;
				cvSetReal2D(dst, rows - radius, cols - radius, v);
			}
		}

	}

}

// 計算 LPB 特徵值
void LBP::calLBPFeatures(IplImage* srcImg, IplImage* dstImg, VecDouble& hist, LBP_TYPE lbpType)
{
	assert(srcImg != NULL && srcImg->nChannels == 1);
	assert(dstImg != NULL && dstImg->nChannels == 1);

	// 計算 LBP 影象
	if (lbpType == LBP_NORMAL)
	{
		calLBP(srcImg, dstImg);
	}
	else if (lbpType == LBP_UNIFORM)
	{
		calUniformLBP(srcImg, dstImg);
	}
	else if (lbpType == LBP_CIRCLE)
	{
		
		try
		{
			if (m_radius == 0 || m_neighbor == 0)
			{
				throw "please call setRadius() and setNeighbor() to set values.";
			}
			else
			{
				calCirLBP(srcImg, dstImg, m_radius, m_neighbor);
			}
		}
		catch (char* e)
		{
			cout << e << endl;
		}

	}// end if

	// 計算直方圖
	VecInt vec;
	vec.resize(256);
	
	for (int i = 0; i < dstImg->width; ++i)
	{
		for (int j = 0; j < dstImg->height; ++j)
		{
			CvScalar s = cvGet2D(dstImg, j, i);
			int val = s.val[0];
			++vec[val];
		}
	}// end for

	// 將直方圖歸一化
	int maxVal = *max_element(vec.begin(), vec.end());
	int minVal = *min_element(vec.begin(), vec.end());

	for (int i = 0; i < vec.size(); ++i)
	{
		double tmp = 0.0;
		tmp = static_cast<double>(vec[i]) / static_cast<double>(maxVal);
		hist.push_back(tmp);
	}

}

相關推薦

基於 OpenCVLBP + SVM 人臉識別

本文中對人臉的LBP特徵的提取,採用了LBP的圓形運算元,通過對ORL92112人臉庫中的樣本進行識別,據統計,訓練集與測試集的準確率均達到了100%; 經LBP處理後的影象如下圖所示: 如上圖所示,左側影象為原影象,右側影象為提取出的LBP影象;利用LBP圓形運算元,可

基於PCA和SVM人臉識別之二.MATLAB實現

此文章中MATLAB實現均根據《數字影象處理與機器視覺----Visual c++ 與MATLAB實現》一書,我所獲得的基礎知識也大多源於此書,感謝!                          下面將我根據教程建立的工程以及敲擊的程式碼塊一一奉上,供日後參閱。建立以專

Linux系統下利用OpenCV實現人臉檢測和基於LBPH演算法的人臉識別

        本文主要的目的是進行人臉檢測和人臉識別。實驗環境為Ubuntu16.04 LTS虛擬機器版,技術為OpenCV,語言為c++。其中人臉檢測的主要過程是從一張圖片中檢測出人臉可以是一個或者是多個,然後用矩形或者圓形線圈標註出來。人臉識別是基於LBPH演算法實現

基於神經網路的人臉識別(Tensorflow,opencv,dlib,cnn,)

訓練一個神經網路 這段時間正在學習tensorflow的卷積神經網路部分,為了對卷積神經網路能夠有一個更深的瞭解,自己動手實現一個例程是比較好的方式,所以就選了一個這樣比較有點意思的專案。專案的github地址:github 喜歡的話就給個Star吧。想要她認得我,就需要給她一些我的照片,讓她記住我的人臉特徵

基於深度學習的人臉識別系統系列(Caffe+OpenCV+Dlib)——【三】使用Caffe的MemoryData層與VGG網路模型提取Mat的特徵

原文地址:http://m.blog.csdn.net/article/details?id=52456548 前言 基於深度學習的人臉識別系統,一共用到了5個開源庫:OpenCV(計算機視覺庫)、Caffe(深度學習庫)、Dlib(機器學習庫)、libfacede

Dlib+OpenCV深度學習人臉識別

row 拷貝 too 這一 驗證 message word endif all 目錄(?)[+] DlibOpenCV深度學習人臉識別 前言 人臉數據庫導入 人臉檢測 人臉識別 異常處理 Dlib+OpenCV深度學習人臉識別 前言 人臉

基於百度AI人臉識別技術的Demo

-a import arr readfile red ets 2.0 路徑 之前 編寫demo之前首先瀏覽官方API:http://ai.baidu.com/docs#/Face-API/top 下面是源碼: package com.examsafety.test;

執行svm人臉識別程式碼提示:Intel MKL FATAL ERROR: Cannot load libmkl_avx2.so or libmkl_def.so.

Intel MKL FATAL ERROR: Cannot load libmkl_avx2.so or libmkl_def.so. Process finished with exit code 2 在anaconda 的環境中,匯入from skimage import measure

基於協同表徵的人臉識別(CRC)演算法

1.標準的基於協同表徵的人臉識別(CRC)問題流程如下: (1)構建訓練樣本字典矩陣A和測試樣本y。假設訓練用的人臉庫中有a個人,每人b張人臉影象。對每張影象進行特徵提取。特徵提取的方法有:基於影象畫素點數值的方法,基於支援向量機的方法,基於子空間分析的方法,基於馬爾科夫鏈模型的方法,基於集合特

基於Opencv的物體輪廓識別

OpenCV是一個很強大的視覺庫,因此本次我們根據一個小例子來說明如何簡單的繪製一個物體的輪廓。  第一步:二值化   就是將影象上的畫素點的灰度值設定為0或255,也就是將整個影象呈現出明顯的只有黑和白的視覺效果,便於接下來的操作。  函式原型:    double

基於深度學習的人臉識別技術綜述

簡介:人臉識別是計算機視覺研究領域的一個熱點,同時人臉識別的研究領域非常廣泛。因此,本技術綜述限定於:一,在LFW資料集上(Labeled Faces in the Wild)獲得優秀結果的方法; 二,是採用深度學習的方法。 前言 LFW資料集(Labeled Fa

基於深度學習的人臉識別AI技術謎與思(十四)--臉型識別

所有圖片源自網路,無意冒犯,如覺不適,通知後立即刪除。 本文在頭條號和百家號同步首發 前言 2017年12月25日,百度大腦人臉模組再一次升級,由原來的1.6.9.0升級為2.0.0.0,自此之後,我們的人臉識別就採用最新的版本了。大公司時刻充滿了焦慮感和

基於深度學習的人臉識別綜述

本文轉載自 https://xraft.github.io/2018/03/21/FaceRecognition/ (作者:Caleb Ge (葛政)),如有侵權請告知刪除。 (下文中的“我”均為原文作者) 另附有查詢的其他參考連結: 論文介紹方面連結: 1、https://

SVM人臉識別分類案例(機器學習)

運用sklearn自帶的資料集做一個分類任務from sklearn.datasets import fetch_lfw_people faces = fetch_lfw_people(min_faces_per_person=60) fig, ax = plt.subplo

區域性二值模式LBP-簡單人臉識別(三)

一)區域性二值模式簡介 前面介紹過關於主成分分析法的識別方法,這個方法是選取的整幅影象的主成分分量來作為新的特徵,從某種意義上說這是一種基於全域性特徵的方法。但是一般影象識別中,僅僅使用全域性特徵是不夠的,獲得的識別率較低,更多的時候,表徵一副影象的特徵也缺少不了區域性

基於center loss的人臉識別模型對LFW人臉資料集進行評測(c++)

接上一篇博文,這篇博文主要是進行人臉識別中的第③和第四個步驟:特徵提取以及相似度計算。              center loss是2016的一篇ECCV論文中提出來的,A Discriminative Feature Learning Approach for De

手把手教你開發基於深度學習的人臉識別【考勤/簽到】系統

人臉識別介紹 人臉識別技術是一項非接觸式、使用者友好、非配合型的計算機視覺識別技術。隨著機器學習、深度學習等技術的發展,人臉識別的應用正日趨完善和成熟。本文將介紹人臉識別技術如何用於考勤/簽到系統。 本文將主要從以下幾個方面闡述: 平臺環境需求涉及的技術點人臉識

基於opencv的攝像頭臉部識別抓取及格式儲存(python)

剛接觸opencv,參照opencv的sample例子做了一個視訊頭像抓取的小程式碼,順便一起學習著用,先上視訊抓取及儲存程式碼: ? 1 2 3 4 5 6 7 8 9 10

SVM人臉識別

SVM在中等維度的分類問題中,有較好的表現,其在某種程度上構建了一個簡單的網路結構,類似於神經網路中的RBF神經網路。 人臉資料集是經典的分類和聚類問題中經常使用的資料集,維度相對不高,灰度影象,這裡選用64*64的人臉影象,將其reshape從1*64^2的一維陣列,共4

利用Python實現基於PCA演算法的人臉識別

        前面的文章中提到,利用opencv+python的組合可以方便的提取出影象中的人臉。當然,opencv自帶的提取演算法還是有很大缺陷的,不過並不妨礙我們的應用。接下來,利用python對已經獲許的人臉圖片進行訓練,從而可以識別出人臉。本文利用的PCA演算法,