double EyeMouthDist( // eye-mouth distance of a face shape, return 1 if not a face const Shape& shape) // in { static const int eyes[] = // surrogates for pupil midpoint { L17_LPupil, L17_RPupil, L17_LEyeOuter, L17_REyeOuter, L17_LEyeInner, L17_REyeInner, L17_LEyebrowInner, L17_REyebrowInner, L17_LEyebrowOuter, L17_REyebrowOuter }; static const int mouths[] = // surrogates for bot of bot lip { L17_CBotOfBotLip, L17_CTopOfTopLip, L17_LMouthCorner, L17_RMouthCorner }; const Shape shape17(Shape17OrEmpty(shape)); if (shape17.rows == 0) // could not convert the shape to a Shape17? return ShapeWidth(shape) / 2; // fallback, note return double eyemouth = CanonicalEyeMouthDist(shape17); if (eyemouth == 0) // pupils and mouth not available? { const int eye = TabPoint(eyes, NELEMS(eyes), shape17); const int mouth = TabPoint(mouths, NELEMS(mouths), shape17); if (eye >= 0 && mouth >= 0) // actual or surrogate points available? { eyemouth = PointDist(shape17, eye, mouth) * CanonicalEyeMouthDist(MEANSHAPE17) / PointDist(MEANSHAPE17, eye, mouth); } } if (eyemouth == 0) { // last resort, estimate eyemouth dist from shape extent eyemouth = MAX(ShapeWidth(shape17), ShapeHeight(shape17)) * PointDist(MEANSHAPE17, L17_LPupil, L17_CBotOfBotLip) / MAX(ShapeWidth(MEANSHAPE17), ShapeHeight(MEANSHAPE17)); } CV_Assert(eyemouth > 1 && eyemouth < 1e5); // sanity check return eyemouth; }
static void WriteLandmarkedImg( const Image& img, // in: the image const char* newpath, // in: the image path const Shape& shape, // in: the shape const Shape& cropshape, // in: crop image to this shape (typically the ref shape) unsigned color=C_RED, // in: rrggbb e.g. 0xff0000 is red int iworst=-1) // in: index of worst fitting point, -1 for none { CImage cimg; cvtColor(img, cimg, CV_GRAY2BGR); // color image if (iworst >= 0) // draw circle at worst fitting point? cv::circle(cimg, cv::Point(cvRound(shape(iworst, IX)), cvRound(shape(iworst, IY))), MAX(2, cvRound(ShapeWidth(shape) / 40)), cv::Scalar(255, 255, 0), 2); // cyan DrawShape(cimg, shape, color); if (crop_g) CropCimgToShapeWithMargin(cimg, cropshape); if (!cv::imwrite(newpath, cimg)) Err("Cannot write %s", newpath); }
double InterEyeDist( // inter-pupil distance of a face shape const Shape& shape) // in { static const int leyes[] = // surrogates for left pupil { L17_LPupil, L17_LEyeOuter, L17_LEyeInner, L17_LEyebrowInner, L17_LEyebrowOuter }; static const int reyes[] = // surrogates for right pupil { L17_RPupil, L17_REyeOuter, L17_REyeInner, L17_REyebrowInner, L17_REyebrowOuter }; const Shape shape17(Shape17OrEmpty(shape)); if (shape17.rows == 0) // could not convert the shape to a Shape17? return ShapeWidth(shape) / 2; // fallback, note return double eyedist = 0; const int leye = TabPoint(leyes, NELEMS(leyes), shape17); const int reye = TabPoint(reyes, NELEMS(reyes), shape17); if (leye >= 0 && reye >= 0 && // actual or surrogate points available? PointDist(shape17, leye, reye) > 1) // surrogates aren't co-located? { eyedist = PointDist(shape17, leye, reye) * PointDist(MEANSHAPE17, L17_LPupil, L17_RPupil) / PointDist(MEANSHAPE17, leye, reye); } else // last resort, estimate inter-pupil distance from shape extent { eyedist = MAX(ShapeWidth(shape17), ShapeHeight(shape17)) * PointDist(MEANSHAPE17, L17_LPupil, L17_RPupil) / MAX(ShapeWidth(MEANSHAPE17), ShapeHeight(MEANSHAPE17)); } CV_Assert(eyedist > 1 && eyedist < 1e5); // sanity check return eyedist; }