1.1.ä»ç»Introduction
ä»OpenCV2.4å¼å§ï¼å å
¥äºæ°çç±»FaceRecognizerï¼æ们å¯ä»¥ä½¿ç¨å®ä¾¿æ·å°è¿è¡äººè¸è¯å«å®éªãæ¬ææ¢ä»ç»ä»£ç 使ç¨ï¼åä»ç»ç®æ³å
çã(ä»åçæºä»£ç ï¼æ们å¯ä»¥å¨OpenCVçopencv\modules\contrib\doc\facerec\srcä¸æ¾å°ï¼å½ç¶ä¹å¯ä»¥å¨ä»ç
githubä¸æ¾å°ï¼å¦æä½ æ³ç 究æºç ï¼èªç¶å¯ä»¥å»ççï¼ä¸å¤æ)
ç®åæ¯æçç®æ³æ
Eigenfacesç¹å¾è¸createEigenFaceRecognizer()
Fisherfaces createFisherFaceRecognizer()
LocalBinary Patterns Histogramså±é¨äºå¼ç´æ¹å¾ createLBPHFaceRecognizer()
ä¸é¢ææçä¾åä¸ç代ç å¨OpenCVå®è£
ç®å½ä¸çsamples/cppä¸é¢é½è½æ¾å°ï¼ææç代ç åç¨æè
å¦ä¹ é½æ¯å
è´¹çã
1.2.人è¸è¯å«Face Recognition
对人类æ¥è¯´ï¼äººè¸è¯å«å¾å®¹æãæç®[Tu06]å
è¯æ们ï¼ä»
ä»
æ¯æä¸å¤©çå©´å¿å·²ç»å¯ä»¥åºåå¨å´çæç人è¸äºãé£ä¹å¯¹äºè®¡ç®æºæ¥è¯´ï¼å°åºæå¤é¾ï¼å
¶å®ï¼è¿ä»ä¸ºæ¢ï¼æ们对äºäººç±»èªå·±ä¸ºä½å¯ä»¥åºåä¸åç人æç¥
çå°ãæ¯äººè¸å
é¨ç¹å¾(ç¼çãé¼»åãå´å·´)è¿æ¯å¤é¨ç¹å¾(头åãåé
线)对äºäººç±»è¯å«æ´ææ?æ们æä¹åæä¸å¼ å¾åï¼å¤§èæ¯å¦ä½å¯¹å®ç¼ç çï¼David HubelåTorstenWieselå
æ们å±ç¤ºï¼æ们ç大èé对ä¸åçåºæ¯ï¼å¦çº¿ãè¾¹ãè§æè
è¿å¨è¿äºå±é¨ç¹å¾æä¸é¨çç¥ç»ç»èä½åºååºãæ¾ç¶æ们没ææä¸ççæé¶æ£çååï¼æ们çè§è§ç®å±å¿
须以æç§æ¹å¼æä¸åçä¿¡æ¯æ¥æºè½¬åææç¨ç模å¼ãèªå¨äººè¸è¯å«å°±æ¯å¦ä½ä»ä¸å¹
å¾åä¸æåææä¹çç¹å¾ï¼æå®ä»¬æ¾å
¥ä¸ç§æç¨ç表示æ¹å¼ï¼ç¶å对ä»ä»¬è¿è¡ä¸äº
åç±»ãåºäºå ä½ç¹å¾ç人è¸ç人è¸è¯å«å¯è½æ¯æç´è§çæ¹æ³æ¥è¯å«äººè¸ã第ä¸ä¸ªèªå¨äººè¸è¯å«ç³»ç»å¨[Kanade73]ä¸
åæè¿°ï¼æ è®°ç¹(ç¼çãè³æµãé¼»åççä½ç½®)ç¨æ¥æé ä¸ä¸ªç¹å¾åé(ç¹ä¸ç¹ä¹é´çè·ç¦»ãè§åº¦ç)ãéè¿è®¡ç®æµè¯åè®ç»å¾åçç¹å¾åéç欧æ°è·ç¦»æ¥è¿è¡è¯
å«ãè¿æ ·çæ¹æ³å¯¹äºå
ç
§ååå¾ç¨³å¥ï¼ä½ä¹æ巨大ç缺ç¹ï¼æ è®°ç¹çç¡®å®æ¯å¾å¤æçï¼å³ä½¿æ¯ä½¿ç¨æå
è¿çç®æ³ãä¸äºå ä½ç¹å¾äººè¸è¯å«è¿æå·¥ä½å¨æç®[Bru92]ä¸ææè¿°ãä¸ä¸ª22ç»´çç¹å¾åé被ç¨å¨ä¸ä¸ªå¤§æ°æ®åºä¸ï¼åé å ä½ç¹å¾ä¸è½æä¾è¶³å¤çä¿¡æ¯ç¨äºäººè¸è¯å«ã
ç¹å¾è¸æ¹æ³å¨æç®[TP91]ä¸
ææè¿°ï¼ä»æè¿°äºä¸ä¸ªå
¨é¢çæ¹æ³æ¥è¯å«äººè¸ï¼é¢é¨å¾åæ¯ä¸ä¸ªç¹ï¼è¿ä¸ªç¹æ¯ä»é«ç»´å¾å空é´æ¾å°å®å¨ä½ç»´ç©ºé´ç表示ï¼è¿æ ·åç±»åå¾å¾ç®åãä½ç»´å空é´ä½ç»´æ¯ä½¿
ç¨ä¸»å
åæ(Principal Component
Analysis,PCA)æ¾å°çï¼å®å¯ä»¥æ¾æ¥ææ大æ¹å·®çé£ä¸ªè½´ãè½ç¶è¿æ ·ç转æ¢æ¯ä»æä½³é建è§åº¦èèçï¼ä½æ¯ä»æ²¡æææ ç¾é®é¢èèè¿å»ã[gm:读æ
è¿æ®µéè¦ä¸äºæºå¨å¦ä¹ ç¥è¯]ãæ³è±¡ä¸ä¸ªæ
åµï¼å¦æååæ¯åºäºå¤é¨æ¥æºï¼æ¯å¦å
ç
§ãè½´çæ大æ¹å·®ä¸ä¸å®å
å«ä»»ä½æé´å«æ§çä¿¡æ¯ï¼å æ¤æ¤æ¶çåç±»æ¯ä¸å¯è½çã
å æ¤ï¼ä¸ä¸ªä½¿ç¨çº¿æ§é´å«(Linear Discriminant Analysis,LDA)çç¹å®ç±»æå½±æ¹æ³è¢«æåºæ¥è§£å³äººè¸è¯å«é®é¢[BHK97]ãå
¶ä¸ä¸ä¸ªåºæ¬çæ³æ³å°±æ¯ï¼ä½¿ç±»å
æ¹å·®æå°çåæ¶ï¼ä½¿ç±»å¤æ¹å·®æ大ã
è¿å¹´æ¥ï¼åç§å±é¨ç¹å¾æåæ¹æ³åºç°ã为äºé¿å
è¾å
¥çå¾åçé«ç»´æ°æ®ï¼ä»
ä»
使ç¨çå±é¨ç¹å¾æè¿°å¾åçæ¹æ³è¢«æåºï¼æåçç¹å¾(å¾æå¸æç)对äºå±é¨é®æ¡ãå
ç
§ååãå°æ ·æ¬çæ
åµæ´å¼ºå¥ãæå
³å±é¨ç¹å¾æåçæ¹æ³æç伯å°æ³¢(Gabor Waelets)([Wiskott97])ï¼ç¦»æ£å
ç«å¶åæ¢(DiscreteCosinus Transform,DCT)([Messer06])ï¼å±é¨äºå¼æ¨¡å¼(LocalBinary Patterns,LBP)([AHP04])ã使ç¨ä»ä¹æ¹æ³æ¥æåæ¶å空é´çå±é¨ç¹å¾ä¾æ§æ¯ä¸ä¸ªå¼æ¾æ§çç 究é®é¢ï¼å 为空é´ä¿¡æ¯æ¯æ½å¨æç¨çä¿¡æ¯ã
1.3.人è¸åºFace Database
æ们å
è·åä¸äºæ°æ®æ¥è¿è¡å®éªå§ãæä¸æ³å¨è¿éåä¸ä¸ªå¹¼ç¨çä¾åãæ们å¨ç 究人è¸è¯å«ï¼æ以æ们éè¦ä¸ä¸ªçç人è¸å¾åï¼ä½ å¯ä»¥èªå·±å建èªå·±çæ°æ®éï¼ä¹å¯ä»¥ä»è¿é(
http://face-rec.org/databases/)ä¸è½½ä¸ä¸ªã
AT&TFacedatabaseå称ORL人è¸æ°æ®åºï¼40个人ï¼æ¯äºº10å¼ ç
§çãç
§çå¨ä¸åæ¶é´ãä¸åå
ç
§ãä¸å表æ
(çç¼éç¼ãç¬æè
ä¸ç¬)ãä¸å人è¸ç»è(æ´ç¼éæè
ä¸æ´ç¼é)ä¸ééãææçå¾åé½å¨ä¸ä¸ªé»æååçèæ¯ä¸ééçï¼æ£é¢ç«ç´äººè¸(æäºææ轻微æ转)ã
YaleFacedatabase A ORL
æ°æ®åºå¯¹äºåå§åæµè¯æ¯è¾éåï¼ä½å®æ¯ä¸ä¸ªç®åçæ°æ®åºï¼ç¹å¾è¸å·²ç»å¯ä»¥è¾¾å°97%çè¯å«çï¼æä»¥ä½ ä½¿ç¨å
¶ä»æ¹æ³å¾é¾å¾å°æ´å¥½çæåãYale人è¸æ°æ®åº
æ¯ä¸ä¸ªå¯¹äºåå§å®éªæ´å¥½çæ°æ®åºï¼å 为è¯å«é®é¢æ´å¤æãè¿ä¸ªæ°æ®åºå
æ¬15个人(14个ç·äºº,1个女人)ï¼æ¯ä¸ä¸ªé½æ11个ç°åº¦å¾åï¼å¤§å°æ¯
320*243åç´ ãæ°æ®åºä¸æå
ç
§åå(ä¸å¿å
ç
§ã左侧å
ç
§ãå³ä¾§å
ç
§)ã表æ
åå(å¼å¿ãæ£å¸¸ãæ²ä¼¤ãçç¡ãæ讶ãç¨ç¼)ãç¼é(æ´ç¼éæè
没æ´)ã
åæ¶æ¯æ¯å®ä¸å¯ä»¥å
¬å¼ä¸è½½ï¼å¯è½å 为åæ¥çæå¡å¨åäºãä½æ们å¯ä»¥æ¾å°ä¸äºéå(æ¯å¦ theMIT)ä½æä¸è½ä¿è¯å®çå®æ´æ§ãå¦æä½ éè¦èªå·±åªè£åæ ¡åå¾åï¼å¯ä»¥é
读æçç¬è®°(bytefish.de/blog/fisherfaces)ã
ExtendedYale Facedatabase B æ¤æ°æ®åºå
å«38个人ç2414å¼ å¾çï¼å¹¶ä¸æ¯åªè£å¥½çãè¿ä¸ªæ°æ®åºéç¹æ¯æµè¯ç¹å¾æåæ¯å¦å¯¹å
ç
§åå强å¥ï¼å 为å¾åç表æ
ãé®æ¡çé½æ²¡ååãæ认为è¿ä¸ªæ°æ®åºå¤ªå¤§ï¼ä¸éåè¿ç¯æç« çå®éªï¼æ建议使ç¨ORLæ°æ®åºã
1.3.1. åå¤æ°æ®
æ们ä»ç½ä¸ä¸äºæ°æ®ï¼ä¸äºæ们éè¦å¨ç¨åºä¸è¯»åå®ï¼æå³å®ä½¿ç¨CSVæ件读åå®ãä¸ä¸ªCSVæ件å
å«æ件åï¼ç´§è·ä¸ä¸ªæ ç¾ã
/path/to/image.ext;0
å设/path/to/image.extæ¯å¾åï¼å°±åä½ å¨windowsä¸çc:/faces/person0/image0.jpgãæåæ们ç»å®ä¸
个æ ç¾0ãè¿ä¸ªæ ç¾ç±»ä¼¼ä»£è¡¨è¿ä¸ªäººçååï¼æ以åä¸ä¸ªäººçç
§ççæ ç¾é½ä¸æ ·ãæ们对ä¸è½½çORLæ°æ®åºè¿è¡æ è¯ï¼å¯ä»¥è·åå°å¦ä¸ç»æï¼
./at/s1/1.pgm;0
./at/s1/2.pgm;0
...
./at/s2/1.pgm;1
./at/s2/2.pgm;1
...
./at/s40/1.pgm;39
./at/s40/2.pgm;39
æ³è±¡æå·²ç»æå¾å解å缩å¨D:/data/atä¸é¢ï¼èCSVæ件å¨D:/data/at.txtãä¸é¢ä½ æ ¹æ®èªå·±çæ
åµä¿®æ¹æ¿æ¢å³å¯ãä¸æ¦ä½ æå建ç«CSVæ件ï¼å°±å¯ä»¥åè¿æ ·è¿è¡ç¤ºä¾ç¨åºï¼
facerec_demo.exe D:/data/at.txt
1.3.2 Creating the CSV File
ä½ ä¸éè¦æå·¥æ¥å建ä¸ä¸ªCSVæ件ï¼æå·²ç»åäºä¸ä¸ªPythonç¨åºæ¥åè¿äºã
[gm:说ä¸ä¸ªæå®ç°çæ¹æ³
å¦æä½ ä¼cmdå½ä»¤ï¼æè
称DOSå½ä»¤ï¼é£ä¹ä½ æå¼å½ä»¤æ§å¶å°ãå设æ们çå¾çæ¾å¨J:ä¸çFacesæ件夹ä¸ï¼å¯ä»¥è¾å
¥å¦ä¸è¯å¥ï¼
J:\Faces\ORL>dir /b/s *.bmp > at.txt
ç¶åä½ æå¼at.txtæ件å¯è½çå°å¦ä¸å
容(åé¢ç0ï¼1..æ ç¾æ¯èªå·±å ç)ï¼
ãããã
J:\Faces\ORL\s1\1.bmp;0
J:\Faces\ORL\s1\10.bmp;0
J:\Faces\ORL\s1\2.bmp;0
J:\Faces\ORL\s1\3.bmp;0
J:\Faces\ORL\s1\4.bmp;0
J:\Faces\ORL\s1\5.bmp;0
J:\Faces\ORL\s1\6.bmp;0
J:\Faces\ORL\s1\7.bmp;0
J:\Faces\ORL\s1\8.bmp;0
J:\Faces\ORL\s1\9.bmp;0
J:\Faces\ORL\s10\1.bmp;1
J:\Faces\ORL\s10\10.bmp;1
J:\Faces\ORL\s10\2.bmp;1
J:\Faces\ORL\s10\3.bmp;1
J:\Faces\ORL\s10\4.bmp;1
J:\Faces\ORL\s10\5.bmp;1
J:\Faces\ORL\s10\6.bmp;1
ãããã
èªç¶è¿æc++ç¼ç¨çæ¹æ³å¯ä»¥åå¾æ´å¥½ï¼çè¿ç¯æç« ååï¼å¦æå¾å¤äººéè¦ï¼æå°±æè¿é¨åç代ç ååºæ¥ã(éåå¤ä¸ªæ件夹ï¼æ ä¸æ ç¾)
]
ç¹å¾è¸Eigenfaces
æ们讲è¿ï¼å¾å表示çé®é¢æ¯ä»çé«ç»´é®é¢ãäºç»´ç°åº¦å¾åp*q大å°ï¼æ¯ä¸ä¸ªm=qpç»´çåé空é´ï¼æ以ä¸ä¸ª100*100åç´ å¤§å°çå¾åå°±æ¯10ï¼000
ç»´çå¾å空é´ãé®é¢æ¯ï¼æ¯ä¸æ¯ææçç»´æ°ç©ºé´å¯¹æ们æ¥è¯´é½æç¨ï¼æ们å¯ä»¥åä¸ä¸ªå³å®ï¼å¦ææ°æ®æä»»ä½å·®å¼ï¼æ们å¯ä»¥éè¿å¯»æ¾ä¸»å
æ¥ç¥é主è¦ä¿¡æ¯ã主æåå
æ(Principal Component Analysis,PCA)æ¯KarlPearson (1901)ç¬ç«å表çï¼è Harold Hotelling (1933)æä¸äºå¯è½ç¸å
³çåé转æ¢æä¸ä¸ªæ´å°çä¸ç¸å
³çåéãæ³æ³æ¯ï¼ä¸ä¸ªé«ç»´æ°æ®éç»å¸¸è¢«ç¸å
³åé表示ï¼å æ¤åªæä¸äºçç»´ä¸æ°æ®ææ¯ææä¹çï¼å
å«æå¤çä¿¡æ¯ãPCAæ¹æ³å¯»æ¾æ°æ®ä¸æ¥ææ大æ¹å·®çæ¹åï¼è¢«ç§°ä¸ºä¸»æåã
ç®æ³æè¿°Algorithmic Description
令 表示ä¸ä¸ªéæºç¹å¾ï¼å
¶ä¸ .
计ç®åå¼åé
计ç®åæ¹å·®ç©éµ S
è®¡ç® çç¹å¾å¼ å对åºçç¹å¾åé
对ç¹å¾å¼è¿è¡éåæåºï¼ç¹å¾åéåå®é¡ºåºä¸è´. K个主æåä¹å°±æ¯k个æ大çç¹å¾å¼å¯¹åºçç¹å¾åéã
xçK个主æ份:
å
¶ä¸ .
PCAåºçéæ:
å
¶ä¸ .
ç¶åç¹å¾è¸éè¿ä¸é¢çæ¹å¼è¿è¡äººè¸è¯å«ï¼
Aï¼ æææçè®ç»æ°æ®æå½±å°PCAå空é´
Bï¼ æå¾
è¯å«å¾åæå½±å°PCAå空é´
Cï¼ æ¾å°è®ç»æ°æ®æå½±åçåéåå¾
è¯å«å¾åæå½±åçåéæè¿çé£ä¸ªã
è¿æä¸ä¸ªé®é¢æå¾
解å³ãæ¯å¦æ们æ400å¼ å¾çï¼æ¯å¼ 100*100åç´ å¤§å°ï¼é£ä¹PCAéè¦è§£å³åæ¹å·®ç©éµ çæ±è§£ï¼èXç大å°æ¯10000*400ï¼é£ä¹æ们ä¼å¾å°10000*10000大å°çç©éµï¼è¿éè¦å¤§æ¦0.8GBçå
åã解å³è¿ä¸ªé®é¢ä¸å®¹æï¼æ以æ们éè¦å¦ä¸ä¸ªè®¡çãå°±æ¯è½¬ç½®ä¸ä¸åæ±ï¼ç¹å¾åéä¸ååãæç® [Duda01]ä¸ææè¿°ã
[gm:è¿ä¸ªPCAè¿æ¯èªå·±æççå§ï¼è¿éç讲çä¸æ¸
æ¥ï¼ä¸éååå¦è
ç]
OpenCVä¸ä½¿ç¨ç¹å¾è¸Eigenfaces in OpenCV
ç»åºç¤ºä¾ç¨åºæºä»£ç
#include "opencv2/core/core.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
usingnamespace cv;
usingnamespace std;
static Mat norm_0_255(InputArray _src) {
Mat src = _src.getMat();
// å建åè¿åä¸ä¸ªå½ä¸ååçå¾åç©éµ:
Mat dst;
switch(src.channels()) {
case1:
cv::normalize(_src, dst, 0,255, NORM_MINMAX, CV_8UC1);
break;
case3:
cv::normalize(_src, dst, 0,255, NORM_MINMAX, CV_8UC3);
break;
default:
src.copyTo(dst);
break;
}
return dst;
}
//使ç¨CSVæ件å»è¯»å¾ååæ ç¾ï¼ä¸»è¦ä½¿ç¨stringstreamågetlineæ¹æ³
staticvoid read_csv(const string& filename, vector<Mat>& images, vector<int>& labels, char separator =';') {
std::ifstream file(filename.c_str(), ifstream::in);
if (!file) {
string error_message ="No valid input file was given, please check the given filename.";
CV_Error(CV_StsBadArg, error_message);
}
string line, path, classlabel;
while (getline(file, line)) {
stringstream liness(line);
getline(liness, path, separator);
getline(liness, classlabel);
if(!path.empty()&&!classlabel.empty()) {
images.push_back(imread(path, 0));
labels.push_back(atoi(classlabel.c_str()));
}
}
}
int main(int argc, constchar*argv[]) {
// æ£æµåæ³çå½ä»¤ï¼æ¾ç¤ºç¨æ³
// å¦æ没æåæ°è¾å
¥åéåºï¼.
if (argc <2) {
cout <<"usage: "<< argv[0]<<" <csv.ext> <output_folder> "<< endl;
exit(1);
}
string output_folder;
if (argc ==3) {
output_folder = string(argv[2]);
}
//读åä½ çCSVæ件路å¾.
string fn_csv = string(argv[1]);
// 2个容å¨æ¥åæ¾å¾åæ°æ®å对åºçæ ç¾
vector<Mat> images;
vector<int> labels;
// 读åæ°æ®. å¦ææ件ä¸åæ³å°±ä¼åºé
// è¾å
¥çæ件åå·²ç»æäº.
try {
read_csv(fn_csv, images, labels);
} catch (cv::Exception& e) {
cerr <<"Error opening file \""<< fn_csv <<"\". Reason: "<< e.msg << endl;
// æ件æé®é¢ï¼æ们å¥ä¹åä¸äºäºï¼éåºäº
exit(1);
}
// å¦æ没æ读åå°è¶³å¤å¾çï¼æ们ä¹å¾éåº.
if(images.size()<=1) {
string error_message ="This demo needs at least 2 images to work. Please add more images to your data set!";
CV_Error(CV_StsError, error_message);
}
// å¾å°ç¬¬ä¸å¼ ç
§ççé«åº¦. å¨ä¸é¢å¯¹å¾å
// åå½¢å°ä»ä»¬åå§å¤§å°æ¶éè¦
int height = images[0].rows;
// ä¸é¢çå è¡ä»£ç ä»
ä»
æ¯ä»ä½ çæ°æ®éä¸ç§»é¤æåä¸å¼ å¾ç
//[gm:èªç¶è¿ééè¦æ ¹æ®èªå·±çéè¦ä¿®æ¹ï¼ä»è¿éç®åäºå¾å¤é®é¢]
Mat testSample = images[images.size() -1];
int testLabel = labels[labels.size() -1];
images.pop_back();
labels.pop_back();
// ä¸é¢å è¡å建äºä¸ä¸ªç¹å¾è¸æ¨¡åç¨äºäººè¸è¯å«ï¼
// éè¿CSVæ件读åçå¾ååæ ç¾è®ç»å®ã
// Tè¿éæ¯ä¸ä¸ªå®æ´çPCAåæ¢
//å¦æä½ åªæ³ä¿ç10个主æåï¼ä½¿ç¨å¦ä¸ä»£ç
// cv::createEigenFaceRecognizer(10);
//
// å¦æä½ è¿å¸æ使ç¨ç½®ä¿¡åº¦éå¼æ¥åå§åï¼ä½¿ç¨ä»¥ä¸è¯å¥ï¼
// cv::createEigenFaceRecognizer(10, 123.0);
//
// å¦æä½ ä½¿ç¨ææç¹å¾å¹¶ä¸ä½¿ç¨ä¸ä¸ªéå¼ï¼ä½¿ç¨ä»¥ä¸è¯å¥ï¼
// cv::createEigenFaceRecognizer(0, 123.0);
//
Ptr<FaceRecognizer> model = createEigenFaceRecognizer();
model->train(images, labels);
// ä¸é¢å¯¹æµè¯å¾åè¿è¡é¢æµï¼predictedLabelæ¯é¢æµæ ç¾ç»æ
int predictedLabel = model->predict(testSample);
//
// è¿æä¸ç§è°ç¨æ¹å¼ï¼å¯ä»¥è·åç»æåæ¶å¾å°éå¼:
// int predictedLabel = -1;
// double confidence = 0.0;
// model->predict(testSample, predictedLabel, confidence);
//
string result_message = format("Predicted class = %d / Actual class = %d.", predictedLabel, testLabel);
cout << result_message << endl;
// è¿éæ¯å¦ä½è·åç¹å¾è¸æ¨¡åçç¹å¾å¼çä¾åï¼ä½¿ç¨äºgetMatæ¹æ³:
Mat eigenvalues = model->getMat("eigenvalues");
// åæ ·å¯ä»¥è·åç¹å¾åé:
Mat W = model->getMat("eigenvectors");
// å¾å°è®ç»å¾åçåå¼åé
Mat mean = model->getMat("mean");
// ç°å®è¿æ¯ä¿å:
if(argc==2) {
imshow("mean", norm_0_255(mean.reshape(1, images[0].rows)));
} else {
imwrite(format("%s/mean.png", output_folder.c_str()), norm_0_255(mean.reshape(1, images[0].rows)));
}
// ç°å®è¿æ¯ä¿åç¹å¾è¸:
for (int i =0; i < min(10, W.cols); i++) {
string msg = format("Eigenvalue #%d = %.5f", i, eigenvalues.at<double>(i));
cout << msg << endl;
// å¾å°ç¬¬ #i个ç¹å¾
Mat ev = W.col(i).clone();
//æå®åæåå§å¤§å°ï¼ä¸ºäºææ°æ®æ¾ç¤ºå½ä¸åå°0~255.
Mat grayscale = norm_0_255(ev.reshape(1, height));
// 使ç¨ä¼ªå½©è²æ¥æ¾ç¤ºç»æï¼ä¸ºäºæ´å¥½çæå.
Mat cgrayscale;
applyColorMap(grayscale, cgrayscale, COLORMAP_JET);
// æ¾ç¤ºæè
ä¿å:
if(argc==2) {
imshow(format("eigenface_%d", i), cgrayscale);
} else {
imwrite(format("%s/eigenface_%d.png", output_folder.c_str(), i), norm_0_255(cgrayscale));
}
}
// å¨ä¸äºé¢æµè¿ç¨ä¸ï¼æ¾ç¤ºè¿æ¯ä¿åé建åçå¾å:
for(int num_components =10; num_components <300; num_components+=15) {
// ä»æ¨¡åä¸çç¹å¾åéæªåä¸é¨å
Mat evs = Mat(W, Range::all(), Range(0, num_components));
Mat projection = subspaceProject(evs, mean, images[0].reshape(1,1));
Mat reconstruction = subspaceReconstruct(evs, mean, projection);
// å½ä¸åç»æï¼ä¸ºäºæ¾ç¤º:
reconstruction = norm_0_255(reconstruction.reshape(1, images[0].rows));
// æ¾ç¤ºæè
ä¿å:
if(argc==2) {
imshow(format("eigenface_reconstruction_%d", num_components), reconstruction);
} else {
imwrite(format("%s/eigenface_reconstruction_%d.png", output_folder.c_str(), num_components), reconstruction);
}
}
// å¦ææ们ä¸æ¯åæ¾å°æ件ä¸ï¼å°±æ¾ç¤ºä»ï¼è¿é使ç¨äºæå®çå¾
é®çè¾å
¥:
if(argc==2) {
waitKey(0);
}
return0;
}
æ使ç¨äºä¼ªå½©è²å¾åï¼æä»¥ä½ å¯ä»¥çå°å¨ç¹å¾è¸ä¸ç°åº¦å¼æ¯å¦ä½åå¸çãä½ å¯ä»¥çå°ç¹å¾è¸ä¸ä½å¯¹äººè¸ç¹å¾è¿è¡ç¼ç ï¼è¿å¯¹è¿äºå¾åä¸çå
ç
§è¿è¡ç¼ç ã