#include "Flandmark.h"
#include "CFeaturePool.h"
#include "CSparseLBPFeatures.h"
#include "CImg.h"
#include "helpers.h"
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
typedef float fl_double_t;
/**
* @brief LSBestLine
* @param points
* @param N
* @return
*/
fl_double_t * LSBestLine(const fl_double_t *points, const int N)
{
fl_double_t *line = new fl_double_t[2];
fl_double_t mx = 0;
fl_double_t my = 0;
fl_double_t sumXminMx2 = 0;
fl_double_t dotProd = 0;
for (int i=0; i < N; ++i)
{
mx += points[INDEX(0, i, 2)];
my += points[INDEX(1, i, 2)];
}
mx /= N;
my /= N;
for (int i=0; i < N; ++i)
{
fl_double_t tmp = (points[INDEX(0, i, 2)]-mx);
dotProd += tmp*(points[INDEX(1, i, 2)]-my);
sumXminMx2 += tmp*tmp;
}
dotProd /= sumXminMx2;
line[1] = dotProd;
line[0] = my - line[1]*mx;
return line;
}
/**
* @brief getUpdatedBBOX
* @param P
* @param N
* @param bbox
*/
void getUpdatedBBOX(const fl_double_t *P, const int N, int *bbox)
{
int left_eye[] = {42, 43, 44, 45, 46, 47};
int right_eye[] = {36, 37, 38, 39, 40, 41};
fl_double_t LeftEye[2] = {0, 0};
fl_double_t RightEye[2] = {0, 0};
fl_double_t CP[2] = {0, 0};
fl_double_t eyes[2*13];
for (int i=0; i < 6; ++i)
{
eyes[INDEX(0, i, 2)] = P[INDEX(0, left_eye[i], 2)];
eyes[INDEX(1, i, 2)] = P[INDEX(1, left_eye[i], 2)];
LeftEye[0] += P[INDEX(0, left_eye[i], 2)];
LeftEye[1] += P[INDEX(1, left_eye[i], 2)];
eyes[INDEX(0, i+7, 2)] = P[INDEX(0, right_eye[i], 2)];
eyes[INDEX(1, i+7, 2)] = P[INDEX(1, right_eye[i], 2)];
RightEye[0] += P[INDEX(0, right_eye[i], 2)];
RightEye[1] += P[INDEX(1, right_eye[i], 2)];
}
eyes[INDEX(0, 6, 2)] = P[INDEX(0, 27, 2)];
eyes[INDEX(1, 6, 2)] = P[INDEX(1, 27, 2)];
LeftEye[0] /= 6;
LeftEye[1] /= 6;
RightEye[0] /= 6;
RightEye[1] /= 6;
fl_double_t *f2 = LSBestLine(eyes, 13);
fl_double_t d = 0;
d = sqrt( ((LeftEye[0]-RightEye[0])*(LeftEye[0]-RightEye[0])) + ((LeftEye[1]-RightEye[1])*(LeftEye[1]-RightEye[1])) );
for (int i=0; i < N; ++i)
{
CP[0] += P[INDEX(0, i, 2)];
CP[1] += P[INDEX(1, i, 2)];
}
CP[0] /= N;
CP[1] /= N;
fl_double_t ec = 2.7;
fl_double_t bb_origin[8];
bb_origin[0] = -d/2.0 * ec; bb_origin[2] = d/2.0 * ec; bb_origin[4] = d/2.0 * ec; bb_origin[6] = -d/2.0 * ec;
bb_origin[1] = -d/2.0 * ec; bb_origin[3] = -d/2.0 * ec; bb_origin[5] = d/2.0 * ec; bb_origin[7] = d/2.0 * ec;
fl_double_t X1[2] = {0, 0};
fl_double_t X2[2] = {1, 0};
fl_double_t vX[2] = {X2[0]-X1[0], X2[1]-X1[1]};
fl_double_t A1[2] = {X1[0], f2[0]+f2[1]*X1[0]};
fl_double_t A2[2] = {X2[0], f2[0]+f2[1]*X2[0]};
fl_double_t vA[2] = {A2[0]-A1[0], A2[1]-A1[1]};
fl_double_t ph;
ph = atan2(vA[1], vA[0]);
for (int i=0; i < 4; ++i)
{
bbox[INDEX(0, i, 2)] = (int)floor( cos(ph)*bb_origin[INDEX(0, i, 2)] - sin(ph)*bb_origin[INDEX(1, i, 2)] + CP[0] + 0.5 );
bbox[INDEX(1, i, 2)] = (int)floor( sin(ph)*bb_origin[INDEX(0, i, 2)] + cos(ph)*bb_origin[INDEX(1, i, 2)] + CP[1] + 0.5 );
}
delete [] f2;
}
cimg_library::CImg<unsigned char> * cvImgToCImg(cv::Mat &cvImg)
{
cimg_library::CImg<unsigned char> * result = new cimg_library::CImg<unsigned char>(cvImg.cols, cvImg.rows);
for (int x = 0; x < cvImg.cols; ++x)
for (int y = 0; y < cvImg.rows; ++y)
(*result)(x, y) = cvImg.at<uchar>(y, x);
return result;
}
cv::Mat & CImgtoCvImg(cv::Mat &result, cimg_library::CImg<unsigned char> *img)
{
result = cv::Mat(img->height(), img->width(), CV_8U);
for (int x=0; x < result.cols; ++x)
for (int y=0; y < result.rows; ++y)
result.at<uchar>(y, x) = (*img)(x, y);
return result;
}
int main(int argc, char *argv[])
{
fl_double_t *landmarks = 0x0;
fl_double_t *coarse_landmarks = 0x0;
int bbox[8], bbox_corrected[8];
// Load image
cimg_library::CImg<unsigned char> inputImage("../../examples/testImage.png");
cimg_library::CImg<unsigned char> img_gray;
// Convert to grayscale
img_gray = inputImage.get_RGBtoYCbCr().get_channel(0);
// initialization of C2F-DPM
const char* CDPM_MODEL = "./models/CDPM.xml";
const char* FDPM_MODEL = "./models/FDPM.xml";
clandmark::Flandmark *CDPM = clandmark::Flandmark::getInstanceOf(CDPM_MODEL);
clandmark::Flandmark *FDPM = clandmark::Flandmark::getInstanceOf(FDPM_MODEL);
if (!CDPM || !FDPM)
{
std::cerr << "Couldn't create instance of C-DPM or F-DPM." << std::endl;
return -1;
}
const int * bw_size = CDPM->getBaseWindowSize();
clandmark::CFeaturePool * featuresPoolCDPM = new clandmark::CFeaturePool(bw_size[0], bw_size[1]);
featuresPoolCDPM->addFeaturesToPool(
new clandmark::CSparseLBPFeatures(featuresPoolCDPM->getWidth(),
featuresPoolCDPM->getHeight(),
featuresPoolCDPM->getPyramidLevels(),
featuresPoolCDPM->getCumulativeWidths())
);
CDPM->setNFfeaturesPool(featuresPoolCDPM);
const int * bw_size2 = FDPM->getBaseWindowSize();
clandmark::CFeaturePool * featuresPoolFDPM = new clandmark::CFeaturePool(bw_size2[0], bw_size2[1]);
featuresPoolFDPM->addFeaturesToPool(
new clandmark::CSparseLBPFeatures(featuresPoolFDPM->getWidth(),
featuresPoolFDPM->getHeight(),
featuresPoolFDPM->getPyramidLevels(),
featuresPoolFDPM->getCumulativeWidths())
);
FDPM->setNFfeaturesPool(featuresPoolFDPM);
// Detect Face
cv::Mat inputImageMat = cv::imread("../../examples/testImage.png");
cv::Mat frame_gray;
cv::cvtColor( inputImageMat, frame_gray, CV_BGR2GRAY );
std::vector<cv::Rect> faces;
cv::CascadeClassifier face_cascade;
std::string face_cascade_name = "../../data/haarcascade_frontalface_alt.xml";
if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading\n"); return -1; };
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, cv::Size(30, 30) );
for( uint32_t i = 0; i < faces.size(); i++ )
{
// Get detected face bounding box
bbox[0] = faces[i].x;
bbox[1] = faces[i].y;
bbox[2] = faces[i].x+faces[i].width;
bbox[3] = faces[i].y;
bbox[4] = faces[i].x+faces[i].width;
bbox[5] = faces[i].y+faces[i].height;
bbox[6] = faces[i].x;
bbox[7] = faces[i].y+faces[i].height;
bbox_corrected[0] = faces[i].x;
bbox_corrected[1] = faces[i].y;
bbox_corrected[2] = faces[i].x+faces[i].width;
bbox_corrected[3] = faces[i].y;
bbox_corrected[4] = faces[i].x+faces[i].width;
bbox_corrected[5] = faces[i].y+faces[i].height;
bbox_corrected[6] = faces[i].x;
bbox_corrected[7] = faces[i].y+faces[i].height;
std::cout << " Index i is : " << "\n";
std::cout << i << "\n";
}
// (skipped)
// bbox in the following code contains detected face (e.g. by OpenCV face detector)
// its format is [x_min, y_min, x_max, y_max]
// --- C2F-DPM detector ---
// Run the C-DPM detector
CDPM->detect(&img_gray, &bbox[0]);
// CDPM->detect_optimized(&img_gray, &bbox[0]);
//CDPM->detect_optimized(img_gray, &bbox[0], 0);
// Get detected landmarks
coarse_landmarks = CDPM->getLandmarks();
// Update face box
getUpdatedBBOX(coarse_landmarks, CDPM->getLandmarksCount(), &bbox_corrected[0]);
// Run the F-DPM detector
FDPM->detect(&img_gray, &bbox_corrected[0]);
//FDPM->detect_optimized(&img_gray, &bbox_corrected[0]);
// Get detected landmarks
landmarks = FDPM->getLandmarks();
// Show landmarks
// (skipped)
// Cleanup
// delete &inputImage;
// delete &img_gray;
delete CDPM;
delete FDPM;
delete featuresPoolCDPM;
delete featuresPoolFDPM;
}