PageRenderTime 194ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/ facerecog --username xjed09/FaceMngr/FaceMngr_complete.cpp

http://facerecog.googlecode.com/
C++ | 429 lines | 358 code | 64 blank | 7 comment | 67 complexity | 5688939ffd11b1dd67eeda93215ef3e2 MD5 | raw file
  1. #define DLLSRC
  2. #include "FaceMngr_complete.h"
  3. #ifdef COMPILE_MNGR_COMPLETE
  4. CFaceMngr::CFaceMngr(void)
  5. {
  6. tfaceImg8 = tfaceImg32 = tfeature = tmodel = NULL;
  7. align = NULL;
  8. light = NULL;
  9. feature = NULL;
  10. ss = NULL;
  11. }
  12. CFaceMngr::~CFaceMngr(void)
  13. {
  14. cvReleaseMat(&tfaceImg8);
  15. cvReleaseMat(&tfaceImg32);
  16. cvReleaseMat(&tfeature);
  17. delete align;
  18. delete light;
  19. delete feature;
  20. delete ss;
  21. ClearList();
  22. }
  23. bool CFaceMngr::Init( CvSize faceSz /*= cvSize(0,0)*/ )
  24. {
  25. align = new CFaceAlign;
  26. if (! align->Init(faceSz)) return false;
  27. m_faceSz = align->m_faceSz;
  28. light = new CLightPrep;
  29. if (! light->Init(m_faceSz, true)) return false;
  30. feature = new CFaceFeature;
  31. if (! (m_featureSz = feature->Init(m_faceSz, light->m_mask))) return false;
  32. ss = new CSubspace;
  33. tfaceImg8 = cvCreateMat(m_faceSz.height, m_faceSz.width, CV_8UC1);
  34. tfaceImg32 = cvCreateMat(m_faceSz.height, m_faceSz.width, CV_32FC1);
  35. tfeature = cvCreateMat(m_featureSz, 1, CV_FT_FC1);
  36. stamp = 0;
  37. return true;
  38. }
  39. bool CFaceMngr::Pic2NormFace( CvArr *pic, CvMat *faceImg8, DWORD flag /*= FM_DO_NORM*/,
  40. CvPoint2D32f *leftEye /*= NULL*/, CvPoint2D32f *rightEye /*= NULL*/ )
  41. {
  42. IplImage *tpic8 = NULL;
  43. bool isrgb = false;
  44. if (! CV_IS_GRAY(pic))
  45. {
  46. isrgb = true;
  47. CvSize picSz = cvGetSize(pic);
  48. tpic8 = cvCreateImage(picSz, 8, 1);
  49. cvCvtColor(pic, tpic8, CV_BGR2GRAY);
  50. }
  51. else tpic8 = (IplImage *)pic;
  52. if (flag & FM_DO_FACE_ALIGN)
  53. {
  54. #ifdef COMPILE_ALIGN_COORD
  55. if ( ! align->GetFace(tpic8, faceImg8, leftEye, rightEye) ) // ???FaceAlign_Coord?
  56. #else
  57. if ( ! align->GetFace(tpic8, faceImg8, flag & FM_ALIGN_USE_BUF) ) // ??????????
  58. #endif
  59. {
  60. if(isrgb) cvReleaseImage(&tpic8);
  61. return false;
  62. }
  63. }
  64. else cvResize(tpic8, faceImg8, CV_INTER_NN); // if flag & FM_DO_FACE_ALIGN
  65. if (flag & FM_DO_LIGHT_PREP)
  66. light->RunLightPrep(faceImg8);
  67. if (isrgb) cvReleaseImage(&tpic8);
  68. return true;
  69. }
  70. bool CFaceMngr::NormFace2Model( CvArr *faceImg8, CvMat *model )
  71. {
  72. if (! ss->m_bTrained)
  73. {
  74. ::MessageBox1("Can't generate model: training hasn't done!");
  75. return false;
  76. }
  77. cvConvertScale(faceImg8, tfaceImg32, 1.0/255);
  78. feature->GetFeature(tfaceImg32, tfeature);
  79. ss->Project(tfeature, model);
  80. return true;
  81. }
  82. void CFaceMngr::SaveToModel( LPCTSTR path, int classId, CvMat *model )
  83. {
  84. SModel sm;
  85. sm.model = model;
  86. sm.classId = classId;
  87. sm.picPath = path;
  88. m_lstModel.push_back(sm);
  89. }
  90. bool CFaceMngr::SavePicToModel( LPCTSTR strPath, int classId, DWORD flag )
  91. {
  92. CString path = strPath;
  93. IplImage *pic = cvLoadImage(path, CV_LOAD_IMAGE_GRAYSCALE);
  94. if (!pic) return false;
  95. if (! Pic2NormFace(pic, tfaceImg8, flag))
  96. {
  97. cvReleaseImage(&pic); // ????
  98. return false;
  99. }
  100. CvMat *model = cvCreateMat(m_modelSz, 1, CV_MODEL_FC1);
  101. cvReleaseImage(&pic);
  102. if (! NormFace2Model(tfaceImg8, model))
  103. {
  104. cvReleaseMat(&model);
  105. return false;
  106. }
  107. SaveToModel(path, classId, model);
  108. if (flag & FM_SAVE_NORM_FACE)
  109. {
  110. int p = path.ReverseFind('\\');
  111. CString fd = path.Left(p+1), fn = path.Right(path.GetLength() - p - 1);
  112. ::CreateDirectory(fd + FACE_REL_PATH, NULL);
  113. cvSaveImage(fd + FACE_REL_PATH + fn, tfaceImg8);
  114. }
  115. return true;
  116. }
  117. void CFaceMngr::ClearList()
  118. {
  119. smd_iter iter = m_lstModel.begin();
  120. for (; iter != m_lstModel.end(); iter++)
  121. {
  122. cvReleaseMat(&(iter->model));
  123. }
  124. m_lstModel.clear();
  125. }
  126. int CFaceMngr::GetModelCount()
  127. {
  128. return m_lstModel.size();
  129. }
  130. bool CFaceMngr::Train( LPCTSTR rootPath, vector<SFInfo> &paths, DWORD flag )
  131. {
  132. /* ??? */
  133. ClearList(); // ???????????????Model
  134. m_rtPath = rootPath;
  135. m_rtPath.TrimRight('\\');
  136. m_rtPath += '\\';
  137. if (flag & FM_SAVE_NORM_FACE) ::CreateDirectory(m_rtPath + FACE_REL_PATH, NULL);
  138. /* ???????????? */
  139. //if (flag & FM_SHOW_DETAIL) cout<<"Computing Feature..."<<endl;
  140. sfi_iter iter = paths.begin();
  141. for (; iter != paths.end(); iter++)
  142. {
  143. CString path = m_rtPath + (iter->picPath).TrimLeft('\\');
  144. IplImage *pic = cvLoadImage(path, CV_LOAD_IMAGE_GRAYSCALE);
  145. if (!pic) continue; // ??????
  146. if (! Pic2NormFace(pic, tfaceImg8, flag, &(iter->leye), &(iter->reye)))
  147. {
  148. cvReleaseImage(&pic);
  149. continue; // ????
  150. }
  151. if (flag & FM_SAVE_NORM_FACE)
  152. cvSaveImage(m_rtPath + FACE_REL_PATH + iter->picPath, tfaceImg8);
  153. cvConvertScale(tfaceImg8, tfaceImg32, 1.0/255);
  154. CvMat *ft = cvCreateMat(m_featureSz, 1, CV_FT_FC1);
  155. feature->GetFeature(tfaceImg32, ft);
  156. if (flag & FM_SAVE_REL_PATH) path = iter->picPath;
  157. SaveToModel(path, iter->classId, ft);
  158. cvReleaseImage(&pic);
  159. }
  160. if (GetModelCount() <= 1)
  161. {
  162. CString msg;
  163. msg.Format("Too few \"%s faces\" were found.", (flag & FM_DO_FACE_ALIGN) ?
  164. "aligned" : "pictures that contain");
  165. ::MessageBox1(msg);
  166. ClearList();
  167. return false;
  168. }
  169. /* ?? */
  170. //if (flag & FM_SHOW_DETAIL) cout<<"Computing Subspace..."<<endl;
  171. m_trainNum = GetModelCount();
  172. CvMat *inputs = cvCreateMat(m_featureSz, m_trainNum, CV_FT_FC1);
  173. int *trainIds = new int[m_trainNum];
  174. FormTrainMat(inputs, trainIds);
  175. ss->Train(inputs, trainIds);
  176. m_modelSz = ss->GetSubspaceDim();
  177. m_trainclsNum = ss->classNum;
  178. if (flag & FM_TRAIN_SAVE2MODEL) TrainResSave2Model();
  179. /* ?? */
  180. else ClearList();
  181. delete []trainIds;
  182. cvReleaseMat(&inputs);
  183. tmodel = cvCreateMat(m_modelSz, 1, CV_MODEL_FC1);
  184. stamp = cvGetTickCount()%100000000;
  185. return true;
  186. }
  187. bool CFaceMngr::HasTrained()
  188. {
  189. return ss->m_bTrained;
  190. }
  191. void CFaceMngr::FormTrainMat( CvMat *inputs, int *trainIds )
  192. {
  193. smd_iter iter = m_lstModel.begin();
  194. CvMat sub, *src;
  195. int i = 0;
  196. for (; iter != m_lstModel.end(); iter++)
  197. {
  198. src = iter->model;
  199. cvGetCol(inputs, &sub, i);
  200. cvCopy(src, &sub);
  201. trainIds[i++] = iter->classId;
  202. }
  203. }
  204. void CFaceMngr::TrainResSave2Model()
  205. {
  206. int mdSz = ss->GetSubspaceDim();
  207. smd_iter iter = m_lstModel.begin();
  208. for (; iter != m_lstModel.end(); iter++)
  209. {
  210. // ????????????????????
  211. CvMat *model = cvCreateMat(mdSz, 1, CV_MODEL_FC1);
  212. ss->Project(iter->model, model);
  213. cvReleaseMat(&(iter->model));
  214. iter->model = model;
  215. }
  216. }
  217. bool CFaceMngr::ModelRecognize( CvMat *model, SMatch *info )
  218. {
  219. if (GetModelCount() == 0)
  220. {
  221. ::MessageBox1("There are no models in the memory! Please enroll first.");
  222. return false;
  223. }
  224. SModel *minpm;
  225. smd_iter iter = m_lstModel.begin();
  226. double minDist = 1e9, curVal; // minDist should be among -1~1 for angle metric
  227. for (; iter != m_lstModel.end(); iter++)
  228. {
  229. curVal = ss->CalcVectorDist(iter->model, model);
  230. if (curVal < minDist)
  231. {
  232. minDist = curVal;
  233. minpm = &(*iter);
  234. }
  235. }
  236. info->classId = minpm->classId;
  237. info->dist = minDist;
  238. info->picPath = minpm->picPath;
  239. return true;
  240. }
  241. bool CFaceMngr::PicRecognize( CvArr *pic, DWORD flag, SMatch *info )
  242. {
  243. if (GetModelCount() == 0)
  244. {
  245. ::MessageBox1("There are no models in the memory! Please enroll first.");
  246. return false;
  247. }
  248. if (! Pic2NormFace(pic, tfaceImg8, flag))
  249. {
  250. ::MessageBox1("Failed processing face detection or alignment.");
  251. return false;
  252. }
  253. if ( NormFace2Model(tfaceImg8, tmodel) &&
  254. ModelRecognize(tmodel, info) )
  255. {
  256. return true;
  257. }
  258. return false;
  259. }
  260. double CFaceMngr::BatchPicRecog( LPCTSTR rootPath, vector<SFInfo> &testList, vector<SMatch> &resList, DWORD flag )
  261. {
  262. sfi_iter testIter = testList.begin();
  263. SMatch info;
  264. int correctNum = 0;
  265. for (; testIter != testList.end(); testIter++)
  266. {
  267. CString path = rootPath;
  268. path += '\\';
  269. path += testIter->picPath;
  270. IplImage *img = cvLoadImage(path, CV_LOAD_IMAGE_GRAYSCALE);
  271. if (! PicRecognize(img, flag, &info))
  272. info.classId = FM_RECOG_NOT_DONE;
  273. resList.push_back(info);
  274. if (info.classId == testIter->classId) correctNum++;
  275. }
  276. return correctNum/testList.size();
  277. }
  278. bool CFaceMngr::WriteMatToFile( ofstream &os )
  279. {
  280. if (!HasTrained())
  281. {
  282. ::MessageBox1("You haven't trained yet!");
  283. return false;
  284. }
  285. WriteIntText(os, stamp, "stamp:");
  286. ss->WriteDataToFile(os);
  287. return true;
  288. }
  289. bool CFaceMngr::WriteModelToFile( ofstream &os )
  290. {
  291. if (GetModelCount() == 0)
  292. {
  293. ::MessageBox1("There are no models in the memory!.");
  294. return false;
  295. }
  296. WriteIntText(os, stamp, "stamp:");
  297. int dataBytes = CV_MODEL_FC1 == CV_32FC1 ? 4:8; // ????????????????????
  298. WriteIntText(os, dataBytes, "dataBytes:");
  299. WriteIntText(os, GetModelCount(), "modelNum:");
  300. WriteIntText(os, m_modelSz, "modelSz:");
  301. WriteStringLine(os, "data:");
  302. smd_iter iter = m_lstModel.begin();
  303. for (; iter != m_lstModel.end(); iter++)
  304. {
  305. WriteIntText(os, iter->classId);
  306. WriteCvMatBin(os,iter->model);
  307. WriteStringLine(os, iter->picPath+"\n");
  308. }
  309. return true;
  310. }
  311. bool CFaceMngr::ReadMatFromFile( ifstream &is )
  312. {
  313. int new_sig;
  314. ReadIntText(is, new_sig);
  315. if (new_sig != stamp)
  316. {
  317. ClearList();
  318. stamp = new_sig;
  319. }
  320. bool ret = ss->ReadDataFromFile(is);
  321. if (ss->inputDim != m_featureSz)
  322. {
  323. ss->Release();
  324. MessageBox1("Feature size not match!");
  325. return false;
  326. }
  327. m_modelSz = ss->GetSubspaceDim();
  328. cvReleaseMat(&tmodel);
  329. tmodel = cvCreateMat(m_modelSz, 1, CV_MODEL_FC1);
  330. return ret;
  331. }
  332. int CFaceMngr::ReadModelFromFile( ifstream &is )
  333. {
  334. int new_sig;
  335. ReadIntText(is, new_sig);
  336. int dataBytes, modelNum;
  337. ReadIntText(is, dataBytes);
  338. if ((dataBytes == 4 && CV_MODEL_FC1 == CV_64FC1) ||
  339. (dataBytes == 8 && CV_MODEL_FC1 == CV_32FC1))
  340. {
  341. ::MessageBox1("float/double not match!");
  342. return 0;
  343. }
  344. if (new_sig != stamp) // ??????append models???????????????(??????)
  345. {
  346. ClearList();
  347. ss->Release();
  348. stamp = new_sig;
  349. }
  350. ReadIntText(is, modelNum);
  351. ReadIntText(is, m_modelSz);
  352. CString tmp;
  353. for (int i = 0; i < modelNum; i++)
  354. {
  355. SModel sm;
  356. ReadStringLine(is, tmp);
  357. ReadIntText(is, sm.classId, false);
  358. sm.model = cvCreateMat(m_modelSz, 1, CV_MODEL_FC1);
  359. ReadCvMatBin(is, sm.model, false);
  360. ReadStringLine(is, sm.picPath);
  361. m_lstModel.push_back(sm);
  362. }
  363. return modelNum;
  364. }
  365. #endif