Shape ConvertShape( // return shape with nlandmarks, return no rows if can't const Shape& shape, // in int nlandmarks) // in: shape.rows=no change, 17=shape17, anything else return no rows // if shape.rows=77, treat specially: // 77=nochange, 76=muct76, 68=xm2vts, 22=ar, 20=bioid, 17=shape17 { Shape newshape; if (nlandmarks == shape.rows) newshape = shape.clone(); else if (nlandmarks == 17) newshape = Shape17OrEmpty(shape); else if (shape.rows == 76) // MUCT 76 { switch (nlandmarks) { case 68: newshape = DimKeep(shape.clone(), 68, 2); // MUCT 68 and XM2VTS break; default: break; } } else if (shape.rows == 77) // MUCT 77 (Stasm version 4) { switch (nlandmarks) { case 20: newshape = Shape77As20(shape); // BioID break; case 22: newshape = Shape77As22(shape); // AR break; case 68: newshape = Shape77As68(shape); // MUCT 68 and XM2VTS break; case 76: newshape = Shape77As76(shape); // MUCT 76 (Stasm version 3) break; default: break; } } CV_Assert(newshape.rows == nlandmarks || newshape.rows == 0); return newshape; }
void GenAndWriteShapeMod( // generate the shape model and write it to a .mh file ShapeFile& sh, // io: shapes_ field modified if there are missing points // entire sh changed if TASM_SUBSET_DESC_MODS const char* outdir, // in: output directory (-d flag) const char* modname, // in: e.g. "yaw00" const char* cmdline, // in: command line used to invoke tasm bool force_facedet, // in: facedet the images themselves (ignore shapefile facedets) bool write_detpars, // in: write the image detpars to facedet.shape bool write_imputed_shapes, // in: write imputed.shapes file if shapes are imputed bool write_imgs) // in: write images showing landmark tab values { clock_t start_time = clock(); lprintf("--- Generating the shape model ---\n"); // the reference shape is the first shape with no missing // points and irefshape is its index int irefshape = FirstShapeWithAllPoints(sh); vec_int nused_vec; // vec [nshapes] of int, nbr of used points in each shape NbrUsedPointsVec(nused_vec, sh.shapes_); const int nshapes_with_missing_points = NbrShapesWithMissingPoints(sh.shapes_, nused_vec); if (nshapes_with_missing_points) ShowPercentagePointsMissing( nshapes_with_missing_points, sh.shapes_); Shape meanshape; VEC eigvals; MAT eigvecs; vec_Shape aligned_shapes; // sh.shapes_ aligned to ref shape GenShapeMod( meanshape, eigvals, eigvecs, aligned_shapes, sh, irefshape, nused_vec, outdir, modname, cmdline, force_facedet, write_detpars); // shapemodel_sh is the shapes we used to build the shape model // (this will be sh unless TASM_REBUILD_SUBSET is not NULL) ShapeFile shapemodel_sh(sh); // copy sh to shapemodel_sh if (nshapes_with_missing_points) { // Points are missing in some shapes (typically because the points // were manually landmarked as missing because they are obscured). // Update sh.shape by imputing those points. // After this, all shapes in sh.shapes_ have all points. ImputeMissingPoints(sh.shapes_, aligned_shapes, meanshape, eigvals, eigvecs); if (write_imputed_shapes) WriteImputedShapes(sh, outdir, cmdline); // write imputed.shape if (TASM_REBUILD_SUBSET) { lprintf("--- Regenerating the shape model " "using the imputed shapes matching %s---\n", TASM_REBUILD_SUBSET); lprintf("Reference shape is now the first shape " "(since all shapes now all have all landmarks)\n"); irefshape = 0; // copy sh from ImputeMissingPoints above to shapemodel_sh shapemodel_sh = sh; shapemodel_sh.Subset_(TASM_REBUILD_SUBSET); if (TASM_SUBSET_DESC_MODS) sh = shapemodel_sh; NbrUsedPointsVec(nused_vec, shapemodel_sh.shapes_); GenShapeMod( meanshape, eigvals, eigvecs, aligned_shapes, shapemodel_sh, irefshape, nused_vec, outdir, modname, cmdline, force_facedet, false /*write_detpars*/); } } WriteShapeMod(TASM_MODNAME, meanshape, eigvals, eigvecs, outdir, cmdline); const double totaltime = double(clock() - start_time) / CLOCKS_PER_SEC; lprintf("[%.1f secs%s to generate the shape model]\n", totaltime, totaltime > 180? ssprintf(" (%.1f minutes)", totaltime / 60): ""); if (write_imgs) TasmDraw(shapemodel_sh, irefshape, meanshape, outdir); // sanity check that we convert to Shape17 correctly or not at all const Shape shape17(Shape17OrEmpty(sh.shapes_[irefshape])); if (shape17.rows) // converted to Shape17? SanityCheckShape17(shape17); }
static void TraceShape( // write an image file showing current shape on the image const Shape& shape, // in: current search shape const Image& pyrimg, // in: image scaled to this pyramid level int ilev, // in: pyramid level (0 is full size) int iter, // in: model iteration (-1 if start shape) const char* suffix) // in { #if TRACE_IMAGES // will be 0 unless debugging (defined in stasm.h) static int index; // number images so they appear in order in the directory // start at index 30 because lower indices have already used for facedet etc. if (strcmp(suffix, "start") == 0) index = 30; Image img; // pyrimg rescaled back to full size image (after rescaling by eyemouth) const double RESOLUTION = 2; // 1 for no extra resolution, 2 for double resolution const double rescale = RESOLUTION / GetPyrScale(ilev); cv::resize(pyrimg, img, cv::Size(), rescale, rescale, cv::INTER_NEAREST); CImage cimg; cvtColor(img, cimg, CV_GRAY2BGR); // color image DesaturateImg(cimg); Shape shape1(RoundMat(shape)); shape1 += .4; // put shape points in center of rescaled pixels shape1 *= rescale; DrawShape(cimg, shape1, C_YELLOW, false, 1); char path[SLEN]; if (iter < 0) // start shape? sprintf(path, "%s_%2.2d_%s.bmp", Base(imgpath_g), index, suffix); else sprintf(path, "%s_%2.2d_lev%d_iter%d_%s.bmp", Base(imgpath_g), index, ilev, iter, suffix); ImgPrintf(cimg, 10 * RESOLUTION, 20 * RESOLUTION, C_YELLOW, 2, path); if (iter >= 0) { // draw 1D patch boundary at one point (patch is drawn // horizontal, not rotated to shape boundary as it should be) // [Thanks to Satish Lokkoju for RoundMat fix] Shape shape2(RoundMat(shape)); int ipoint = 0; int proflen = 9; // TASM_1D_PROFLEN int x1 = cvRound(shape2(ipoint, IX)) - proflen / 2; int x2 = x1 + proflen; int y1 = cvRound(shape2(ipoint, IY)); int y2 = y1 + 1; rectangle(cimg, cv::Point(cvRound(rescale * x1), cvRound(rescale * y1)), cv::Point(cvRound(rescale * x2), cvRound(rescale * y2)), CV_RGB(255,0,0), 1); // draw 2D patch boundary at one point if (ilev <= HAT_START_LEV) // we use HATs only at upper pyr levs { // get position of left eye pupil by first converting to a shape17 ipoint = 0; // assume we can't get position of left eye pupil Shape newshape(Shape17OrEmpty(shape2)); if (newshape.rows) // successfully converted to a shape17? ipoint = L17_LPupil; else newshape = shape2; #define round2(x) 2 * cvRound((x) / 2) int patchwidth = HAT_PATCH_WIDTH + round2(ilev * HAT_PATCH_WIDTH_ADJ); x1 = cvRound(newshape(ipoint, IX)) - patchwidth / 2; x2 = x1 + patchwidth; y1 = cvRound(newshape(ipoint, IY)) - patchwidth / 2; y2 = y1 + patchwidth; rectangle(cimg, cv::Point(cvRound(rescale * x1), cvRound(rescale * y1)), cv::Point(cvRound(rescale * x2), cvRound(rescale * y2)), CV_RGB(255,0,0), 1); } } lprintf("%s\n", path); if (!cv::imwrite(path, cimg)) Err("Cannot write %s", path); index++; #endif // TRACE_IMAGES }