static Shape AlignMeanShapeToFaceDetRect( const DetPar& detpar, // in const Shape& meanshape, // in double scale, // in: scale the face rectangle const Image& img) // io: the image (grayscale) { if (trace_g) lprintf("AlignToFaceDetBox "); DetPar detpar1(detpar); if (IsLeftFacing(detpar.eyaw)) detpar1 = FlipDetPar(detpar, img.cols); CV_Assert(meanshape.rows > 0 && meanshape.cols == 2); const double xscale = detpar1.width * scale / DET_FACE_WIDTH; const double yscale = detpar1.height * scale / DET_FACE_WIDTH; Shape startshape = AlignShape(meanshape, xscale, 0, detpar1.x, 0, yscale, detpar1.y); return startshape; }
static Shape AlignMeanShapeToBothEyesNoMouth( const DetPar& detpar, // in const Shape& meanshape) // in { if (trace_g) lprintf("AlignToBothEyesNoMouth "); CV_Assert(NSIZE(meanshape) > 0 && PointUsed(meanshape, 0)); CV_Assert(Valid(detpar.lex)); CV_Assert(Valid(detpar.rex)); Shape meanline(2, 2), detline(2, 2); // line from eye to eye meanline(0, IX) = meanshape(L_LPupil, IX); // left eye meanline(0, IY) = meanshape(L_LPupil, IY); meanline(1, IX) = meanshape(L_RPupil, IX); // right eye meanline(1, IY) = meanshape(L_RPupil, IY); detline(0, IX) = detpar.lex; // left eye detline(0, IY) = detpar.ley; detline(1, IX) = detpar.rex; // right eye detline(1, IY) = detpar.rey; return AlignShape(meanshape, AlignmentMat(meanline, detline)); }
static Shape AlignMeanShapeToRightEyeAndMouth( const DetPar& detpar, // in const Shape& meanshape) // in { if (trace_g) lprintf("AlignToRightEyeAndMouth "); CV_Assert(NSIZE(meanshape) > 0 && PointUsed(meanshape, 0)); CV_Assert(!Valid(detpar.lex)); // left eye invalid? (else why are we here?) CV_Assert(Valid(detpar.rex)); // right eye valid? CV_Assert(Valid(detpar.mouthx)); // mouth valid? const double x_meanmouth = (meanshape(L_CTopOfTopLip, IX) + meanshape(L_CBotOfBotLip, IX)) / 2; const double y_meanmouth = (meanshape(L_CTopOfTopLip, IY) + meanshape(L_CBotOfBotLip, IY)) / 2; Shape meanline(2, 2), detline(2, 2); // line from eye to mouth meanline(0, IX) = meanshape(L_RPupil, IX); // right eye meanline(0, IY) = meanshape(L_RPupil, IY); meanline(1, IX) = x_meanmouth; // mouth meanline(1, IY) = y_meanmouth; detline(0, IX) = detpar.rex; // right eye detline(0, IY) = detpar.rey; detline(1, IX) = detpar.mouthx; // mouth detline(1, IY) = detpar.mouthy; return AlignShape(meanshape, AlignmentMat(meanline, detline)); }
//----------------------------------------------------------------------------- void GetStartShapeFromPreviousSearch (SHAPE &StartShape, // out const SHAPE &PrevShape, // in: final shape from previous search const SHAPE &MeanShape) // in { if (MeanShape.nrows() == PrevShape.nrows()) StartShape = PrevShape; else if (MeanShape.nrows() < PrevShape.nrows()) { StartShape = PrevShape; StartShape.dimKeep(MeanShape.nrows(), 2); } else // MeanShape.nrows() > PrevShape.nrows() { // The algorithm below is: use points from PrevShape where possible, // but of a point is unused in PrevShape, use the point from the // aligned MeanShape instead. // use "assign" not "=" because dims may be different StartShape.assign(MeanShape); SHAPE Combined(PrevShape); Combined.dimKeep(MeanShape.nrows(), 2); AlignShape(StartShape, Combined); const int nRows = PrevShape.nrows(); for (unsigned iRow = 0; iRow < unsigned(nRows); iRow++) if (fPointUsed(StartShape, iRow)) StartShape.row(iRow) = PrevShape.row(iRow); } }
static Shape AlignMeanShapeToBothEyesEstMouth( const DetPar& detpar, // in const Shape& meanshape) // in { // .48 was tested to give slightly better worse case results than .50 static double EYEMOUTH_TO_FACERECT_RATIO = .48; if (trace_g) lprintf("AlignToBothEyesNoMouth(EstMouth) "); CV_Assert(NSIZE(meanshape) > 0 && PointUsed(meanshape, 0)); CV_Assert(Valid(detpar.lex)); CV_Assert(Valid(detpar.rex)); // estimate the mouth's position double x_eyemid = 0; switch (detpar.eyaw) { case EYAW00: // mid point x_eyemid = .50 * detpar.lex + .50 * detpar.rex; break; // TODO The constants below have not been empirically optimized. case EYAW_45: // closer to left eye x_eyemid = .30 * detpar.lex + .70 * detpar.rex; break; case EYAW_22: // closer to left eye x_eyemid = .30 * detpar.lex + .70 * detpar.rex; break; case EYAW22: // closer to right eye x_eyemid = .30 * detpar.lex + .70 * detpar.rex; break; case EYAW45: // closer to right eye x_eyemid = .30 * detpar.lex + .70 * detpar.rex; break; default: Err("AlignMeanShapeToBothEyesEstMouth: Invalid eyaw %d", detpar.eyaw); break; } const double y_eyemid = (detpar.ley + detpar.rey) / 2; Shape mean_tri(3, 2), det_tri(3, 2); // triangle of eyes and mouth mean_tri(0, IX) = meanshape(L_LPupil, IX); // left eye mean_tri(0, IY) = meanshape(L_LPupil, IY); mean_tri(1, IX) = meanshape(L_RPupil, IX); // right eye mean_tri(1, IY) = meanshape(L_RPupil, IY); mean_tri(2, IX) = meanshape(L_CBotOfBotLip, IX); // mouth mean_tri(2, IY) = meanshape(L_CBotOfBotLip, IY); det_tri(0, IX) = detpar.lex; // left eye det_tri(0, IY) = detpar.ley; det_tri(1, IX) = detpar.rex; // right eye det_tri(1, IY) = detpar.rey; det_tri(2, IX) = x_eyemid; // mouth det_tri(2, IY) = y_eyemid + EYEMOUTH_TO_FACERECT_RATIO * detpar.width; return AlignShape(meanshape, AlignmentMat(mean_tri, det_tri)); }
SHAPE ConformShapeToModel (Vec &b, // io const SHAPE &Shape, // in const ASM_MODEL &Model, // in int iLev, // in bool fShapeModelFinalIter) // in { Vec MeanShape(Model.AsmLevs[iLev].MeanShape); // For calculations below we need to see shapes (nrows x 2) as vectors (1 x 2*nrows). // Note that this is a "view" so if you change MeanShapeAsVec you // are changing MeanShape too, and vice versa. VecView MeanShapeAsVec(MeanShape.viewAsCol()); // find y, the model shape that best fits Shape SHAPE OutShape(Shape); int nEigs = Model.AsmLevs[iLev].nEigs; double BMax = Model.AsmLevs[iLev].BMax; if (fShapeModelFinalIter) { // final iter in main ASM search loop so loosen up the model nEigs = Model.AsmLevs[iLev].nEigsFinal; BMax = Model.AsmLevs[iLev].BMaxFinal; } ASSERT(BMax > 0); ASSERT(nEigs > 0); SHAPE x(Shape.nrows(), 2); x.viewAsCol() = MeanShapeAsVec + Model.EigVecs * b; // generate a model shape x Mat Pose(AlignShape(x, Shape)); SHAPE y(TransformShape(Shape, Pose.inverse())); // project Shape into model space // update model params b to match y // We limit b to ensure we stay within model limits b = Model.EigInverse * (y.viewAsCol() - MeanShapeAsVec); LimitB(b, Model.AsmLevs[iLev].EigVals, nEigs, BMax); // generate OutShape from the model using our calculated b, // and align OutShape to Shape OutShape.viewAsCol() = Model.EigVecs * b; OutShape = TransformShape(Model.AsmLevs[iLev].MeanShape + OutShape, Pose); return OutShape; }
AAM_Shape AAMFit::InitShape( const AAM_Shape& pMeanShape, CvRect *pR, int pType = 0 ) { AAM_Shape detShape; AAM_Shape startShape; detShape.resize(2); detShape[0].x = pR->x; detShape[0].y = pR->y; detShape[1].x = detShape[0].x + pR->width; detShape[1].y = detShape[0].y + pR->height; if( pType == AAM_FIT_FACE ) AdjustFaceShape(detShape); else if( pType == AAM_FIT_MOUTH ) AdjustMouthShape(detShape); AlignShape(startShape, detShape, pMeanShape); return startShape; }
static Shape PinMeanShape( // align mean shape to the pinned points const Shape& pinned, // in: at least two of these points must be set const Shape& meanshape) // in { CV_Assert(pinned.rows == meanshape.rows); int ipoint, nused = 0; // number of points used in pinned for (ipoint = 0; ipoint < meanshape.rows; ipoint++) if (PointUsed(pinned, ipoint)) nused++; if (nused < 2) Err("Need at least two pinned landmarks"); // Create an anchor shape (the pinned landmarks) and an alignment shape (the // points in meanshape that correspond to those pinned landmarks). Do that by // copying the used points in pinned to pinned_used, and the corresponding // points in meanshape to meanused. Shape pinned_used(nused, 2), mean_used(nused, 2); int i = 0; for (ipoint = 0; ipoint < meanshape.rows; ipoint++) if (PointUsed(pinned, ipoint)) { pinned_used(i, IX) = pinned(ipoint, IX); pinned_used(i, IY) = pinned(ipoint, IY); mean_used(i, IX) = meanshape(ipoint, IX); mean_used(i, IY) = meanshape(ipoint, IY); i++; } CV_Assert(i == nused); // transform meanshape to pose generated by aligning mean_used to pinned_used Shape TransformedShape( AlignShape(meanshape, AlignmentMat(mean_used, pinned_used))); return JitterPointsAt00(TransformedShape); }
static Shape AlignMeanShapeToBothEyesAndMouth( const DetPar& detpar, // in const Shape& meanshape) // in { if (trace_g) lprintf("AlignToBothEyesAndMouth "); CV_Assert(NSIZE(meanshape) > 0 && PointUsed(meanshape, 0)); CV_Assert(Valid(detpar.mouthx)); CV_Assert(Valid(detpar.lex)); CV_Assert(Valid(detpar.rex)); Shape mean_tri(3, 2), det_tri(3, 2); // triangle of eyes and mouth const double x_meanmouth = (meanshape(L_CTopOfTopLip, IX) + meanshape(L_CBotOfBotLip, IX)) / 2.; const double y_meanmouth = (meanshape(L_CTopOfTopLip, IY) + meanshape(L_CBotOfBotLip, IY)) / 2.; mean_tri(0, IX) = meanshape(L_LPupil, IX); // left eye mean_tri(0, IY) = meanshape(L_LPupil, IY); mean_tri(1, IX) = meanshape(L_RPupil, IX); // right eye mean_tri(1, IY) = meanshape(L_RPupil, IY); mean_tri(2, IX) = x_meanmouth; // mouth mean_tri(2, IY) = y_meanmouth; det_tri(0, IX) = detpar.lex; // left eye det_tri(0, IY) = detpar.ley; det_tri(1, IX) = detpar.rex; // right eye det_tri(1, IY) = detpar.rey; det_tri(2, IX) = detpar.mouthx; // mouth det_tri(2, IY) = detpar.mouthy; return AlignShape(meanshape, AlignmentMat(mean_tri, det_tri)); }