static double EstRotFromEyeAngle( // estimate face rotation from intereye angle const DetPar& detpar) // in: detpar wrt the ROI { double rot = 0; if (Valid(detpar.lex) && Valid(detpar.rey)) // both eyes detected? rot = RadsToDegrees(-atan2(detpar.rey - detpar.ley, detpar.rex - detpar.lex)); return rot; }
double EyeAngle( // eye angle in degrees, INVALID if eye angle not available const DetPar& detpar) // in: detpar wrt the ROI { double angle = 0; if (Valid(detpar.lex) && Valid(detpar.rey)) // both eyes detected? { angle = RadsToDegrees( -atan2(detpar.rey - detpar.ley, detpar.rex - detpar.lex)); } return angle; }
double EyeAngle( // eye angle in degrees, INVALID if eye angle not available const Shape& shape) // in { double angle = INVALID; const Shape shape17(Shape17OrEmpty(shape)); if (shape17.rows && // converted shape to a Shape17 successfully? Valid(shape17(L17_LPupil, IX)) && Valid(shape17(L17_RPupil, IX)) && PointUsed(shape17, L17_LPupil) && PointUsed(shape17, L17_RPupil)) { angle = RadsToDegrees( -atan2(shape17(L17_RPupil, IY) - shape17(L17_LPupil, IY), shape17(L17_RPupil, IX) - shape17(L17_LPupil, IX))); } return angle; }
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 InitGradMagAndOrientMats( MAT& magmat, // out: grad mag mat MAT& orientmat, // out: grad ori mat const Image& img) // in: ROI scaled to current pyramid level { const int nrows = img.rows, nrows1 = img.rows-1; const int ncols = img.cols, ncols1 = img.cols-1; const double bins_per_degree = BINS_PER_HIST / 360.; magmat.create(nrows, ncols); orientmat.create(nrows, ncols); for (int y = 0; y < nrows1; y++) { const byte* const buf = (byte*)(img.data) + y * ncols; const byte* const buf_x1 = (byte*)(img.data) + y * ncols + 1; const byte* const buf_y1 = (byte*)(img.data) + (y+1) * ncols; double* const magbuf = Buf(magmat) + y * ncols; double* const orientbuf = Buf(orientmat) + y * ncols; for (int x = 0; x < ncols1; x++) { const byte pixel = buf[x]; const double xdelta = buf_x1[x] - pixel; const double ydelta = buf_y1[x] - pixel; magbuf[x] = sqrt(SQ(xdelta) + SQ(ydelta)); double orient = RadsToDegrees(atan2(ydelta, xdelta)); // -180 <= orient < 180 if (orient < 0) orient += 360; // 0 <= orient < 360 orientbuf[x] = orient * bins_per_degree; // 0 <= orient < BINS_PER_HIST } } // fill bottom and right edges magmat.row(nrows1) = 0; magmat.col(ncols1) = 0; orientmat.row(nrows1) = 0; orientmat.col(ncols1) = 0; }