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