00001 #include<cob_people_detection/subspace_analysis_fuerte.h>
00002
00003 #include "boost/filesystem/operations.hpp"
00004 #include "boost/filesystem/convenience.hpp"
00005 #include "boost/filesystem/path.hpp"
00006 #include <boost/thread/mutex.hpp>
00007 #include<opencv/cv.h>
00008 #include <opencv/cvaux.h>
00009 #include <opencv/highgui.h>
00010 #include <opencv/ml.h>
00011 void SubspaceAnalysis::error_prompt(std::string fct, std::string desc)
00012 {
00013 std::cerr << "ERROR\n";
00014 std::cerr << "Function:......... " << fct << std::endl;
00015 std::cerr << "Description:...... " << desc << std::endl;
00016 }
00017 void SubspaceAnalysis::dump_matrix(cv::Mat& mat, std::string filename)
00018 {
00019 std::string path = "/share/goa-tz/people_detection/eval/vis/";
00020 path.append(filename.c_str());
00021 std::ofstream os(path.c_str());
00022 for (int r = 0; r < mat.rows; r++)
00023 {
00024 for (int c = 0; c < mat.cols; c++)
00025 {
00026 os << mat.at<double>(r, c) << " ";
00027 }
00028 os << "\n";
00029 }
00030 os.close();
00031 }
00032
00033 void SubspaceAnalysis::condense_labels(std::vector<int>& labels)
00034 {
00035 int min_val = std::numeric_limits<int>::max();
00036 for (int i = 0; i < labels.size(); i++)
00037 {
00038 if (labels[i] < min_val)
00039 min_val = labels[i];
00040 }
00041 if (min_val > 0)
00042 {
00043 for (int i = 0; i < labels.size(); i++)
00044 {
00045 labels[i] -= min_val;
00046 }
00047 }
00048 }
00049 void SubspaceAnalysis::mat_info(cv::Mat& mat)
00050 {
00051
00052 for (int r = 0; r < mat.rows; r++)
00053 {
00054 for (int c = 0; c < mat.cols; c++)
00055 {
00056 std::cout << mat.at<float>(r, c) << " ";
00057 }
00058
00059 std::cout << "\n";
00060 }
00061 std::cout << "Matrix info:\n";
00062 std::cout << "rows= " << mat.rows << " cols= " << mat.cols << std::endl;
00063 std::cout << "Type = " << mat.type() << std::endl;
00064 std::cout << "Channels = " << mat.channels() << std::endl;
00065 }
00066 void SubspaceAnalysis::unique_elements(cv::Mat & mat, int& unique_elements, std::vector<int>& distinct_vec)
00067 {
00068 bool unique = true;
00069 for (int i = 0; i < mat.total(); ++i)
00070 {
00071
00072 if (i != 0)
00073 {
00074 unique = true;
00075 for (int j = 0; j < distinct_vec.size(); j++)
00076 {
00077 if (mat.at<float>(i) == distinct_vec[j])
00078 unique = false;
00079 }
00080 }
00081 if (unique == true)
00082 distinct_vec.push_back(mat.at<float>(i));
00083 }
00084 unique_elements = distinct_vec.size();
00085 }
00086 void SubspaceAnalysis::unique_elements(std::vector<int> & vec, int& unique_elements, std::vector<int>& distinct_vec)
00087 {
00088 bool unique = true;
00089 for (int i = 0; i < vec.size(); ++i)
00090 {
00091
00092 if (i != 0)
00093 {
00094 unique = true;
00095 for (int j = 0; j < distinct_vec.size(); j++)
00096 {
00097 if (vec[i] == distinct_vec[j])
00098 unique = false;
00099 }
00100 }
00101 if (unique == true)
00102 distinct_vec.push_back(vec[i]);
00103 }
00104 unique_elements = distinct_vec.size();
00105 }
00106
00107
00108
00109
00110
00111
00112 void SubspaceAnalysis::XFaces::calcDFFS(cv::Mat& orig_mat, cv::Mat& recon_mat, cv::Mat& avg, std::vector<double>& DFFS)
00113 {
00114
00115 cv::Mat temp = cv::Mat(orig_mat.rows, orig_mat.cols, orig_mat.type());
00116 orig_mat.copyTo(temp);
00117 DFFS.resize(recon_mat.rows);
00118 for (int i = 0; i < orig_mat.rows; i++)
00119 {
00120 cv::Mat recon_row = recon_mat.row(i);
00121 cv::Mat temp_row = temp.row(i);
00122 cv::subtract(temp_row, avg, temp_row);
00123 DFFS[i] = cv::norm(recon_row, temp_row, cv::NORM_L2);
00124 }
00125 return;
00126 }
00127
00128 void SubspaceAnalysis::XFaces::mat2arr(cv::Mat& src_mat, cv::Mat& dst_mat)
00129 {
00130
00131 dst_mat = src_mat.clone().reshape(1, 1);
00132
00133 return;
00134 }
00135 void SubspaceAnalysis::XFaces::project(cv::Mat& src_mat, cv::Mat& proj_mat, cv::Mat& avg_mat, cv::Mat& coeff_mat)
00136 {
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147 cv::gemm(src_mat, proj_mat, 1.0, cv::Mat(), 0.0, coeff_mat, cv::GEMM_2_T);
00148
00149 }
00150
00151 void SubspaceAnalysis::XFaces::reconstruct(cv::Mat& coeffs, cv::Mat& proj_mat, cv::Mat& avg, cv::Mat& rec_im)
00152 {
00153 cv::gemm(coeffs, proj_mat, 1.0, cv::Mat(), 0.0, rec_im);
00154 for (int i = 0; i < rec_im.rows; i++)
00155 {
00156 cv::Mat curr_row = rec_im.row(i);
00157 cv::add(curr_row, avg.reshape(1, 1), curr_row);
00158 }
00159 }
00160
00161 void SubspaceAnalysis::XFaces::calcDataMat(std::vector<cv::Mat>& input_data, cv::Mat& data_mat)
00162 {
00163
00164
00165
00166 for (int i = 0; i < input_data.size(); i++)
00167 {
00168 cv::Mat src_mat;
00169 src_mat = input_data[i];
00170 src_mat = src_mat.reshape(1, 1);
00171
00172
00173 cv::Mat dst_row = data_mat.row(i);
00174 src_mat.copyTo(dst_row);
00175 }
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219 return;
00220 }
00221
00222 void SubspaceAnalysis::XFaces::retrieve(std::vector<cv::Mat>& out_eigenvectors, cv::Mat& out_eigenvalues, cv::Mat& out_avg, cv::Mat& out_proj_model_data)
00223 {
00224
00225 avg_arr_.copyTo(out_avg);
00226 proj_model_data_arr_.copyTo(out_proj_model_data);
00227
00228 for (int r = 0; r < eigenvector_arr_.rows; r++)
00229 {
00230 cv::Mat curr_row = eigenvector_arr_.row(r);
00231
00232 curr_row.clone().reshape(1, sqrt(curr_row.cols));
00233 curr_row.convertTo(curr_row, CV_32FC1);
00234 curr_row.copyTo(out_eigenvectors[r]);
00235
00236 }
00237
00238 eigenvalue_arr_.copyTo(out_eigenvalues);
00239
00240 }
00241
00242 void SubspaceAnalysis::XFaces::getModel(cv::Mat& out_eigenvectors, cv::Mat& out_eigenvalues, cv::Mat& out_avg, cv::Mat& out_proj_model_data)
00243 {
00244 avg_arr_ .copyTo(out_avg);
00245 proj_model_data_arr_.copyTo(out_proj_model_data);
00246 eigenvector_arr_ .copyTo(out_eigenvectors);
00247 eigenvalue_arr_ .copyTo(out_eigenvalues);
00248 }
00249
00250 void SubspaceAnalysis::XFaces::retrieve(std::vector<cv::Mat>& out_eigenvectors, cv::Mat& out_eigenvalues, cv::Mat& out_avg, cv::Mat& out_proj_model_data, cv::Size output_dim)
00251 {
00252
00253 avg_arr_.copyTo(out_avg);
00254 proj_model_data_arr_.copyTo(out_proj_model_data);
00255
00256 for (int r = 0; r < eigenvector_arr_.rows; r++)
00257 {
00258 cv::Mat curr_row = eigenvector_arr_.row(r);
00259
00260 curr_row.clone().reshape(1, output_dim.height);
00261 curr_row.convertTo(curr_row, CV_32FC1);
00262 curr_row.copyTo(out_eigenvectors[r]);
00263
00264 }
00265
00266 eigenvalue_arr_.copyTo(out_eigenvalues);
00267
00268 }
00269
00270 void SubspaceAnalysis::XFaces::projectToSubspace(cv::Mat& probe_mat, cv::Mat& coeff_arr, double& DFFS)
00271 {
00272
00273 if (this->trained == false)
00274 {
00275 std::cout << "XFaces --> Model not trained - aborting projectToSubspace\n";
00276 return;
00277 }
00278
00279 cv::Mat src_arr;
00280 mat2arr(probe_mat, src_arr);
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291 project(src_arr, eigenvector_arr_, avg_arr_, coeff_arr);
00292
00293 cv::Mat rec_mat = cv::Mat(src_arr.rows, eigenvector_arr_.rows, CV_64FC1);
00294 reconstruct(coeff_arr, eigenvector_arr_, avg_arr_, rec_mat);
00295
00296 std::vector<double> DFFS_vec;
00297 DFFS_vec.push_back(DFFS);
00298 calcDFFS(src_arr, rec_mat, avg_arr_, DFFS_vec);
00299 DFFS = DFFS_vec[0];
00300
00301
00302
00303
00304
00306
00307 }
00308
00309 void SubspaceAnalysis::XFaces::calc_threshold(cv::Mat& data, std::vector<cv::Mat>& thresh)
00310 {
00311
00312 double sigma = 1.7f;
00313 thresh.resize(num_classes_);
00314 class_centers_ = cv::Mat::zeros(num_classes_, data.cols, CV_64FC1);
00315 SubspaceAnalysis::LDA lda;
00316 lda.calcClassMean(data, model_label_arr_, class_centers_, num_classes_);
00317
00318 cv::Mat max_arr, curr_mean, curr_sample, curr_max;
00319 max_arr = cv::Mat::ones(num_classes_, data.cols, CV_64FC1);
00320 max_arr *= std::numeric_limits<double>::min();
00321
00322 for (int i = 0; i < data.rows; i++)
00323 {
00324 int index = (int)model_label_arr_.at<float>(i);
00325 curr_sample = data.row(i);
00326 curr_mean = class_centers_.row(index);
00327 curr_max = max_arr.row(index);
00328 cv::max(curr_max, curr_sample - curr_mean, curr_max);
00329 }
00330
00331 for (int j = 0; j < num_classes_; j++)
00332 {
00333 cv::Mat curr_row = max_arr.row(j);
00334 thresh[j] = sigma * curr_row;
00335 }
00336 }
00337 void SubspaceAnalysis::XFaces::calc_threshold(cv::Mat& data, double& thresh)
00338 {
00339
00340
00341
00342 std::vector<double> P(num_classes_, std::numeric_limits<double>::max());
00343 std::vector<double> D(num_classes_, std::numeric_limits<double>::min());
00344 std::vector<double> Phi(num_classes_, std::numeric_limits<double>::max());
00345
00346 for (int i = 0; i < data.rows; i++)
00347 {
00348 cv::Mat i_row = data.row(i);
00349 for (int n = 0; n < data.rows; n++)
00350 {
00351 if (n == i)
00352 continue;
00353 cv::Mat n_row = data.row(n);
00354 double dist = cv::norm(i_row, n_row, cv::NORM_L2);
00355 if (model_label_arr_.at<float>(n) == model_label_arr_.at<float>(i))
00356 {
00357 D[model_label_arr_.at<float>(i)] = std::max(dist, D[model_label_arr_.at<float>(i)]);
00358 }
00359 else
00360 {
00361 P[model_label_arr_.at<float>(i)] = std::min(dist, P[model_label_arr_.at<float>(i)]);
00362 }
00363 }
00364 }
00365
00366
00367 if (num_classes_ == 1)
00368 {
00369 P[0] = D[0];
00370 }
00371
00372 for (int c = 0; c < num_classes_; c++)
00373 {
00374 thresh = std::min(thresh, (P[c] + D[c]) * 0.5);
00375
00376 }
00377 std::cout << "THRESH for db: " << thresh << std::endl;
00378
00379 }
00380
00381 void SubspaceAnalysis::XFaces::classify(cv::Mat& coeff_arr, Classifier method, int& class_index)
00382 {
00383 if (this->trained == false)
00384 {
00385 std::cout << "XFaces --> Model not trained - aborting classify\n";
00386 return;
00387 }
00388 if (coeff_arr.rows > 1)
00389 {
00390 std::cout << "[CLASSIFICATION] only implemented for single sample in single row" << std::endl;
00391 return;
00392 }
00393
00394 if (num_classes_ < 2)
00395 {
00396 method = SubspaceAnalysis::CLASS_DIFS;
00397 }
00398
00399 switch (method)
00400 {
00401 case SubspaceAnalysis::CLASS_DIFS:
00402 {
00403 double minDIFS;
00404 cv::Mat minDIFScoeffs;
00405 int minDIFSindex;
00406 calcDIFS(coeff_arr, minDIFSindex, minDIFS, minDIFScoeffs);
00407 class_index = (int)model_label_arr_.at<float>(minDIFSindex);
00408
00409 break;
00410 }
00411 ;
00412
00413 case SubspaceAnalysis::CLASS_KNN:
00414 {
00415
00416 if (!knn_trained_)
00417 {
00418
00419 cv::Mat data_float;
00420 proj_model_data_arr_.convertTo(data_float, CV_32FC1);
00421
00422 knn_.train(data_float, model_label_arr_);
00423 knn_trained_ = true;
00424 }
00425
00426
00427 cv::Mat sample;
00428 coeff_arr.convertTo(sample, CV_32FC1);
00429
00430 cv::Mat result;
00431
00432 class_index = (int)knn_.find_nearest(sample, 3);
00433
00434 break;
00435 }
00436 ;
00437 case SubspaceAnalysis::CLASS_SVM:
00438 {
00439
00440 if (!svm_trained_)
00441 {
00442
00443 CvSVMParams params;
00444 params.svm_type = CvSVM::C_SVC;
00445
00446 params.kernel_type = CvSVM::LINEAR;
00447 params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 50, 1e-5);
00448
00449 cv::Mat data_float;
00450 proj_model_data_arr_.convertTo(data_float, CV_32FC1);
00451
00452 svm_.train(data_float, model_label_arr_, cv::Mat(), cv::Mat(), params);
00453 svm_trained_ = true;
00454 }
00455
00456
00457 cv::Mat sample;
00458 coeff_arr.convertTo(sample, CV_32FC1);
00459
00460 class_index = (int)svm_.predict(sample);
00461
00462 break;
00463 }
00464 ;
00465 case SubspaceAnalysis::CLASS_RF:
00466 {
00467
00468 if (!rf_trained_)
00469 {
00470
00471 CvRTParams params;
00472
00473 cv::Mat data_float;
00474 proj_model_data_arr_.convertTo(data_float, CV_32FC1);
00475
00476 rf_.train(data_float, CV_ROW_SAMPLE, model_label_arr_, cv::Mat(), cv::Mat(), cv::Mat(), cv::Mat(), params);
00477 rf_trained_ = true;
00478 }
00479
00480
00481 cv::Mat sample;
00482 coeff_arr.convertTo(sample, CV_32FC1);
00483
00484 class_index = (int)rf_.predict(sample);
00485
00486 break;
00487 }
00488 ;
00489
00490 default:
00491 {
00492 std::cout << "[CLASSIFICATION] method not implemented" << std::endl;
00493 break;
00494 }
00495 ;
00496 }
00497
00498 if (use_unknown_thresh_)
00499 {
00500 verifyClassification(coeff_arr, class_index);
00501 }
00502 return;
00503
00504 }
00505
00506 void SubspaceAnalysis::XFaces::calcDIFS(cv::Mat& probe_mat, int& minDIFSindex, double& minDIFS, cv::Mat& minDIFScoeffs)
00507 {
00508 double temp;
00509 minDIFS = std::numeric_limits<int>::max();
00510 for (int r = 0; r < proj_model_data_arr_.rows; r++)
00511 {
00512 cv::Mat model_mat = proj_model_data_arr_.row(r);
00513 cv::Mat diff_row;
00514 cv::subtract(probe_mat, model_mat, diff_row);
00515 temp = cv::norm(diff_row, cv::NORM_L2);
00516 if (temp < minDIFS)
00517 {
00518 minDIFSindex = r;
00519 minDIFScoeffs = diff_row;
00520 minDIFS = temp;
00521 }
00522 }
00523
00524 return;
00525 }
00526
00527 void SubspaceAnalysis::XFaces::releaseModel()
00528 {
00529 num_classes_ = -1;
00530 ss_dim_ = -1;
00531 svm_trained_ = false;
00532 knn_trained_ = false;
00533 eigenvector_arr_.release();
00534 eigenvalue_arr_.release();
00535 avg_arr_.release();
00536 model_data_arr_.release();
00537 proj_model_data_arr_.release();
00538 model_label_arr_.release();
00539 ;
00540
00541 CvSVM svm_;
00542 CvKNearest knn_;
00543
00544 }
00545
00546 bool SubspaceAnalysis::XFaces::verifyClassification(cv::Mat& sample, int& index)
00547 {
00548
00549 double minDIFS = std::numeric_limits<double>::max();
00550 for (int n = 0; n < proj_model_data_arr_.rows; n++)
00551 {
00552 if (model_label_arr_.at<float>(n) == (float)index)
00553 {
00554 cv::Mat curr_row = proj_model_data_arr_.row(n);
00555 double dist = cv::norm(curr_row, sample, cv::NORM_L2);
00556 minDIFS = std::min(dist, minDIFS);
00557 }
00558 }
00559 if (minDIFS > thresh_)
00560 {
00561 std::cout << "NEW threshold: unknown " << minDIFS << std::endl;
00562 index = -1;
00563 return false;
00564 }
00565 return true;
00566 }
00567
00568
00569
00570
00571
00572 bool SubspaceAnalysis::Eigenfaces::init(std::vector<cv::Mat>& img_vec, std::vector<int>& label_vec, int& red_dim)
00573 {
00574 svm_trained_ = false;
00575 knn_trained_ = false;
00576 thresh_ = std::numeric_limits<double>::max();
00577 SubspaceAnalysis::unique_elements(label_vec, num_classes_, unique_labels_);
00578
00579 model_label_arr_ = cv::Mat(1, label_vec.size(), CV_32FC1);
00580 for (int i = 0; i < label_vec.size(); i++)
00581 {
00582 model_label_arr_.at<float>(i) = static_cast<float>(label_vec[i]);
00583 }
00584
00585 ss_dim_ = red_dim;
00586
00587
00588 if (img_vec.size() < ss_dim_ + 1)
00589 {
00590
00591 std::cout << "EIGFACE: Invalid subspace dimension\n";
00592 return false;
00593 }
00594
00595
00596 model_data_arr_ = cv::Mat(img_vec.size(), img_vec[0].total(), CV_64FC1);
00597 avg_arr_ = cv::Mat(1, img_vec[0].total(), CV_64FC1);
00598 proj_model_data_arr_ = cv::Mat(img_vec.size(), ss_dim_, CV_64FC1);
00599 eigenvector_arr_ = cv::Mat(ss_dim_, img_vec[0].total(), CV_64FC1);
00600 eigenvalue_arr_ = cv::Mat(ss_dim_, ss_dim_, CV_64FC1);
00601
00602 calcDataMat(img_vec, model_data_arr_);
00603
00604
00605
00606 pca_ = SubspaceAnalysis::PCA(model_data_arr_, ss_dim_);
00607
00608 eigenvector_arr_ = pca_.eigenvecs;
00609 eigenvalue_arr_ = pca_.eigenvals;
00610 avg_arr_ = pca_.mean;
00611
00612 project(model_data_arr_, eigenvector_arr_, avg_arr_, proj_model_data_arr_);
00613
00614 return true;
00615 }
00616
00617 void SubspaceAnalysis::Eigenfaces::meanCoeffs(cv::Mat& coeffs, std::vector<int>& label_vec, cv::Mat& mean_coeffs)
00618 {
00619
00620 mean_coeffs = cv::Mat::zeros(num_classes_, coeffs.cols, CV_64FC1);
00621 std::vector<int> samples_per_class(num_classes_);
00622
00623
00624 for (int i = 0; i < num_classes_; i++)
00625 {
00626 samples_per_class[i] = 0;
00627 }
00628
00629 int class_index;
00630 for (int i = 0; i < coeffs.rows; i++)
00631 {
00632 cv::Mat curr_row = coeffs.row(i);
00633 class_index = label_vec[i];
00634
00635 cv::Mat mean_row = mean_coeffs.row(class_index);
00636
00637 add(mean_row, curr_row, mean_row);
00638 samples_per_class[class_index]++;
00639 }
00640
00641 for (int i = 0; i < num_classes_; i++)
00642 {
00643 cv::Mat mean_row = mean_coeffs.row(i);
00644 mean_row.convertTo(mean_row, CV_64FC1, 1.0 / static_cast<double>(samples_per_class[i]));
00645
00646 }
00647 }
00648
00649
00650
00651
00652
00653
00654 bool SubspaceAnalysis::Fisherfaces::init(std::vector<cv::Mat>& img_vec, std::vector<int>& label_vec)
00655 {
00656 svm_trained_ = false;
00657 knn_trained_ = false;
00658 thresh_ = std::numeric_limits<double>::max();
00659
00660 if (img_vec.size() != label_vec.size())
00661 {
00662 std::cout << "ERROR : image and label vectors have to be of same length" << std::endl;
00663 return false;
00664 }
00665
00666 model_label_arr_ = cv::Mat(1, label_vec.size(), CV_32FC1);
00667 for (int i = 0; i < label_vec.size(); i++)
00668 {
00669 model_label_arr_.at<float>(i) = static_cast<float>(label_vec[i]);
00670 }
00671
00672
00673 model_data_arr_ = cv::Mat(img_vec.size(), img_vec[0].total(), CV_64FC1);
00674 avg_arr_ = cv::Mat(1, img_vec[0].total(), CV_64FC1);
00675
00676
00677 SubspaceAnalysis::unique_elements(label_vec, num_classes_, unique_labels_);
00678
00679 if (num_classes_ < 2)
00680 {
00681 std::cout << "FISHERFACES ERROR : More than one class is necessary" << std::endl;
00682 return false;
00683 }
00684
00685
00686 ss_dim_ = num_classes_ - 1;
00687
00688 int pca_dim = model_data_arr_.rows - num_classes_;
00689
00690 calcDataMat(img_vec, model_data_arr_);
00691
00692
00693 pca_ = SubspaceAnalysis::PCA(model_data_arr_, pca_dim);
00694
00695 cv::Mat proj_model_data_arr_PCA = cv::Mat(model_data_arr_.rows, pca_dim, CV_64FC1);
00696 project(model_data_arr_, pca_.eigenvecs, pca_.mean, proj_model_data_arr_PCA);
00697
00698
00699 cv::Mat P_pca = cv::Mat(pca_dim, img_vec[0].total(), CV_64FC1);
00700 P_pca = pca_.eigenvecs;
00701 avg_arr_ = pca_.mean;
00702
00703
00704 lda_ = SubspaceAnalysis::LDA(proj_model_data_arr_PCA, label_vec, num_classes_, ss_dim_);
00705
00706
00707 cv::Mat P_lda = cv::Mat(ss_dim_, pca_dim, CV_64FC1);
00708 P_lda = lda_.eigenvecs;
00709
00710
00711 cv::gemm(P_pca.t(), P_lda.t(), 1.0, cv::Mat(), 0.0, eigenvector_arr_);
00712
00713
00714 eigenvector_arr_ = eigenvector_arr_.t();
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724 proj_model_data_arr_ = cv::Mat(img_vec.size(), ss_dim_, CV_64FC1);
00725
00726 project(model_data_arr_, eigenvector_arr_, avg_arr_, proj_model_data_arr_);
00727
00728 return true;
00729
00730 }
00731
00732
00733
00734
00735
00736 SubspaceAnalysis::FishEigFaces::FishEigFaces()
00737 {
00738 fallback_ = false;
00739 svm_trained_ = false;
00740 knn_trained_ = false;
00741 use_unknown_thresh_ = true;
00742
00743
00744 thresh_ = std::numeric_limits<double>::max();
00745
00746 num_classes_ = -1;
00747
00748 }
00749
00750
00752
00753
00754 bool SubspaceAnalysis::FishEigFaces::init(std::vector<cv::Mat>& img_vec, std::vector<int>& label_vec, int& red_dim)
00755 {
00756 trainModel(img_vec, label_vec, red_dim);
00757 }
00758 bool SubspaceAnalysis::FishEigFaces::init(std::vector<cv::Mat>& img_vec, std::vector<int>& label_vec, int& red_dim, Method method)
00759 {
00760 trainModel(img_vec, label_vec, red_dim, method);
00761 }
00762 bool SubspaceAnalysis::FishEigFaces::init(std::vector<cv::Mat>& img_vec, std::vector<int>& label_vec, int& red_dim, Method method, bool fallback, bool use_unknown_thresh)
00763 {
00764 trainModel(img_vec, label_vec, red_dim, method, fallback, use_unknown_thresh);
00765 }
00766
00768
00769
00770 bool SubspaceAnalysis::XFaces::saveModel(std::string path)
00771 {
00772
00773 std::cout << "saving model" << std::endl;
00774
00775 if (boost::filesystem::is_regular_file(path.c_str()))
00776 {
00777 if (boost::filesystem::remove(path.c_str()) == false)
00778 {
00779
00780 error_prompt("saveModel()", "old rdata.xml can not be removed");
00781 return false;
00782 }
00783 }
00784 cv::FileStorage fileStorage(path.c_str(), cv::FileStorage::WRITE);
00785 if (!fileStorage.isOpened())
00786 {
00787 error_prompt("saveModel()", "Output path is invalid");
00788 return false;
00789 }
00790
00791 fileStorage << "eigenvectors" << eigenvector_arr_;
00792
00793 fileStorage << "eigenvalues" << eigenvalue_arr_;
00794
00795
00796 fileStorage << "average_image" << avg_arr_;
00797
00798
00799 fileStorage << "projected_model_data" << proj_model_data_arr_;
00800
00801 fileStorage << "model_data_labels" << model_label_arr_;
00802
00803 fileStorage.release();
00804
00805 return true;
00806 }
00807
00808 bool SubspaceAnalysis::XFaces::loadModelFromFile(std::string path, bool use_unknown_thresh)
00809 {
00810
00811
00812
00813
00814 cv::FileStorage fileStorage(path.c_str(), cv::FileStorage::READ);
00815 if (!fileStorage.isOpened())
00816 {
00817 error_prompt("loadModelFromFile()", "Invalid input file");
00818 return false;
00819 }
00820 else
00821 {
00822 fileStorage["eigenvectors"] >> eigenvector_arr_;
00823 fileStorage["eigenvalues"] >> eigenvalue_arr_;
00824 fileStorage["average_image"] >> avg_arr_;
00825 fileStorage["projected_model_data"] >> proj_model_data_arr_;
00826 fileStorage["model_data_labels"] >> model_label_arr_;
00827
00828 }
00829 fileStorage.release();
00830
00831
00832
00833 use_unknown_thresh_ = use_unknown_thresh;
00834
00835 SubspaceAnalysis::unique_elements(model_label_arr_, num_classes_, unique_labels_);
00836
00837 ss_dim_ = proj_model_data_arr_.cols;
00838
00839 if (use_unknown_thresh_)
00840 {
00841 std::cout << "calculating threshold...";
00842 calc_threshold(proj_model_data_arr_, thresh_);
00843 std::cout << "done" << std::endl;
00844 }
00845 this->trained = true;
00846 std::cout << "FishEigFaces --> model loaded successfully\n";
00847 return true;
00848
00849 }
00850
00851 bool SubspaceAnalysis::XFaces::loadModel(cv::Mat& eigenvec_arr, cv::Mat& eigenval_arr, cv::Mat& avg_arr, cv::Mat& proj_model, std::vector<int>& label_vec, bool use_unknown_thresh)
00852 {
00853
00854 if (label_vec.size() != proj_model.rows)
00855 {
00856 error_prompt("loadModel()", "#labels != #rows in projected model data");
00857 return false;
00858 }
00859
00860
00861 eigenvector_arr_ = eigenvec_arr;
00862 eigenvalue_arr_ = eigenval_arr;
00863 proj_model_data_arr_ = proj_model;
00864 avg_arr_ = avg_arr;
00865
00866 use_unknown_thresh_ = use_unknown_thresh;
00867
00868 SubspaceAnalysis::unique_elements(label_vec, num_classes_, unique_labels_);
00869 SubspaceAnalysis::condense_labels(label_vec);
00870 model_label_arr_ = cv::Mat(1, label_vec.size(), CV_32FC1);
00871 for (int i = 0; i < label_vec.size(); i++)
00872 {
00873 model_label_arr_.at<float>(i) = static_cast<float>(label_vec[i]);
00874 }
00875
00876 ss_dim_ = proj_model_data_arr_.cols;
00877
00878 if (use_unknown_thresh_)
00879 {
00880 std::cout << "calculating threshold...";
00881 calc_threshold(proj_model_data_arr_, thresh_);
00882 std::cout << "done" << std::endl;
00883 }
00884 this->trained = true;
00885 std::cout << "FishEigFaces --> model loaded successfully\n";
00886 return true;
00887 }
00888
00889 bool SubspaceAnalysis::FishEigFaces::trainModel(std::vector<cv::Mat>& img_vec, std::vector<int>& label_vec, int& red_dim)
00890 {
00891 trainModel(img_vec, label_vec, red_dim, SubspaceAnalysis::METH_FISHER, true, true);
00892 }
00893 bool SubspaceAnalysis::FishEigFaces::trainModel(std::vector<cv::Mat>& img_vec, std::vector<int>& label_vec, int& red_dim, Method method)
00894 {
00895 trainModel(img_vec, label_vec, red_dim, method, true, true);
00896 }
00897 bool SubspaceAnalysis::FishEigFaces::trainModel(std::vector<cv::Mat>& img_vec, std::vector<int>& label_vec, int& red_dim, Method method, bool fallback, bool use_unknown_thresh)
00898
00899 {
00900 fallback_ = fallback;
00901 use_unknown_thresh_ = use_unknown_thresh;
00902
00903
00904
00905
00906 SubspaceAnalysis::unique_elements(label_vec, num_classes_, unique_labels_);
00907 SubspaceAnalysis::condense_labels(label_vec);
00908
00909
00910
00911 ss_dim_ = red_dim;
00912 if (img_vec.size() < ss_dim_)
00913 {
00914 error_prompt("trainModel()", "Invalid subspace dimension");
00915 return false;
00916 }
00917
00918 if (label_vec.size() != img_vec.size())
00919 {
00920 return false;
00921 }
00922
00923 if (num_classes_ < 2)
00924 {
00925 if (fallback_)
00926 {
00927 method = SubspaceAnalysis::METH_EIGEN;
00928 std::cout << " Automatic Fallback to Eigenfaces" << std::endl;
00929 }
00930 else
00931 return false;
00932 }
00933
00934
00935 model_data_arr_ = cv::Mat(img_vec.size(), img_vec[0].total(), CV_64FC1);
00936 model_label_arr_ = cv::Mat(1, label_vec.size(), CV_32FC1);
00937 avg_arr_ = cv::Mat(1, img_vec[0].total(), CV_64FC1);
00938 proj_model_data_arr_ = cv::Mat(img_vec.size(), ss_dim_, CV_64FC1);
00939 eigenvector_arr_ = cv::Mat(ss_dim_, img_vec[0].total(), CV_64FC1);
00940 eigenvalue_arr_ = cv::Mat(ss_dim_, ss_dim_, CV_64FC1);
00941
00942 for (int i = 0; i < label_vec.size(); i++)
00943 {
00944 model_label_arr_.at<float>(i) = static_cast<float>(label_vec[i]);
00945 }
00946
00947 calcDataMat(img_vec, model_data_arr_);
00948
00949 int pca_dim;
00950 cv::Mat proj_model_data_arr_PCA, P_pca, P_lda;
00951 switch (method)
00952 {
00953 case SubspaceAnalysis::METH_FISHER:
00954 {
00955 std::cout << "FISHERFACES" << std::endl;
00956 if (num_classes_ < 2)
00957 {
00958 std::cout << "FISHERFACES ERROR : More than one class is necessary" << std::endl;
00959 return false;
00960 }
00961
00962 ss_dim_ = num_classes_ - 1;
00963
00964 pca_dim = model_data_arr_.rows - num_classes_;
00965
00966 pca_ = SubspaceAnalysis::PCA(model_data_arr_, pca_dim);
00967 proj_model_data_arr_PCA = cv::Mat(model_data_arr_.rows, pca_dim, CV_64FC1);
00968 project(model_data_arr_, pca_.eigenvecs, pca_.mean, proj_model_data_arr_PCA);
00969
00970
00971 P_pca = cv::Mat(pca_dim, img_vec[0].total(), CV_64FC1);
00972 P_pca = pca_.eigenvecs;
00973 avg_arr_ = pca_.mean;
00974
00975
00976 lda_ = SubspaceAnalysis::LDA(proj_model_data_arr_PCA, label_vec, num_classes_, ss_dim_);
00977
00978
00979 P_lda = cv::Mat(ss_dim_, pca_dim, CV_64FC1);
00980 P_lda = lda_.eigenvecs;
00981
00982
00983 cv::gemm(P_pca.t(), P_lda.t(), 1.0, cv::Mat(), 0.0, eigenvector_arr_);
00984
00985 eigenvector_arr_ = eigenvector_arr_.t();
00986 break;
00987
00988 case SubspaceAnalysis::METH_IFLDA:
00989 {
00990 if (num_classes_ < 2)
00991 {
00992 std::cout << "Improved FISHERFACES ERROR : More than one class is necessary" << std::endl;
00993 return false;
00994 }
00995
00996 ss_dim_ = num_classes_ - 1;
00997
00998 pca_dim = model_data_arr_.rows - num_classes_;
00999
01000 pca_ = SubspaceAnalysis::PCA(model_data_arr_, pca_dim);
01001 proj_model_data_arr_PCA = cv::Mat(model_data_arr_.rows, pca_dim, CV_64FC1);
01002 project(model_data_arr_, pca_.eigenvecs, pca_.mean, proj_model_data_arr_PCA);
01003
01004
01005 P_pca = cv::Mat(pca_dim, img_vec[0].total(), CV_64FC1);
01006 P_pca = pca_.eigenvecs;
01007 avg_arr_ = pca_.mean;
01008
01009
01010 lda_ = SubspaceAnalysis::ILDA(proj_model_data_arr_PCA, label_vec, num_classes_, ss_dim_);
01011
01012
01013 P_lda = cv::Mat(ss_dim_, pca_dim, CV_64FC1);
01014 P_lda = lda_.eigenvecs;
01015
01016
01017 cv::gemm(P_pca.t(), P_lda.t(), 1.0, cv::Mat(), 0.0, eigenvector_arr_);
01018
01019 eigenvector_arr_ = eigenvector_arr_.t();
01020 break;
01021 }
01022 }
01023
01024 case SubspaceAnalysis::METH_EIGEN:
01025 {
01026 std::cout << "EIGENFACES" << std::endl;
01027
01028 pca_ = SubspaceAnalysis::PCA(model_data_arr_, ss_dim_);
01029 eigenvector_arr_ = pca_.eigenvecs;
01030 eigenvalue_arr_ = pca_.eigenvals;
01031 avg_arr_ = pca_.mean;
01032 break;
01033 }
01034 case SubspaceAnalysis::METH_OCV_FISHER:
01035 {
01036 std::cout << "OpenCv Fisherfaces" << std::endl;
01037 cv::Ptr < cv::FaceRecognizer > model = cv::createFisherFaceRecognizer();
01038 model->train(img_vec, label_vec);
01039
01040 eigenvector_arr_ = model->getMat("eigenvectors").t();
01041 eigenvalue_arr_ = model->getMat("eigenvalues");
01042 avg_arr_ = model->getMat("mean");
01043 break;
01044 }
01045
01046 }
01047
01048 proj_model_data_arr_ = cv::Mat(img_vec.size(), ss_dim_, CV_64FC1);
01049
01050 project(model_data_arr_, eigenvector_arr_, avg_arr_, proj_model_data_arr_);
01051
01052
01053 if (use_unknown_thresh_)
01054 {
01055 std::cout << "calculating threshold...";
01056 calc_threshold(proj_model_data_arr_, thresh_);
01057 std::cout << "done" << std::endl;
01058 }
01059 this->trained = true;
01060
01061 return true;
01062
01063 }
01064
01065
01066
01067
01068 void SubspaceAnalysis::SSA::calcDataMatMean(cv::Mat& data, cv::Mat& mean_row)
01069 {
01070 for (int i = 0; i < data.rows; ++i)
01071 {
01072 cv::Mat data_row = data.row(i);
01073
01074 cv::add(mean_row, data_row, mean_row);
01075 }
01076 mean_row.convertTo(mean_row, CV_64F, 1.0 / static_cast<double>(data.rows));
01077
01078 }
01079
01080 void SubspaceAnalysis::SSA::decompose2(cv::Mat& data_mat)
01081 {
01082
01083 cv::Mat zero_mat = cv::Mat::zeros(1, data_mat.cols, CV_64FC1);
01084 cv::PCA pca(data_mat, zero_mat, CV_PCA_DATA_AS_ROW, ss_dim_);
01085 eigenvecs = pca.eigenvectors;
01086
01087
01088 eigenvals = pca.eigenvalues;
01089
01090 }
01091 void SubspaceAnalysis::SSA::decompose(cv::Mat& data_mat)
01092 {
01093
01094 data_mat.convertTo(data_mat, CV_64F, 1 / sqrt(data_mat.rows));
01095 cv::SVD svd(data_mat.t());
01096 eigenvecs = svd.u;
01097
01098 eigenvecs = eigenvecs.t();
01099
01100 eigenvals = svd.w;
01101
01102 }
01103
01104
01105
01106
01107 SubspaceAnalysis::LDA::LDA(cv::Mat& input_data, std::vector<int>& input_labels, int& num_classes, int& ss_dim)
01108 {
01109
01110 SubspaceAnalysis::unique_elements(input_labels, num_classes_, unique_labels_);
01111 cv::Mat data_work = input_data.clone();
01112 mean = cv::Mat::zeros(1, data_work.cols, CV_64FC1);
01113 calcDataMatMean(data_work, mean);
01114
01115
01116
01117
01118 class_mean_arr = cv::Mat::zeros(num_classes_, input_data.cols, CV_64FC1);
01119 calcClassMean(data_work, input_labels, class_mean_arr, num_classes_);
01120
01121 calcProjMatrix(data_work, input_labels);
01122
01123 eigenvecs = eigenvecs(cv::Rect(0, 0, input_data.cols, ss_dim));
01124 eigenvals = eigenvals(cv::Rect(0, 0, 1, ss_dim)).t();
01125
01126
01127 }
01128 void SubspaceAnalysis::LDA::calcClassMean(cv::Mat& data_mat, cv::Mat& label_mat, cv::Mat& class_mean_arr, int& num_classes)
01129 {
01130 std::vector<int> label_vec;
01131 for (int i = 0; i < label_mat.cols; i++)
01132 {
01133 label_vec.push_back((int)label_mat.at<float>(i));
01134 }
01135
01136 calcClassMean(data_mat, label_vec, class_mean_arr, num_classes);
01137
01138 }
01139 void SubspaceAnalysis::LDA::calcClassMean(cv::Mat& data_mat, std::vector<int>& label_vec, cv::Mat& class_mean_arr, int& num_classes)
01140 {
01141
01142 std::vector<int> samples_per_class(num_classes, 0);
01143
01144 int class_index;
01145 for (int i = 0; i < data_mat.rows; i++)
01146 {
01147 cv::Mat data_row = data_mat.row(i);
01148 class_index = label_vec[i];
01149 cv::Mat mean_row = class_mean_arr.row(class_index);
01150
01151 add(mean_row, data_row, mean_row);
01152 samples_per_class[class_index]++;
01153 }
01154
01155 for (int i = 0; i < num_classes; i++)
01156 {
01157 cv::Mat mean_arr_row = class_mean_arr.row(i);
01158 mean_arr_row.convertTo(mean_arr_row, CV_64FC1, 1.0 / static_cast<double>(samples_per_class[i]));
01159 }
01160
01161 }
01162
01163 void SubspaceAnalysis::LDA::calcProjMatrix(cv::Mat& data_arr, std::vector<int>& label_vec)
01164 {
01165
01166 cv::Mat S_intra = cv::Mat::zeros(data_arr.cols, data_arr.cols, CV_64FC1);
01167 cv::Mat S_inter = cv::Mat::zeros(data_arr.cols, data_arr.cols, CV_64FC1);
01168 int class_index;
01169
01170 for (int i = 0; i < data_arr.rows; ++i)
01171 {
01172
01173 class_index = label_vec[i];
01174
01175
01176 cv::Mat data_row = data_arr.row(i);
01177 cv::Mat class_mean_row = class_mean_arr.row(class_index);
01178
01179
01180 cv::subtract(data_row, class_mean_row, data_row);
01181
01182
01183 }
01184 for (int c = 0; c < num_classes_; c++)
01185 {
01186 cv::Mat temp;
01187 class_index = unique_labels_[c];
01188 cv::Mat class_mean_row = class_mean_arr.row(class_index);
01189 cv::subtract(class_mean_row, mean, temp);
01190 cv::mulTransposed(temp, temp, true);
01191 cv::add(S_inter, temp, S_inter);
01192
01193 }
01194
01195 cv::mulTransposed(data_arr, S_intra, true);
01196
01197 cv::Mat S_intra_inv = S_intra.inv();
01198
01199 cv::Mat P;
01200 gemm(S_intra_inv, S_inter, 1.0, cv::Mat(), 0.0, P);
01201
01202 decompose(P);
01203
01204 return;
01205
01206 }
01207
01208
01209
01210
01211
01212 SubspaceAnalysis::ILDA::ILDA(cv::Mat& input_data, std::vector<int>& input_labels, int& num_classes, int& ss_dim)
01213 {
01214 SubspaceAnalysis::unique_elements(input_labels, num_classes_, unique_labels_);
01215 cv::Mat data_work = input_data.clone();
01216 mean = cv::Mat::zeros(1, data_work.cols, CV_64FC1);
01217 calcDataMatMean(data_work, mean);
01218 num_classes_ = num_classes;
01219
01220
01221
01222
01223 class_mean_arr = cv::Mat::zeros(num_classes_, input_data.cols, CV_64FC1);
01224 calcClassMean(data_work, input_labels, class_mean_arr, num_classes_);
01225
01226 calcProjMatrix(data_work, input_labels);
01227
01228 eigenvecs = eigenvecs(cv::Rect(0, 0, input_data.cols, ss_dim));
01229 eigenvals = eigenvals(cv::Rect(0, 0, 1, ss_dim)).t();
01230
01231 }
01232 void SubspaceAnalysis::ILDA::calcProjMatrix(cv::Mat& data_arr, std::vector<int>& label_vec)
01233 {
01234
01235
01236
01237
01238
01239 cv::Mat S_intra = cv::Mat::zeros(data_arr.cols, data_arr.cols, CV_64FC1);
01240 cv::Mat S_inter = cv::Mat::zeros(data_arr.cols, data_arr.cols, CV_64FC1);
01241 int class_index;
01242
01243 for (int i = 0; i < data_arr.rows; ++i)
01244 {
01245
01246 class_index = label_vec[i];
01247
01248
01249 cv::Mat data_row = data_arr.row(i);
01250 cv::Mat class_mean_row = class_mean_arr.row(class_index);
01251
01252
01253 cv::subtract(data_row, class_mean_row, data_row);
01254
01255
01256 }
01257 for (int c = 0; c < num_classes_; c++)
01258 {
01259 cv::Mat temp;
01260 class_index = unique_labels_[c];
01261 cv::Mat class_mean_row = class_mean_arr.row(class_index);
01262 cv::subtract(class_mean_row, mean, temp);
01263 cv::mulTransposed(temp, temp, true);
01264 cv::add(S_inter, temp, S_inter);
01265
01266 }
01267
01268 cv::mulTransposed(data_arr, S_intra, true);
01269 cv::Mat S_intra_inv = S_intra.inv();
01270 cv::Mat sigma = cv::Mat(1, num_classes_, CV_64FC1);
01271
01272 for (int i = 0; i < num_classes_; ++i)
01273 {
01274 cv::Mat mu_i = class_mean_arr.row(i);
01275 for (int j = 0; j < num_classes_; ++j)
01276 {
01277 cv::Mat mu_j = class_mean_arr.row(j);
01278
01279 cv::Mat delta_ij = ((mu_j - mu_i) * S_intra_inv * (mu_j - mu_i).t());
01280 for (int k = 0; k < data_arr.rows; k++)
01281 {
01282
01283 }
01284 sigma.at<double>(j) = 1 / (delta_ij.at<double>(0, 0));
01285 }
01286
01287 }
01288
01289 for (int j = 0; j < num_classes_; j++)
01290 {
01291 class_index = label_vec[j];
01292
01293
01294 cv::Mat s_intra_row = S_intra.row(j);
01295 cv::Mat s_inter_row = S_inter.row(j);
01296 double sigma_j = sigma.at<double>(class_index);
01297 s_intra_row *= sigma_j;
01298 s_inter_row *= sigma_j;
01299 }
01300
01301 S_intra_inv = S_intra.inv();
01302
01303 cv::Mat P;
01304 gemm(S_intra_inv, S_inter, 1.0, cv::Mat(), 0.0, P);
01305
01306 decompose(P);
01307
01308 return;
01309
01310 }
01311
01312
01313
01314
01315 SubspaceAnalysis::PCA::PCA(cv::Mat& input_data, int& ss_dim)
01316 {
01317 ss_dim_ = ss_dim;
01318 cv::Mat data_work = input_data.clone();
01319 mean = cv::Mat::zeros(1, data_work.cols, CV_64FC1);
01320 calcDataMatMean(data_work, mean);
01321 calcProjMatrix(data_work);
01322
01323 eigenvecs = eigenvecs(cv::Rect(0, 0, input_data.cols, ss_dim));
01324 eigenvals = eigenvals(cv::Rect(0, 0, 1, ss_dim)).t();
01325
01326
01327
01328
01329
01330
01331
01332
01333
01334
01335 }
01336
01337 void SubspaceAnalysis::PCA::calcProjMatrix(cv::Mat& data)
01338 {
01339 cv::Mat data_row;
01340 for (int i = 0; i < data.rows; ++i)
01341 {
01342
01343 data_row = data.row(i);
01344 cv::subtract(data_row, mean, data_row);
01345 }
01346
01347 decompose(data);
01348 }
01349