PageRenderTime 151ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/Workspace/GC/Windows-GCFOM/GC_FaceOrientationMapper/AAM_Basic.cpp

https://github.com/sreedal/GC
C++ | 375 lines | 283 code | 51 blank | 41 comment | 33 complexity | 0ba1b62b0b5bca9fde0c09d27cd3c6a1 MD5 | raw file
  1. /****************************************************************************
  2. * AAMLibrary
  3. * http://code.google.com/p/aam-library
  4. * Copyright (c) 2008-2009 by GreatYao, all rights reserved.
  5. ****************************************************************************/
  6. #include "stdafx.h"
  7. #include <ctime>
  8. #include <direct.h>
  9. #include "AAM_Basic.h"
  10. //============================================================================
  11. AAM_Basic::AAM_Basic()
  12. {
  13. __G = 0;
  14. __current_c_q = 0;
  15. __update_c_q = 0;
  16. __delta_c_q = 0;
  17. __c = 0;
  18. __p = 0;
  19. __q = 0;
  20. __lamda = 0;
  21. __s = 0;
  22. __t_m = 0;
  23. __t_s = 0;
  24. __delta_t = 0;
  25. }
  26. //============================================================================
  27. AAM_Basic::~AAM_Basic()
  28. {
  29. cvReleaseMat(&__G); cvReleaseMat(&__current_c_q);
  30. cvReleaseMat(&__update_c_q); cvReleaseMat(&__delta_c_q);
  31. cvReleaseMat(&__p); cvReleaseMat(&__q);
  32. cvReleaseMat(&__c); cvReleaseMat(&__lamda);
  33. cvReleaseMat(&__s); cvReleaseMat(&__t_s);
  34. cvReleaseMat(&__t_m); cvReleaseMat(&__delta_t);
  35. }
  36. //============================================================================
  37. void AAM_Basic::Train(const file_lists& pts_files,
  38. const file_lists& img_files,
  39. double scale /* = 1.0 */,
  40. double shape_percentage /* = 0.975 */,
  41. double texture_percentage /* = 0.975 */,
  42. double appearance_percentage /* = 0.975 */)
  43. {
  44. if(pts_files.size() != img_files.size())
  45. {
  46. fprintf(stderr, "ERROE(%s, %d): #Shapes != #Images\n",
  47. __FILE__, __LINE__);
  48. exit(0);
  49. }
  50. printf("################################################\n");
  51. printf("Build Fixed Jocobian Active Appearance Model ...\n");
  52. __cam.Train(pts_files, img_files, scale, shape_percentage,
  53. texture_percentage, appearance_percentage);
  54. printf("Build Jacobian Matrix...\n");
  55. __G = cvCreateMat(__cam.nModes()+4, __cam.__texture.nPixels(), CV_64FC1);
  56. CalcJacobianMatrix(pts_files, img_files);
  57. //allocate memory for on-line fitting
  58. __current_c_q = cvCreateMat(1, __cam.nModes()+4, CV_64FC1);
  59. __update_c_q = cvCreateMat(1, __cam.nModes()+4, CV_64FC1);
  60. __delta_c_q = cvCreateMat(1, __cam.nModes()+4, CV_64FC1);
  61. __c = cvCreateMat(1, __cam.nModes(), CV_64FC1);
  62. __p = cvCreateMat(1, __cam.__shape.nModes(), CV_64FC1);
  63. __q = cvCreateMat(1, 4, CV_64FC1);
  64. __lamda = cvCreateMat(1, __cam.__texture.nModes(), CV_64FC1);
  65. __s = cvCreateMat(1, __cam.__shape.nPoints()*2, CV_64FC1);
  66. __t_s = cvCreateMat(1, __cam.__texture.nPixels(), CV_64FC1);
  67. __t_m = cvCreateMat(1, __cam.__texture.nPixels(), CV_64FC1);
  68. __delta_t = cvCreateMat(1, __cam.__texture.nPixels(), CV_64FC1);
  69. printf("################################################\n\n");
  70. }
  71. //============================================================================
  72. static double rand_in_between(double a, double b)
  73. {
  74. int A = rand() % 50;
  75. return a + (b-a)*A/49;
  76. }
  77. //============================================================================
  78. void AAM_Basic::CalcJacobianMatrix(const file_lists& pts_files,
  79. const file_lists& img_files,
  80. double disp_scale /* = 0.2 */,
  81. double disp_angle /* = 20 */,
  82. double disp_trans /* = 5.0 */,
  83. double disp_std /* = 1.0 */,
  84. int nExp /* = 30 */)
  85. {
  86. CvMat* J = cvCreateMat(__cam.nModes()+4, __cam.__texture.nPixels(), CV_64FC1);
  87. CvMat* d = cvCreateMat(1, __cam.nModes()+4, CV_64FC1);
  88. CvMat* o = cvCreateMat(1, __cam.nModes()+4, CV_64FC1);
  89. CvMat* oo = cvCreateMat(1, __cam.nModes()+4, CV_64FC1);
  90. CvMat* t = cvCreateMat(1, __cam.__texture.nPixels(), CV_64FC1);
  91. CvMat* t_m = cvCreateMat(1, __cam.__texture.nPixels(), CV_64FC1);
  92. CvMat* t_s = cvCreateMat(1, __cam.__texture.nPixels(), CV_64FC1);
  93. CvMat* t1 = cvCreateMat(1, __cam.__texture.nPixels(), CV_64FC1);
  94. CvMat* t2 = cvCreateMat(1, __cam.__texture.nPixels(), CV_64FC1);
  95. CvMat* u = cvCreateMat(1, __cam.nModes()+4, CV_64FC1);
  96. CvMat* c = cvCreateMat(1, __cam.nModes(), CV_64FC1);
  97. CvMat* s = cvCreateMat(1, __cam.__shape.nPoints()*2, CV_64FC1);
  98. CvMat* q = cvCreateMat(1, 4, CV_64FC1);
  99. CvMat* p = cvCreateMat(1, __cam.__shape.nModes(),CV_64FC1);
  100. CvMat* lamda = cvCreateMat(1, __cam.__texture.nModes(), CV_64FC1);
  101. double theta = disp_angle * CV_PI / 180;
  102. double aa = MAX(fabs(disp_scale*cos(theta)), fabs(disp_scale*sin(theta)));
  103. cvmSet(d,0,0,aa); cvmSet(d,0,1,aa); cvmSet(d,0,2,disp_trans); cvmSet(d,0,3,disp_trans);
  104. for(int nmode = 0; nmode < __cam.nModes(); nmode++)
  105. cvmSet(d,0,4+nmode,disp_std*sqrt(__cam.Var(nmode)));
  106. srand(unsigned(time(0)));
  107. cvSetZero(u);cvSetZero(J);
  108. for(int i = 0; i < pts_files.size(); i++)
  109. {
  110. IplImage* image = cvLoadImage(img_files[i].c_str(), -1);
  111. AAM_Shape Shape;
  112. if(!Shape.ReadAnnotations(pts_files[i]))
  113. Shape.ScaleXY(image->width, image->height);
  114. Shape.Point2Mat(s);
  115. //calculate current texture vector
  116. __cam.__paw.CalcWarpTexture(s, image, t);
  117. __cam.__texture.NormalizeTexture(__cam.__MeanG, t);
  118. //calculate appearance parameters
  119. __cam.__shape.CalcParams(s, p, q);
  120. __cam.__texture.CalcParams(t, lamda);
  121. __cam.CalcParams(c, p, lamda);
  122. //update appearance and pose parameters
  123. CvMat subo;
  124. cvGetCols(o, &subo, 0, 4); cvCopy(q, &subo);
  125. cvGetCols(o, &subo, 4, 4+__cam.nModes()); cvCopy(c, &subo);
  126. //get optimal EstResidual
  127. EstResidual(image, o, s, t_m, t_s, t1);
  128. for(int j = 0; j < nExp; j++)
  129. {
  130. printf("Pertubing (%d/%d) for image (%d/%d)...\r", j, nExp, i, pts_files.size());
  131. for(int l = 0; l < 4+__cam.nModes(); l++)
  132. {
  133. double D = cvmGet(d,0,l);
  134. double v = rand_in_between(-D, D);
  135. cvCopy(o, oo); CV_MAT_ELEM(*oo,double,0,l) += v;
  136. EstResidual(image, oo, s, t_m, t_s, t2);
  137. cvSub(t1, t2, t2);
  138. cvConvertScale(t2, t2, 1.0/v);
  139. //accumulate into l-th row
  140. CvMat Jl; cvGetRow(J, &Jl, l);
  141. cvAdd(&Jl, t2, &Jl);
  142. CV_MAT_ELEM(*u, double, 0, l) += 1.0;
  143. }
  144. }
  145. cvReleaseImage(&image);
  146. }
  147. //normalize
  148. for(int l = 0; l < __cam.nModes()+4; l++)
  149. {
  150. CvMat Jl; cvGetRow(J, &Jl, l);
  151. cvConvertScale(&Jl, &Jl, 1.0/cvmGet(u,0,l));
  152. }
  153. CvMat* JtJ = cvCreateMat(__cam.nModes()+4, __cam.nModes()+4, CV_64FC1);
  154. CvMat* InvJtJ = cvCreateMat(__cam.nModes()+4, __cam.nModes()+4, CV_64FC1);
  155. cvGEMM(J, J, 1, NULL, 0, JtJ, CV_GEMM_B_T);
  156. cvInvert(JtJ, InvJtJ, CV_SVD);
  157. cvMatMul(InvJtJ, J, __G);
  158. cvReleaseMat(&J); cvReleaseMat(&d); cvReleaseMat(&o);
  159. cvReleaseMat(&oo); cvReleaseMat(&t); cvReleaseMat(&t_s);
  160. cvReleaseMat(&t_m); cvReleaseMat(&t1); cvReleaseMat(&t2);
  161. cvReleaseMat(&u); cvReleaseMat(&c); cvReleaseMat(&s);
  162. cvReleaseMat(&q); cvReleaseMat(&p); cvReleaseMat(&lamda);
  163. cvReleaseMat(&JtJ); cvReleaseMat(&InvJtJ);
  164. }
  165. //============================================================================
  166. double AAM_Basic::EstResidual(const IplImage* image, const CvMat* c_q,
  167. CvMat* s, CvMat* t_m,
  168. CvMat* t_s, CvMat* deltat)
  169. {
  170. CvMat c, q;
  171. cvGetCols(c_q, &q, 0, 4);
  172. cvGetCols(c_q, &c, 4, 4+__cam.nModes());
  173. // generate model texture
  174. __cam.CalcTexture(t_m, &c);
  175. // generate model shape
  176. __cam.CalcShape(s, c_q);
  177. // generate warped texture
  178. AAM_Common::CheckShape(s, image->width, image->height);
  179. __cam.__paw.CalcWarpTexture(s, image, t_s);
  180. __cam.__texture.NormalizeTexture(__cam.__MeanG, t_s);
  181. // calculate pixel difference
  182. cvSub(t_m, t_s, deltat);
  183. return cvNorm(deltat);
  184. }
  185. //============================================================================
  186. void AAM_Basic::SetAllParamsZero()
  187. {
  188. cvSetZero(__q);
  189. cvSetZero(__c);
  190. }
  191. //============================================================================
  192. void AAM_Basic::InitParams(const IplImage* image)
  193. {
  194. //shape parameter
  195. __cam.__shape.CalcParams(__s, __p, __q);
  196. //texture parameter
  197. __cam.__paw.CalcWarpTexture(__s, image, __t_s);
  198. __cam.__texture.NormalizeTexture(__cam.__MeanG, __t_s);
  199. __cam.__texture.CalcParams(__t_s, __lamda);
  200. //combined appearance parameter
  201. __cam.CalcParams(__c, __p, __lamda);
  202. }
  203. //============================================================================
  204. void AAM_Basic::Fit(const IplImage* image, AAM_Shape& Shape,
  205. int max_iter /* = 30 */,bool showprocess /* = false */)
  206. {
  207. //intial some stuff
  208. double t = gettime;
  209. double e1, e2;
  210. const int np = 5;
  211. double k_values[np] = {1, 0.5, 0.25, 0.125, 0.0625};
  212. int k;
  213. IplImage* Drawimg = 0;
  214. Shape.Point2Mat(__s);
  215. InitParams(image);
  216. CvMat subcq;
  217. cvGetCols(__current_c_q, &subcq, 0, 4); cvCopy(__q, &subcq);
  218. cvGetCols(__current_c_q, &subcq, 4, 4+__cam.nModes()); cvCopy(__c, &subcq);
  219. //calculate error
  220. e1 = EstResidual(image, __current_c_q, __s, __t_m, __t_s, __delta_t);
  221. //do a number of iteration until convergence
  222. for(int iter = 0; iter <max_iter; iter++)
  223. {
  224. if(showprocess)
  225. {
  226. if(Drawimg == 0) Drawimg = cvCloneImage(image);
  227. else cvCopy(image, Drawimg);
  228. __cam.CalcShape(__s, __current_c_q);
  229. Shape.Mat2Point(__s);
  230. Draw(Drawimg, Shape, 2);
  231. mkdir("result");
  232. char filename[100];
  233. sprintf(filename, "result/Iter-%02d.jpg", iter);
  234. cvSaveImage(filename, Drawimg);
  235. }
  236. // predict parameter update
  237. cvGEMM(__delta_t, __G, 1, NULL, 0, __delta_c_q, CV_GEMM_B_T);
  238. //force first iteration
  239. if(iter == 0)
  240. {
  241. cvAdd(__current_c_q, __delta_c_q, __current_c_q);
  242. CvMat c; cvGetCols(__current_c_q, &c, 4, 4+__cam.nModes());
  243. //constrain parameters
  244. __cam.Clamp(&c);
  245. e1 = EstResidual(image, __current_c_q, __s, __t_m, __t_s, __delta_t);
  246. }
  247. //find largest step size which reduces texture EstResidual
  248. else
  249. {
  250. for(k = 0; k < np; k++)
  251. {
  252. cvScaleAdd(__delta_c_q, cvScalar(k_values[k]), __current_c_q, __update_c_q);
  253. //constrain parameters
  254. CvMat c; cvGetCols(__update_c_q, &c, 4, 4+__cam.nModes());
  255. __cam.Clamp(&c);
  256. e2 = EstResidual(image, __update_c_q, __s, __t_m, __t_s, __delta_t);
  257. if(e2 <= e1) break;
  258. }
  259. }
  260. //check for convergence
  261. if(iter > 0)
  262. {
  263. if(k == np)
  264. {
  265. e1 = e2;
  266. cvCopy(__update_c_q, __current_c_q);
  267. }
  268. else if(fabs(e2-e1)<0.001*e1) break;
  269. else if (cvNorm(__delta_c_q)<0.001) break;
  270. else
  271. {
  272. cvCopy(__update_c_q, __current_c_q);
  273. e1 = e2;
  274. }
  275. }
  276. }
  277. cvReleaseImage(&Drawimg);
  278. __cam.CalcShape(__s, __current_c_q);
  279. Shape.Mat2Point(__s);
  280. t = gettime - t;
  281. printf("AAM-Basic Fitting time cost: %.3f millisec\n", t);
  282. }
  283. //===========================================================================
  284. void AAM_Basic::Draw(IplImage* image, const AAM_Shape& Shape, int type)
  285. {
  286. if(type == 0) AAM_Common::DrawPoints(image, Shape);
  287. else if(type == 1) AAM_Common::DrawTriangles(image, Shape, __cam.__paw.__tri);
  288. else if(type == 2)
  289. {
  290. double minV, maxV;
  291. cvMinMaxLoc(__t_m, &minV, &maxV);
  292. cvConvertScale(__t_m, __t_m, 255/(maxV-minV), -minV*255/(maxV-minV));
  293. AAM_PAW paw;
  294. paw.Train(Shape, __cam.__Points, __cam.__Storage, __cam.__paw.GetTri(), false);
  295. AAM_Common::DrawAppearance(image, Shape, __t_m, paw, __cam.__paw);
  296. }
  297. else fprintf(stderr, "ERROR(%s, %d): Unsupported drawing type\n",
  298. __FILE__, __LINE__);
  299. }
  300. //===========================================================================
  301. void AAM_Basic::Write(std::ofstream& os)
  302. {
  303. __cam.Write(os);
  304. os << __G;
  305. }
  306. //===========================================================================
  307. void AAM_Basic::Read(std::ifstream& is)
  308. {
  309. __cam.Read(is);
  310. __G = cvCreateMat(__cam.nModes()+4, __cam.__texture.nPixels(), CV_64FC1);
  311. is >> __G;
  312. //allocate memory for on-line fitting
  313. __current_c_q = cvCreateMat(1, __cam.nModes()+4, CV_64FC1);
  314. __update_c_q = cvCreateMat(1, __cam.nModes()+4, CV_64FC1);
  315. __delta_c_q = cvCreateMat(1, __cam.nModes()+4, CV_64FC1);
  316. __c = cvCreateMat(1, __cam.nModes(), CV_64FC1);
  317. __p = cvCreateMat(1, __cam.__shape.nModes(), CV_64FC1);
  318. __q = cvCreateMat(1, 4, CV_64FC1);
  319. __lamda = cvCreateMat(1, __cam.__texture.nModes(), CV_64FC1);
  320. __s = cvCreateMat(1, __cam.__shape.nPoints()*2, CV_64FC1);
  321. __t_s = cvCreateMat(1, __cam.__texture.nPixels(), CV_64FC1);
  322. __t_m = cvCreateMat(1, __cam.__texture.nPixels(), CV_64FC1);
  323. __delta_t = cvCreateMat(1, __cam.__texture.nPixels(), CV_64FC1);
  324. }