static void EstRotAndYawFrom5PointShape( double& rot, // out double& yaw, // out const Shape shape) // in { if (shape.rows != 5 || // basic sanity checks shape(0, IX) > shape(1, IX) || // eye corners shape(3, IX) > shape(4, IX)) // mouth corners { rot = yaw = 0; return; } Shape workshape(shape.clone()); // local copy we can modify // Derotate shape using eye angle as estimate of in-plane rotation. // We rotate about the shape centroid. // TODO EstYawFrom5PointShape was trained on shapes without this // derotation, so must retrain the model for best results. rot = RadsToDegrees(-atan2(workshape(1, IY) - workshape(0, IY), workshape(1, IX) - workshape(0, IX))); PossiblySetRotToZero(rot); // treat small Rots as zero Rots if (rot) RotShapeInPlace(workshape, -rot, SumElems(workshape.col(IX)) / 5, SumElems(workshape.col(IY)) / 5); // mean-center x and y MAT X(workshape.col(IX)); X -= SumElems(X) / 5; MAT Y(workshape.col(IY)); Y -= SumElems(Y) / 5; // normalize so shape size is 1 double norm = 0; for (int i = 0; i < 5; i++) norm += SQ(X(i)) + SQ(Y(i)); workshape /= sqrt(norm); yaw = EstYawFrom5PointShape(Buf(workshape)); }
static void ShowEigs(const MAT& eigvals) { double min_eig = eigvals(0) / 1000; double var_all = SumElems(eigvals); double var10 = 0; int neigs = NSIZE(eigvals); for (int i = 0; i < MIN(10, neigs); i++) var10 += eigvals(i); int iprint = 0; while (iprint < neigs && eigvals(iprint) > min_eig && iprint < 9) iprint++; if (iprint < neigs + 1) // show first small eig value, for context iprint++; lprintf("%.0f%% percent variance is explained by %s%d shape eigs:", 100 * var10 / var_all, (iprint < neigs? "the first ": ""), iprint); const MAT eigvals_t(eigvals.t()); for (int i = 0; i < iprint; i++) lprintf(" %.0f", 100 * eigvals_t(i) / var_all); lprintf("%%\n"); }