主成分分析C ++ OpenCV

时间:2017-04-26 07:29:39

标签: c++ image opencv pca

我是OpenCV的新手,我正在尝试在AT&T database上实施主成分分析(Eigenspace)。特征值按10 ^ 6的顺序排列。结果令人失望,因为图像似乎是在特征向量的空间上随机投影的。类似的以及不同的图像之间的距离^ 2,大约10 ^ 8。以下是我的代码:

一些常数:

const int ROWSIZE = 112; //number of rows per image
const int COLSIZE = 92; //number of columns per image
int ROW = 92*112; //each image is represented as a column of size ROW*1
int PEOPLE = 3; // number of people in training set
int FACES = 3; // number of faces used per person
int COL = PEOPLE*FACES; //total number of training faces
static const double THRESHOLD = 0.9; //fraction of energy of eigenvalue to be chosen

以下是步骤: 将图像加载到图像矩阵,转换为CV_64F格式并将训练集中的图像转换为列。

img.convertTo(img1, CV_64F);
for (int i = 1; i <= PEOPLE; i++) {
    for (int j = 1; j <= FACES; j++) {
        for (int x = 0; x < ROWSIZE; x++) {
            for (int y = 0; y < COLSIZE; y++) {
                images.at<double>(x*COLSIZE+y, (i-1)*FACES+j-1) = 
                img1.at<double>(x, y);
            }
        }
    } 
}

将testImage转换为单列。

计算所有列的平均值,并使用

减去平均值
    Mat avg(ROW, 1, CV_64F, double(0));
    for (int j = 0; j < COL; j++) {
        avg += images.col(j);
    }
    avg = avg / COL;
    for (int j = 0; j < COL; j++) {
        images.col(j) = images.col(j) - avg;
    }

计算images.t()* images()的特征值和特征向量,因为它具有低维度

    Mat eig_val(COL, 1, CV_64F, double(0));
    Mat eig_vec(COL, COL, CV_64F, double(0));   
    eigen((images.t()*images), eig_val, eig_vec);

使用

计算重要的特征值
    double totalSum = 0;
    for (int i = 0; i < COL; i++) {
        totalSum += sqrt(eig_val.at<double>(i, 0));
    }
    double sum = 0; int k = 0;
    for (k = 0; k < COL; k++) {
        sum += sqrt(eig_val.at<double>(k, 0));
        if (sum > THRESHOLD*totalSum)break;
    }
    int sigValue = k + 1;

计算初始图像矩阵的归一化特征向量。请注意,特征向量是eig_vec矩阵的行

    Mat featureVec(sigValue, ROW, CV_64F, double(0));
    for (int i = 0; i < sigValue; i++) {
            featureVec.row(i) = eig_vec.row(i)*images.t();
            Mat d = featureVec.row(i)*featureVec.row(i).t();
            featureVec.row(i) = featureVec.row(i) / sqrt(d.at<double>(0,0));
    }   

计算转换的训练向量和测试向量

    Mat transformedData = featureVec*images;
    Mat transformedTestImage = featureVec*testImage;

获取与测试图像距离最小的训练图像的索引

    int imageIndex = -1; double currMin = 1000000000.0;
    for (int j = 0; j < COL; j++) {
        Mat mat = (transformedData.col(j).t() - transformedTestImage.col(0).t())*(transformedData.col(j) - transformedTestImage.col(0));
        if (currMin > mat.at<double>(0,0)){
            imageIndex = j;
            currMin = mat.at<double>(0, 0);
        }
    }

0 个答案:

没有答案