void Fm29( double& fm29, // out: FM29 measure of fitness int& iworst, // out: index of point with worse fit const Shape& shape, // in const Shape& refshape) // in { if (shape.rows != 77) Err("Fitness measure FM29 can be used only on shapes with 77 points " "(your shape has %d points)", shape.rows); if (refshape.rows != 77) Err("Fitness measure FM29 can be used only on shapes with 77 points " "(your reference shape has %d points)", refshape.rows); fm29 = 0; iworst = -1; double worst = -1; double weight = 0; for (int i = 0; i < shape.rows; i++) if (FITPARAMS[i].xres && // point is used for FM29? PointUsed(refshape, i)) // point present in ref shape? { CV_Assert(PointUsed(shape, i)); CV_Assert(FITPARAMS[i].yres); const double pointfit = SQ((shape(i, IX) - refshape(i, IX)) / FITPARAMS[i].xres) + SQ((shape(i, IY) - refshape(i, IY)) / FITPARAMS[i].yres); fm29 += pointfit; const double pointweight = 1 / SQ(FITPARAMS[i].xres) + 1 / SQ(FITPARAMS[i].yres); weight += pointweight; if (pointfit > worst) { worst = pointfit; iworst = i; } } CV_Assert(weight > 0); // multiply by 2 so same as mean euclidean dist when all xres = yres = 1 fm29 = sqrt(fm29 * 2 / weight) / EyeMouthDist(refshape); }
static Shape Shape77As20( // return an approximated BioID 20 point shape const Shape& shape) // in: Stasm 77 point shape { CV_Assert(shape.rows == 77); Shape newshape(20, 2); CopyPoint(newshape, shape, 0, 38); CopyPoint(newshape, shape, 1, 39); CopyPoint(newshape, shape, 2, 59); CopyPoint(newshape, shape, 3, 65); CopyPoint(newshape, shape, 4, 18); CopyPoint(newshape, shape, 5, 21); CopyPoint(newshape, shape, 6, 22); CopyPoint(newshape, shape, 7, 25); CopyPoint(newshape, shape, 8, 0); CopyPoint(newshape, shape, 9, 34); CopyPoint(newshape, shape, 10, 30); CopyPoint(newshape, shape, 11, 40); CopyPoint(newshape, shape, 12, 44); CopyPoint(newshape, shape, 13, 12); CopyPoint(newshape, shape, 14, 52); CopyPoint(newshape, shape, 15, 51); CopyPoint(newshape, shape, 16, 53); CopyPoint(newshape, shape, 17, 62); CopyPoint(newshape, shape, 18, 74); CopyPoint(newshape, shape, 19, 6); #if MOD_A1 || MOD_A || MOD_A_EMU const double eyemouth = EyeMouthDist(shape); newshape(15, IY) += MAX(1, .02 * eyemouth); // move down, into nostril newshape(16, IY) += MAX(1, .02 * eyemouth); // move down, into nostril #endif return newshape; }
static Shape Shape77AsXm2vts68( // return an approximated XM2VTS 68 point shape const Shape& shape) // in: Stasm 77 point shape { CV_Assert(shape.rows == 77); Shape newshape(68, 2); CopyPoint(newshape, shape, 0, 0); InterPoint(newshape, shape, 1, .6667, 1, 2); InterPoint(newshape, shape, 2, .5, 2, 3); CopyPoint(newshape, shape, 3, 3); InterPoint(newshape, shape, 4, .3333, 3, 4); InterPoint(newshape, shape, 5, .6667, 4, 5); CopyPoint(newshape, shape, 6, 5); CopyPoint(newshape, shape, 7, 6); CopyPoint(newshape, shape, 8, 7); InterPoint(newshape, shape, 9, .3333, 7, 8); InterPoint(newshape, shape, 10, .6667, 8, 9); CopyPoint(newshape, shape, 11, 9); InterPoint(newshape, shape, 12, .5, 9, 10); InterPoint(newshape, shape, 13, .3333, 10, 11); CopyPoint(newshape, shape, 14, 12); CopyPoint(newshape, shape, 15, 25); CopyPoint(newshape, shape, 16, 24); CopyPoint(newshape, shape, 17, 23); CopyPoint(newshape, shape, 18, 22); CopyPoint(newshape, shape, 19, 27); CopyPoint(newshape, shape, 20, 26); CopyPoint(newshape, shape, 21, 18); CopyPoint(newshape, shape, 22, 17); CopyPoint(newshape, shape, 23, 16); CopyPoint(newshape, shape, 24, 21); CopyPoint(newshape, shape, 25, 20); CopyPoint(newshape, shape, 26, 19); CopyPoint(newshape, shape, 27, 34); CopyPoint(newshape, shape, 28, 32); CopyPoint(newshape, shape, 29, 30); CopyPoint(newshape, shape, 30, 36); CopyPoint(newshape, shape, 31, 38); CopyPoint(newshape, shape, 32, 44); CopyPoint(newshape, shape, 33, 42); CopyPoint(newshape, shape, 34, 40); CopyPoint(newshape, shape, 35, 46); CopyPoint(newshape, shape, 36, 39); InterPoint(newshape, shape, 37, .6667, 30, 40); newshape(37, IX) = shape(50, IX); CopyPoint(newshape, shape, 38, 50); CopyPoint(newshape, shape, 39, 58); CopyPoint(newshape, shape, 40, 57); CopyPoint(newshape, shape, 41, 56); CopyPoint(newshape, shape, 42, 55); CopyPoint(newshape, shape, 43, 54); CopyPoint(newshape, shape, 44, 48); InterPoint(newshape, shape, 45, .3333, 30, 40); newshape(45, IX) = shape(48, IX); CopyPoint(newshape, shape, 46, 51); CopyPoint(newshape, shape, 47, 53); CopyPoint(newshape, shape, 48, 59); CopyPoint(newshape, shape, 49, 60); CopyPoint(newshape, shape, 50, 61); CopyPoint(newshape, shape, 51, 62); CopyPoint(newshape, shape, 52, 63); CopyPoint(newshape, shape, 53, 64); CopyPoint(newshape, shape, 54, 65); CopyPoint(newshape, shape, 55, 72); CopyPoint(newshape, shape, 56, 73); CopyPoint(newshape, shape, 57, 74); CopyPoint(newshape, shape, 58, 75); CopyPoint(newshape, shape, 59, 76); CopyPoint(newshape, shape, 60, 69); CopyPoint(newshape, shape, 61, 70); CopyPoint(newshape, shape, 62, 71); CopyPoint(newshape, shape, 63, 66); CopyPoint(newshape, shape, 64, 67); CopyPoint(newshape, shape, 65, 68); InterPoint(newshape, shape, 66, .5, 67, 70); CopyPoint(newshape, shape, 67, 52); #if MOD_A1 || MOD_A || MOD_A_EMU const double eyemouth = EyeMouthDist(shape); newshape(38, IY) += MAX(1, .05 * eyemouth); // move side of nose down newshape(44, IY) += MAX(1, .05 * eyemouth); // move side of nose down newshape(46, IY) += MAX(1, .02 * eyemouth); // move down, into nostril newshape(47, IY) += MAX(1, .02 * eyemouth); // move down, into nostril #endif return newshape; }
static void ProcessFace( const Image& img, // in const char* imgpath, // in int foundface, // in const Shape& shape, // in float estyaw, // in double facedet_time, // in double asmsearch_time, // in const Shape& refshape, // in FILE* fitfile, // in const ShapeFile& sh, // in int ishape) // in: shape index in the shapefile { double meanfit = NOFIT; // fitness measure over all shapefile points int iworst = -1; // worst fitting point in above measure of fitness double me17 = NOFIT; // fitness measure me17 double fm29 = NOFIT; // fitness measure FM29 (only for 77 point shapes) int iworst_fm29 = -1; // worst fitting point using FM29 measure if (!foundface) printf_g("no face "); else { if (trace_g) LogShape(shape, imgpath); // we will succesfully get the meanfit only if the shape can be converted to // the shapefile number of points (by ConvertShape in MeanFitOverInterEye) meanfit = MeanFitOverInterEye(iworst, shape, refshape); if (meanfit != NOFIT) // were able to get the mean fit? printf_g("meanfit %5.3f ", meanfit); // use fitness measure me17 if can convert the shape to a shape17 me17 = Me17(shape, refshape); if (me17 != NOFIT) // were able to get the me17 fit? printf_g("me17 %5.3f ", me17); // get fitness measure fm29 if the shape has 77 points if (shape.rows == 77 && refshape.rows == 77) { Fm29(fm29, iworst_fm29, shape, refshape); printf_g("fm29 %5.3f ", fm29); } if (writeimgs_g) // -i flag WriteImgs(img, imgpath, shape, refshape, meanfit, iworst, me17, fm29, iworst_fm29); } printf_g("\n"); if (trace_g) lprintf("\n"); const char* const base = Base(imgpath); const VEC pose(sh.Pose_(base)); Fprintf(fitfile, "%-*s%s " "%7.5f % 6d " "%7.5f " "%7.5f % 6d " "%8.2f %8.2f ", sh.nchar_, base, " ", meanfit, iworst, me17, fm29, iworst_fm29, InterEyeDist(refshape), EyeMouthDist(refshape)); Fprintf(fitfile, "% 5.0f " "% 6.0f % 6.0f % 6.0f %9.3f " "[%5.3f] [%5.3f]\n", estyaw, pose(0), pose(1), pose(2), pose(3), facedet_time, asmsearch_time); }
void ApplyShapeModelHacks( // adjust shape by applying various hacks Shape& shape, // io: position of features possibly adjusted unsigned hackbits) // in: which hacks to apply, see SHAPEHACKS defs { if (shape.rows != 77) // the shape hacks assume stasm77 points return; // NOTE return const double eyemouth = EyeMouthDist(shape); if (hackbits & SHAPEHACKS_DEFAULT) { // Possibly shift the entire mouth down, if it is too close to the nose. // Useful when the descriptor matchers think the nostrils are the mouth. const double nosemouth_gap = shape(L_CTopOfTopLip, IY) - shape(L_CNoseBase, IY); if (nosemouth_gap < .1 * eyemouth) { PossiblyPrint("ShiftMouthDown"); for (int i = L_LMouthCorner; i <= L_LMouth76; i++) shape(i, IY) += SHIFT_MOUTH_FROM_NOSE_FRAC * eyemouth; } // Shift the bottom of mouth down if it is above the top of mouth. const double gap = shape(L_CTopOfBotLip, IY) - shape(L_CTopOfTopLip, IY); if (gap < 0) { PossiblyPrint("ShiftBottomOfMouthDown"); for (int i = L_RMouthCorner; i <= L_LMouth76; i++) shape(i, IY) -= gap; } // Possibly shift the chin down or up, if it too close to the mouth. // Useful when the chin is on the mouth. const double y_mouth_center = (shape(L_CTopOfTopLip, IY) + shape(L_CBotOfBotLip, IY)) / 2; const double nosemouth_gap1 = MAX(0, y_mouth_center - shape(L_CNoseBase, IY)); const double mouthchin_gap = shape(L_CTipOfChin, IY) - y_mouth_center; if (mouthchin_gap < CHIN_DOWN_RATIO * nosemouth_gap1) { PossiblyPrint("ShiftChinDown"); double yadjust = CHIN_DOWN_SHIFT * eyemouth; shape(L_LJaw04, IY) += yadjust; shape(L_LJaw05, IY) += yadjust; shape(L_CTipOfChin, IY) += yadjust; shape(L_RJaw07, IY) += yadjust; shape(L_RJaw08, IY) += yadjust; } if (mouthchin_gap > CHIN_UP_RATIO * nosemouth_gap1) { PossiblyPrint("ShiftChinUp"); double yadjust = CHIN_UP_SHIFT * eyemouth; shape(L_LJaw04, IY) -= yadjust; shape(L_LJaw05, IY) -= yadjust; shape(L_CTipOfChin, IY) -= yadjust; shape(L_RJaw07, IY) -= yadjust; shape(L_RJaw08, IY) -= yadjust; } } // Possibly shift the side of face away from eye. // Useful when the side of face is on the eye. if (hackbits & SHAPEHACKS_SHIFT_TEMPLE_OUT) { if (shape(L_LTemple, IX) > shape(L_LEyeOuter, IX) - TEMPLE_RATIO * eyemouth) { PossiblyPrint("LTempleOut"); double xadjust = TEMPLE_SHIFT * ABS(shape(L_LEyeOuter, IX) - shape(L_LTemple, IX)); shape(L_LTemple, IX) -= xadjust; shape(L_LJaw01, IX) -= xadjust; shape(L_LJawNoseline, IX) -= xadjust; shape(L_LJawMouthline, IX) -= .5 * xadjust; } if (shape(L_RTemple, IX) < shape(L_REyeOuter, IX) + TEMPLE_RATIO * eyemouth) { PossiblyPrint("RTempleOut"); double xadjust = TEMPLE_SHIFT * ABS(shape(L_REyeOuter, IX) - shape(L_RTemple, IX)); shape(L_RTemple, IX) += xadjust; shape(L_RJaw11, IX) += xadjust; shape(L_RJawNoseline, IX) += xadjust; shape(L_RJawMouthline, IX) += .5 * xadjust; } } }
static double GetPrescale( // factor to scale face to standard size prior to search const Shape& startshape) // in: startshape roughly positioned on face { return EYEMOUTH_DIST / EyeMouthDist(startshape); }