diff --git a/3rdparty/stasm4.0.0/stasm/src/facedet.cpp b/3rdparty/stasm4.0.0/stasm/src/facedet.cpp new file mode 100755 index 0000000..69b2dfc --- /dev/null +++ b/3rdparty/stasm4.0.0/stasm/src/facedet.cpp @@ -0,0 +1,221 @@ +// facedet.cpp: find faces in images (frontal model version) +// +// Copyright (C) 2005-2013, Stephen Milborrow + +#include "facedet.h" +#include "stasm_lib.h" + +namespace stasm +{ +typedef vector vec_DetPar; + +//static cv::CascadeClassifier facedet_g; // the face detector + +static double BORDER_FRAC = 0.1; // fraction of image width or height + // use 0.0 for no border + +//----------------------------------------------------------------------------- + +void FaceDet::OpenFaceDetector_( // called by stasm_init, init face det from XML file + const char* datadir, // in: directory of face detector files + void*) // in: unused (func signature compatibility) +{ + (void) datadir; + //OpenDetector(facedet_g, "haarcascade_frontalface_alt2.xml", datadir); +} + +// If a face is near the edge of the image, the OpenCV detectors tend to +// return a too-small face rectangle. By adding a border around the edge +// of the image we mitigate this problem. + +static Image EnborderImg( // return the image with a border + int& leftborder, // out: border size in pixels + int& topborder, // out: border size in pixels + const Image& img) // io +{ + Image bordered_img(img); + leftborder = cvRound(BORDER_FRAC * bordered_img.cols); + topborder = cvRound(BORDER_FRAC * bordered_img.rows); + copyMakeBorder(bordered_img, bordered_img, + topborder, topborder, leftborder, leftborder, + cv::BORDER_REPLICATE); + return bordered_img; +} + +void DetectFaces( // all face rects into detpars + vec_DetPar& detpars, // out + const Image& img, // in + int minwidth, + cv::CascadeClassifier cascade) // in: as percent of img width +{ + int leftborder = 0, topborder = 0; // border size in pixels + Image bordered_img(BORDER_FRAC == 0? + img: EnborderImg(leftborder, topborder, img)); + + // Detection results are very slightly better with equalization + // (tested on the MUCT images, which are not pre-equalized), and + // it's quick enough to equalize (roughly 10ms on a 1.6 GHz laptop). + + Image equalized_img; cv::equalizeHist(bordered_img, equalized_img); + + CV_Assert(minwidth >= 1 && minwidth <= 100); + + int minpix = MAX(100, cvRound(img.cols * minwidth / 100.)); + + // the params below are accurate but slow + static const double SCALE_FACTOR = 1.1; + static const int MIN_NEIGHBORS = 3; + static const int DETECTOR_FLAGS = 0; + + vec_Rect facerects = // all face rects in image + Detect(equalized_img, &cascade, NULL, + SCALE_FACTOR, MIN_NEIGHBORS, DETECTOR_FLAGS, minpix); + + // copy face rects into the detpars vector + + detpars.resize(NSIZE(facerects)); + for (int i = 0; i < NSIZE(facerects); i++) + { + Rect* facerect = &facerects[i]; + DetPar detpar; // detpar constructor sets all fields INVALID + // detpar.x and detpar.y is the center of the face rectangle + detpar.x = facerect->x + facerect->width / 2.; + detpar.y = facerect->y + facerect->height / 2.; + detpar.x -= leftborder; // discount the border we added earlier + detpar.y -= topborder; + detpar.width = double(facerect->width); + detpar.height = double(facerect->height); + detpar.yaw = 0; // assume face has no yaw in this version of Stasm + detpar.eyaw = EYAW00; + detpars[i] = detpar; + } +} + +// order by increasing distance from left marg, and dist from top marg within that + +static bool IncreasingLeftMargin( // compare predicate for std::sort + const DetPar& detpar1, // in + const DetPar& detpar2) // in +{ + return 1e5 * detpar2.x + detpar2.y > + 1e5 * detpar1.x + detpar1.y; +} + +// order by decreasing width, and dist from the left margin within that + +static bool DecreasingWidth( // compare predicate for std::sort + const DetPar& detpar1, // in + const DetPar& detpar2) // in +{ + return 1e5 * detpar2.width - detpar2.x < + 1e5 * detpar1.width - detpar1.x; + +} + +// Discard too big or small faces (this helps reduce the number of false positives) + +static void DiscardMissizedFaces( + vec_DetPar& detpars) // io +{ + // constants (TODO These have not yet been rigorously empirically adjusted.) + const double MIN_WIDTH = 1.33; // as fraction of median width + const double MAX_WIDTH = 1.33; // as fraction of median width + + if (NSIZE(detpars) >= 3) // need at least 3 faces + { + // sort the faces on their width (smallest first) so can get median width + sort(detpars.begin(), detpars.end(), DecreasingWidth); + const int median = cvRound(detpars[NSIZE(detpars) / 2].width); + const int minallowed = cvRound(median / MIN_WIDTH); + const int maxallowed = cvRound(MAX_WIDTH * median); + // keep only faces that are not too big or small + vec_DetPar all_detpars(detpars); + detpars.resize(0); + for (int iface = 0; iface < NSIZE(all_detpars); iface++) + { + DetPar* face = &all_detpars[iface]; + if (face->width >= minallowed && face->width <= maxallowed) + detpars.push_back(*face); + else if (trace_g || TRACE_IMAGES) + lprintf("[discard %d of %d]", iface, NSIZE(all_detpars)); + } + } +} + +static void TraceFaces( // write image showing detected face rects + const vec_DetPar& detpars, // in + const Image& img, // in + const char* filename) // in +{ + (void) detpars; + (void) img; + (void) filename; + +#if TRACE_IMAGES // will be 0 unless debugging (defined in stasm.h) + + CImage cimg; cvtColor(img, cimg, CV_GRAY2BGR); // color image + for (int iface = 0; iface < NSIZE(detpars); iface++) + { + const DetPar &detpar = detpars[iface]; + + rectangle(cimg, + cv::Point(cvRound(detpar.x - detpar.width/2), + cvRound(detpar.y - detpar.height/2)), + cv::Point(cvRound(detpar.x + detpar.width/2), + cvRound(detpar.y + detpar.height/2)), + CV_RGB(255,255,0), 2); + + ImgPrintf(cimg, // 10 * iface to minimize overplotting + detpar.x + 10 * iface, detpar.y, 0xffff00, 1, ssprintf("%d", iface)); + } + cv::imwrite(filename, cimg); + +#endif +} + +void FaceDet::DetectFaces_( // call once per image to find all the faces + const Image& img, // in: the image (grayscale) + const char*, // in: unused (match virt func signature) + bool multiface, // in: if false, want only the best face + int minwidth, // in: min face width as percentage of img width + void* user, // in: unused (match virt func signature) + cv::CascadeClassifier cascade) +{ + CV_Assert(user == NULL); + //CV_Assert(!facedet_g.empty()); // check that OpenFaceDetector_ was called + + DetectFaces(detpars_, img, minwidth, cascade); + TraceFaces(detpars_, img, "facedet_BeforeDiscardMissizedFaces.bmp"); + DiscardMissizedFaces(detpars_); + TraceFaces(detpars_, img, "facedet_AfterDiscardMissizedFaces.bmp"); + if (multiface) // order faces on increasing distance from left margin + { + sort(detpars_.begin(), detpars_.end(), IncreasingLeftMargin); + TraceFaces(detpars_, img, "facedet.bmp"); + } + else + { + // order faces on decreasing width, keep only the first (the largest face) + sort(detpars_.begin(), detpars_.end(), DecreasingWidth); + TraceFaces(detpars_, img, "facedet.bmp"); + if (NSIZE(detpars_)) + detpars_.resize(1); + } + iface_ = 0; // next invocation of NextFace_ must get first face +} + +// Get the (next) face from the image. +// If no face available, return detpar.x INVALID. +// Eyes, mouth, and rot in detpar always returned INVALID. + +const DetPar FaceDet::NextFace_(void) +{ + DetPar detpar; // detpar constructor sets all fields INVALID + + if (iface_ < NSIZE(detpars_)) + detpar = detpars_[iface_++]; + + return detpar; +} + +} // namespace stasm \ No newline at end of file diff --git a/3rdparty/stasm4.0.0/stasm/src/initasm.cpp b/3rdparty/stasm4.0.0/stasm/src/initasm.cpp new file mode 100755 index 0000000..be98c28 --- /dev/null +++ b/3rdparty/stasm4.0.0/stasm/src/initasm.cpp @@ -0,0 +1,35 @@ +// initasm.cpp: initialize the ASM model +// +// Copyright (C) 2005-2013, Stephen Milborrow + +#include "initasm.h" +#include "yaw00.h" + +namespace stasm +{ +void InitMods( // initialize ASM model + vec_Mod& mods, // out: ASM model (only one model in this version of Stasm) + const char* datadir) // in: directory of face detector files +{ + if (mods.empty()) // models not yet initialized? + { + mods.resize(1); // 1 model + + static const Mod mod_yaw00( + EYAW00, + ESTART_EYES, // ignore detected mouth for best startshape on frontal faces + datadir, + yaw00_meanshape, + yaw00_eigvals, + yaw00_eigvecs, + 20, // neigs (value from empirical testing) + 1.5, // bmax (value from empirical testing) + SHAPEHACKS_DEFAULT | SHAPEHACKS_SHIFT_TEMPLE_OUT, + YAW00_DESCMODS, // defined in yaw00.h + NELEMS(YAW00_DESCMODS)); + + mods[0] = &mod_yaw00; + } +} + +} // namespace stasm \ No newline at end of file