Files
opencv_contrib/modules/face/src/getlandmarks.cpp
T

289 lines
10 KiB
C++

// 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