ããåæ
æ示ï¼è¦çæ代ç åï¼ä½ å¾å
ç¥éOpenCVçå®è£
åé
ç½®ï¼ä¼ç¨C++ï¼ç¨è¿ä¸äºOpenCVå½æ°ãåºæ¬çå¾åå¤çåç©éµç¥è¯ä¹æ¯éè¦çã[gm:ææ¯ç®«é¸£ç注é]ç±äºæä»
ä»
æ¯ç¿»è¯ï¼å¯¹äºå
级æè¿çæï¼è¯å®æä¸äºç¿»è¯éçæè
ä¸å½çå°æ¹ï¼æä»¥è¯·å¤§å®¶çº éã
ãã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
ãã令 2 表示ä¸ä¸ªéæºç¹å¾ï¼å
¶ä¸ 3 .
ãã计ç®åå¼åé 4
ãã5
ãã
ãã计ç®åæ¹å·®ç©éµ S
ãã6
ãã
ããè®¡ç® çç¹å¾å¼7 å对åºçç¹å¾åé 8 9
ãã
ãã对ç¹å¾å¼è¿è¡éåæåºï¼ç¹å¾åéåå®é¡ºåºä¸è´. K个主æåä¹å°±æ¯k个æ大çç¹å¾å¼å¯¹åºçç¹å¾åéã
ããxçK个主æ份:
ãã10
ãã
ããå
¶ä¸11 .
ããPCAåºçéæ:
ãã12
ãã
ããå
¶ä¸ 13 .
ããç¶åç¹å¾è¸éè¿ä¸é¢çæ¹å¼è¿è¡äººè¸è¯å«ï¼
ããAï¼ æææçè®ç»æ°æ®æå½±å°PCAå空é´
ããBï¼ æå¾
è¯å«å¾åæå½±å°PCAå空é´
ããCï¼ æ¾å°è®ç»æ°æ®æå½±åçåéåå¾
è¯å«å¾åæå½±åçåéæè¿çé£ä¸ªã
ããè¿æä¸ä¸ªé®é¢æå¾
解å³ãæ¯å¦æ们æ400å¼ å¾çï¼æ¯å¼ 100*100åç´ å¤§å°ï¼é£ä¹PCAéè¦è§£å³åæ¹å·®ç©éµ 14çæ±è§£ï¼è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;
ãã}