我是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);
}
}