// This file is part of OpenCV project. // It is subject to the license terms in the LICENSE file found in the top-level directory // of this distribution and at http://opencv.org/license.html. #include "precomp.hpp" #include "face_alignmentimpl.hpp" #include <fstream> #include <ctime> using namespace std; namespace cv{ namespace face{ bool FacemarkKazemiImpl :: findNearestLandmarks( vector< vector<int> >& nearest){ if(meanshape.empty()||loaded_pixel_coordinates.empty()){ String error_message = "Model not loaded properly.Aborting..."; CV_Error(Error::StsBadArg, error_message); return false; } nearest.resize(loaded_pixel_coordinates.size()); for(unsigned long i=0 ; i< loaded_pixel_coordinates.size(); i++){ for(unsigned long j = 0;j<loaded_pixel_coordinates[i].size();j++){ nearest[i].push_back(getNearestLandmark(loaded_pixel_coordinates[i][j])); } } return true; } void FacemarkKazemiImpl :: readSplit(ifstream& is, splitr &vec) { is.read((char*)&vec.index1, sizeof(vec.index1)); is.read((char*)&vec.index2, sizeof(vec.index2)); is.read((char*)&vec.thresh, sizeof(vec.thresh)); uint32_t dummy_ = 0; is.read((char*)&dummy_, sizeof(dummy_)); // buggy writer structure alignment CV_CheckEQ((int)(sizeof(vec.index1) + sizeof(vec.index2) + sizeof(vec.thresh) + sizeof(dummy_)), 24, "Invalid build configuration"); } void FacemarkKazemiImpl :: readLeaf(ifstream& is, vector<Point2f> &leaf) { uint64_t size; is.read((char*)&size, sizeof(size)); leaf.resize((size_t)size); is.read((char*)&leaf[0], leaf.size() * sizeof(Point2f)); } void FacemarkKazemiImpl :: readPixels(ifstream& is,uint64_t index) { is.read((char*)&loaded_pixel_coordinates[(unsigned long)index][0], loaded_pixel_coordinates[(unsigned long)index].size() * sizeof(Point2f)); } void FacemarkKazemiImpl :: loadModel(String filename){ if(filename.empty()){ String error_message = "No filename found.Aborting...."; CV_Error(Error::StsBadArg, error_message); return ; } ifstream f(filename.c_str(),ios::binary); if(!f.is_open()){ String error_message = "No file with given name found.Aborting...."; CV_Error(Error::StsBadArg, error_message); return ; } uint64_t len; f.read((char*)&len, sizeof(len)); char* temp = new char[(size_t)len+1]; f.read(temp, len); temp[len] = '\0'; string s(temp); delete [] temp; if(s.compare("cascade_depth")!=0){ String error_message = "Data not saved properly.Aborting....."; CV_Error(Error::StsBadArg, error_message); return ; } uint64_t cascade_size; f.read((char*)&cascade_size,sizeof(cascade_size)); loaded_forests.resize((unsigned long)cascade_size); f.read((char*)&len, sizeof(len)); temp = new char[(unsigned long)len+1]; f.read(temp, len); temp[len] = '\0'; s = string(temp); delete [] temp; if(s.compare("pixel_coordinates")!=0){ String error_message = "Data not saved properly.Aborting....."; CV_Error(Error::StsBadArg, error_message); return ; } loaded_pixel_coordinates.resize((unsigned long)cascade_size); uint64_t num_pixels; f.read((char*)&num_pixels,sizeof(num_pixels)); for(unsigned long i=0 ; i < cascade_size ; i++){ loaded_pixel_coordinates[i].resize((unsigned long)num_pixels); readPixels(f,i); } f.read((char*)&len, sizeof(len)); temp = new char[(unsigned long)len+1]; f.read(temp, len); temp[len] = '\0'; s = string(temp); delete [] temp; if(s.compare("mean_shape")!=0){ String error_message = "Data not saved properly.Aborting....."; CV_Error(Error::StsBadArg, error_message); return ; } uint64_t mean_shape_size; f.read((char*)&mean_shape_size,sizeof(mean_shape_size)); meanshape.resize((unsigned long)mean_shape_size); f.read((char*)&meanshape[0], meanshape.size() * sizeof(Point2f)); if(!setMeanExtreme()) exit(0); f.read((char*)&len, sizeof(len)); temp = new char[(unsigned long)len+1]; f.read(temp, len); temp[len] = '\0'; s = string(temp); delete [] temp; if(s.compare("num_trees")!=0){ String error_message = "Data not saved properly.Aborting....."; CV_Error(Error::StsBadArg, error_message); return ; } uint64_t num_trees; f.read((char*)&num_trees,sizeof(num_trees)); for(unsigned long i=0;i<cascade_size;i++){ for(unsigned long j=0;j<num_trees;j++){ regtree tree; f.read((char*)&len, sizeof(len)); char* temp2 = new char[(unsigned long)len+1]; f.read(temp2, len); temp2[len] = '\0'; s =string(temp2); delete [] temp2; if(s.compare("num_nodes")!=0){ String error_message = "Data not saved properly.Aborting....."; CV_Error(Error::StsBadArg, error_message); return ; } uint64_t num_nodes; f.read((char*)&num_nodes,sizeof(num_nodes)); tree.nodes.resize((unsigned long)num_nodes+1); for(unsigned long k=0; k < num_nodes ; k++){ f.read((char*)&len, sizeof(len)); char* temp3 = new char[(unsigned long)len+1]; f.read(temp3, len); temp3[len] = '\0'; s =string(temp3); delete [] temp3; tree_node node; if(s.compare("split")==0){ splitr split; readSplit(f,split); node.split = split; node.leaf.clear(); } else if(s.compare("leaf")==0){ vector<Point2f> leaf; readLeaf(f,leaf); node.leaf = leaf; } else{ String error_message = "Data not saved properly.Aborting....."; CV_Error(Error::StsBadArg, error_message); return ; } tree.nodes[k]=node; } loaded_forests[i].push_back(tree); } } f.close(); isModelLoaded = true; } /** * @brief Copy the contents of a corners vector to an OutputArray, settings its size. */ static void _copyVector2Output(std::vector< std::vector< Point2f > > &vec, OutputArrayOfArrays out) { out.create((int)vec.size(), 1, CV_32FC2); if (out.isMatVector()) { for (unsigned int i = 0; i < vec.size(); i++) { out.create(68, 1, CV_32FC2, i); Mat &m = out.getMatRef(i); Mat(Mat(vec[i]).t()).copyTo(m); } } else if (out.isUMatVector()) { for (unsigned int i = 0; i < vec.size(); i++) { out.create(68, 1, CV_32FC2, i); UMat &m = out.getUMatRef(i); Mat(Mat(vec[i]).t()).copyTo(m); } } else if (out.kind() == _OutputArray::STD_VECTOR_VECTOR) { for (unsigned int i = 0; i < vec.size(); i++) { out.create(68, 1, CV_32FC2, i); Mat m = out.getMat(i); Mat(Mat(vec[i]).t()).copyTo(m); } } else { CV_Error(cv::Error::StsNotImplemented, "Only Mat vector, UMat vector, and vector<vector> OutputArrays are currently supported."); } } bool FacemarkKazemiImpl::fit(InputArray img, InputArray roi, OutputArrayOfArrays _landmarks) { if(!isModelLoaded){ String error_message = "No model loaded. Aborting...."; CV_Error(Error::StsBadArg, error_message); return false; } Mat image = img.getMat(); Mat roimat = roi.getMat(); std::vector<Rect> faces = roimat.reshape(4, roimat.rows); std::vector<std::vector<Point2f> > shapes; shapes.resize(faces.size()); if(image.empty()){ String error_message = "No image found.Aborting.."; CV_Error(Error::StsBadArg, error_message); return false; } if(faces.empty()){ String error_message = "No faces found.Aborting.."; CV_Error(Error::StsBadArg, error_message); return false; } if(meanshape.empty()||loaded_forests.empty()||loaded_pixel_coordinates.empty()){ String error_message = "Model not loaded properly.Aborting..."; CV_Error(Error::StsBadArg, error_message); return false; } if(loaded_forests.size()==0){ String error_message = "Model not loaded properly.Aboerting..."; CV_Error(Error::StsBadArg, error_message); return false; } if(loaded_pixel_coordinates.size()==0){ String error_message = "Model not loaded properly.Aboerting..."; CV_Error(Error::StsBadArg, error_message); return false; } vector< vector<int> > nearest_landmarks; findNearestLandmarks(nearest_landmarks); tree_node curr_node; vector<Point2f> pixel_relative; vector<int> pixel_intensity; Mat warp_mat; for(size_t e=0;e<faces.size();e++){ shapes[e]=meanshape; convertToActual(faces[e],warp_mat); for(size_t i=0;i<loaded_forests.size();i++){ pixel_intensity.clear(); pixel_relative = loaded_pixel_coordinates[i]; getRelativePixels(shapes[e],pixel_relative,nearest_landmarks[i]); getPixelIntensities(image,pixel_relative,pixel_intensity,faces[e]); for(size_t j=0;j<loaded_forests[i].size();j++){ regtree tree = loaded_forests[i][j]; curr_node = tree.nodes[0]; unsigned long curr_node_index = 0; while(curr_node.leaf.size()==0) { if ((float)pixel_intensity[(unsigned long)curr_node.split.index1] - (float)pixel_intensity[(unsigned long)curr_node.split.index2] > curr_node.split.thresh) { curr_node_index=left(curr_node_index); } else curr_node_index=right(curr_node_index); curr_node = tree.nodes[curr_node_index]; } for(size_t p=0;p<curr_node.leaf.size();p++){ shapes[e][p]=shapes[e][p] + curr_node.leaf[p]; } } } for(unsigned long j=0;j<shapes[e].size();j++){ Mat C = (Mat_<double>(3,1) << shapes[e][j].x, shapes[e][j].y, 1); Mat D = warp_mat*C; shapes[e][j].x=float(D.at<double>(0,0)); shapes[e][j].y=float(D.at<double>(1,0)); } } _copyVector2Output(shapes, _landmarks); return true; } }//cv }//face