static Shape AlignMeanShapeToFaceDet( 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("AlignToFaceDet "); 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 = TransformShape(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 const Shape shape17(Shape17(meanshape)); meanline(0, IX) = shape17(L17_LPupil, IX); // left eye meanline(0, IY) = shape17(L17_LPupil, IY); meanline(1, IX) = shape17(L17_RPupil, IX); // right eye meanline(1, IY) = shape17(L17_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 TransformShape(meanshape, AlignmentMat(meanline, detline)); }
static Shape AlignMeanShapeToRightEyeMouth( const DetPar& detpar, // in const Shape& meanshape) // in { if (trace_g) lprintf("AlignToRightEyeMouth "); 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 Shape shape17(Shape17(meanshape)); const double x_meanmouth = (shape17(L17_CTopOfTopLip, IX) + shape17(L17_CBotOfBotLip, IX)) / 2; const double y_meanmouth = (shape17(L17_CTopOfTopLip, IY) + shape17(L17_CBotOfBotLip, IY)) / 2; Shape meanline(2, 2), detline(2, 2); // line from eye to mouth meanline(0, IX) = shape17(L17_RPupil, IX); // right eye meanline(0, IY) = shape17(L17_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 TransformShape(meanshape, AlignmentMat(meanline, detline)); }
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; }
Mat AlignShape (SHAPE &Shape, // io const SHAPE &AnchorShape, // in const Vec *pWeights) // in: can be NULL { CheckSameNbrRows(Shape, AnchorShape, "AlignShape"); if (pWeights && pWeights->nrows() == 0) pWeights = NULL; if (pWeights) ASSERT(Shape.nrows() == pWeights->nelems()); double X1 = 0, Y1 = 0, X2 = 0, Y2 = 0, W = 0, Z = 0, C1 = 0, C2 = 0; int iRow = Shape.nrows(); while (iRow--) { const double x1 = AnchorShape(iRow, VX); const double y1 = AnchorShape(iRow, VY); const double x2 = Shape(iRow, VX); const double y2 = Shape(iRow, VY); if (x1 == 0 && y1 == 0) // is anchor landmark unused? ; else if (x2 == 0 && y2 == 0) // is landmark unused? ; else { const double w = (pWeights? (*pWeights)(iRow): 1.0); W += w; Z += w * (x2 * x2 + y2 * y2); X1 += w * x1; Y1 += w * y1; X2 += w * x2; Y2 += w * y2; C1 += w * (x1 * x2 + y1 * y2); C2 += w * (y1 * x2 - x1 * y2); } } double SolnData[] = { X2, -Y2, W, 0, Y2, X2, 0, W, Z, 0, X2, Y2, 0, Z, -Y2, X2 }; MatView Mat4(SolnData, 4, 4, 0); // 4x4, tda=0 double VecData[] = { X1, Y1, C1, C2 }; VecView Vec4(VecData, 4); Vec Soln(SolveWithLU(Mat4, Vec4)); double TransformData[] = { Soln(0), -Soln(1), Soln(2), // a b tx Soln(1), Soln(0), Soln(3), // c d ty 0, 0, 1 }; Mat Transform(TransformData, 3, 3); Shape = TransformShape(Shape, Transform); return Transform; }
void TransformInPlace (SHAPE &Shape, // io double x0, double y0, double z0, // in double x1, double y1, double z1) // in { double Tr[] = { x0, y0, z0, x1, y1, z1 }; Mat Transform(Tr, 2, 3); Shape = TransformShape(Shape, Transform); }
SHAPE TransformShape (const SHAPE &Shape, // in double x0, double y0, double z0, // in double x1, double y1, double z1) // in { double Tr[] = { x0, y0, z0, x1, y1, z1 }; Mat Transform(Tr, 2, 3); return TransformShape(Shape, Transform); }
static void AlignStartShapeToDet (SHAPE &StartShape, // out const DET_PARAMS &DetParams, // in const SHAPE &DetAv, // in double Scale) { ASSERT(DetAv.nrows() > 0 && DetAv.ncols() == 2); const double xScale = DetParams.width * Scale / DET_FACE_WIDTH; const double yScale = DetParams.height * Scale / DET_FACE_WIDTH; StartShape = TransformShape(DetAv, xScale, 0, DetParams.x, 0, yScale, DetParams.y); }
Shape ConformShapeToMod( // Return a copy of inshape conformed to the model VEC& b, // io: eigvec weights, 2n x 1 const Shape& inshape, // in: the current position of the landmarks const Shape& meanshape, // in: n x 2 const VEC& eigvals, // in: neigs x 1 const MAT& eigvecs, // in: 2n x neigs const MAT& eigvecsi, // in: neigs x 2n, inverse of eigvecs const double bmax, // in: for LimitB const VEC& pointweights) // in: contribution of each point to the pose { Shape shape(inshape.clone()); // estimate the pose which transforms the shape into the model space // (use the b from previous iterations of the ASM) MAT modelshape(AsColVec(meanshape) + eigvecs * b); modelshape = DimKeep(modelshape, shape.rows, 2); // redim back to 2 columns const MAT pose(AlignmentMat(modelshape, shape, Buf(pointweights))); // transform the shape into the model space modelshape = TransformShape(shape, pose.inv(cv::DECOMP_LU)); // update shape model params b to match modelshape, then limit b b = eigvecsi * AsColVec(modelshape - meanshape); LimitB(b, eigvals, bmax); // generate conformedshape from the model using the limited b // (we generate as a column vec, then redim back to 2 columns) const Shape conformedshape(DimKeep(eigvecs * b, shape.rows, 2)); // back to image space return JitterPointsAt00(TransformShape(meanshape + conformedshape, pose)); }
static Shape AlignMeanShapeToBothEyesMouth( const DetPar& detpar, // in const Shape& meanshape) // in { if (trace_g) lprintf("AlignToBothEyesMouth "); 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.; const Shape shape17(Shape17(meanshape)); mean_tri(0, IX) = shape17(L17_LPupil, IX); // left eye mean_tri(0, IY) = shape17(L17_LPupil, IY); mean_tri(1, IX) = shape17(L17_RPupil, IX); // right eye mean_tri(1, IY) = shape17(L17_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 TransformShape(meanshape, AlignmentMat(mean_tri, det_tri)); }
static Shape AlignMeanShapeToBothEyesEstMouth( const DetPar& detpar, // in const Shape& meanshape) // in { // .48 was tested to give slightly better worse case results than .50 static const double EYEMOUTH_TO_FACERECT_RATIO = .48; if (trace_g) lprintf("AlignToBothEyesEstMouth "); 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 const Shape shape17(Shape17(meanshape)); mean_tri(0, IX) = shape17(L17_LPupil, IX); // left eye mean_tri(0, IY) = shape17(L17_LPupil, IY); mean_tri(1, IX) = shape17(L17_RPupil, IX); // right eye mean_tri(1, IY) = shape17(L17_RPupil, IY); mean_tri(2, IX) = shape17(L17_CBotOfBotLip, IX); // mouth mean_tri(2, IY) = shape17(L17_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 TransformShape(meanshape, AlignmentMat(mean_tri, det_tri)); }