OpenCV學習(35) OpenCV中的PCA算法

PCA算法的基本原理能夠參考:http://www.cnblogs.com/mikewolf2002/p/3429711.htmlhtml

    對一副寬p、高q的二維灰度圖,要完整表示該圖像,須要m = p*q維的向量空間,好比100*100的灰度圖像,它的向量空間爲100*100=10000。下圖是一個3*3的灰度圖和表示它的向量表示:ios

imageimage

該向量爲行向量,共9維,用變量表示就是[v0, v1, v2, v3, v4, v5, v6, v7, v8],其中v0...v8,的範圍都是0-255。算法

      如今的問題是假如咱們用1*10000向量,表示100*100的灰度圖,是否向量中的10000維對咱們一樣重要?確定不是這樣的,有些維的值可能對圖像更有用,有些維相對來講做用小些。爲了節省存儲空間,咱們須要對10000維的數據進行降維操做,這時就用到了PCA算法,該算法主要就是用來處理降維的,降維後會儘可能保留更有意義的維數,它的思想就是對於高維的數據集來講,一部分維數表示大部分有意義的數據app

算法的基本原理:ui

假設 image  表示一個特徵向量,其中 image【注:xi可能也是一個列向量】spa

1.計算均值向量 image3d

image

2.計算協方差矩陣 Scode

image

3.計算S的特徵值image   和對應的特徵向量image,根據線性代數知識咱們知道有公式:imagecomponent

4. 對特徵值按照大小進行遞減排序,特徵向量的順序和特徵值是一致的。假設咱們只須要保留K個維數(K<n),則咱們會選取特徵值最大的前K個特徵向量,用這K個特徵向量,來表示圖像,這K個向量就是圖像K個主成分份量。orm

對於被觀測的向量image,它的K個主成份量能夠經過下面公式計算獲得:

image其中image

由於W是正交矩陣,全部有image

下面咱們在OpenCV中看一個計算PCA的例子:

1.首先讀入10副人臉圖像,這些圖像大小相等,是一我的的各類表情圖片。

2.把圖片轉爲1*pq的一維形式,p是圖像寬,q是圖像高。這時咱們的S矩陣就是10行,每行是pq維的向量。

3.而後咱們在S上執行PCA算法,設置K=5,求得5個特徵向量,這5個特徵向量就是咱們求得的特徵臉,用這5個特徵臉圖像,能夠近似表示以前的十副圖像。

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/contrib/contrib.hpp"

#include <iostream>
#include <fstream>
#include <sstream>

using namespace cv;
using namespace std;




//把圖像歸一化爲0-255,便於顯示
Mat norm_0_255(const Mat& src)
{
Mat dst;
switch(src.channels())
{
case 1:
cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
break;
case 3:
cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
break;
default:
src.copyTo(dst);
break;
}
return dst;
}

//轉化給定的圖像爲行矩陣
Mat asRowMatrix(const vector<Mat>& src, int rtype, double alpha = 1, double beta = 0)
{
//樣本數量
size_t n = src.size();
//若是沒有樣本,返回空矩陣
if(n == 0)
return Mat();
//樣本的維數
size_t d = src[0].total();

Mat data(n, d, rtype);
//拷貝數據
for(int i = 0; i < n; i++)
{

if(src[i].empty())
{
string error_message = format("Image number %d was empty, please check your input data.", i);
CV_Error(CV_StsBadArg, error_message);
}
// 確保數據能被reshape
if(src[i].total() != d)
{
string error_message = format("Wrong number of elements in matrix #%d! Expected %d was %d.", i, d, src[i].total());
CV_Error(CV_StsBadArg, error_message);
}
Mat xi = data.row(i);
//轉化爲1行,n列的格式
if(src[i].isContinuous())
{
src[i].reshape(1, 1).convertTo(xi, rtype, alpha, beta);
} else {
src[i].clone().reshape(1, 1).convertTo(xi, rtype, alpha, beta);
}
}
return data;
}

int main(int argc, const char *argv[])
{

vector<Mat> db;

string prefix = "../att_faces/";

db.push_back(imread(prefix + "s1/1.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/2.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/3.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/4.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/5.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/6.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/7.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/8.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/9.pgm", IMREAD_GRAYSCALE));
db.push_back(imread(prefix + "s1/10.pgm", IMREAD_GRAYSCALE));

// Build a matrix with the observations in row:
Mat data = asRowMatrix(db, CV_32FC1);

// PCA算法保持5主成分份量
int num_components = 5;

//執行pca算法
PCA pca(data, Mat(), CV_PCA_DATA_AS_ROW, num_components);

//copy pca算法結果
Mat mean = pca.mean.clone();
Mat eigenvalues = pca.eigenvalues.clone();
Mat eigenvectors = pca.eigenvectors.clone();

//均值臉
imshow("avg", norm_0_255(mean.reshape(1, db[0].rows)));

//五個特徵臉
imshow("pc1", norm_0_255(pca.eigenvectors.row(0)).reshape(1, db[0].rows));
imshow("pc2", norm_0_255(pca.eigenvectors.row(1)).reshape(1, db[0].rows));
imshow("pc3", norm_0_255(pca.eigenvectors.row(2)).reshape(1, db[0].rows));
imshow("pc4", norm_0_255(pca.eigenvectors.row(3)).reshape(1, db[0].rows));
imshow("pc5", norm_0_255(pca.eigenvectors.row(4)).reshape(1, db[0].rows));

while(1)
waitKey(0);

// Success!
return 0;
}

咱們輸入的10副圖像爲:

image_thumbimage_thumb2image_thumb3image_thumb4image_thumb5image_thumb6image_thumb7image_thumb8image_thumb9image_thumb1

獲得的5副特徵臉爲:

imageimageimage

imageimage

均值臉爲:

image

 

程序代碼:參照工程FirstOpenCV32

相關文章
相關標籤/搜索