From ba994f4404b6eadcab4e0ead46ef4d3ffeceb024 Mon Sep 17 00:00:00 2001 From: Antoine Villeret Date: Thu, 10 Jul 2014 14:39:22 +0000 Subject: lots of changes ! 1. switch to a new build system based on automake (because we need to check for some lib on ./configure before make) 2. sort files in different directory 3. add some new features (some of them need OpenCV >= 2.4.5) svn path=/trunk/externals/pix_opencv/; revision=17324 --- src/pix_opencv_facetracker.cc | 302 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 302 insertions(+) create mode 100644 src/pix_opencv_facetracker.cc (limited to 'src/pix_opencv_facetracker.cc') diff --git a/src/pix_opencv_facetracker.cc b/src/pix_opencv_facetracker.cc new file mode 100644 index 0000000..e5021d0 --- /dev/null +++ b/src/pix_opencv_facetracker.cc @@ -0,0 +1,302 @@ +//////////////////////////////////////////////////////// +// +// GEM - Graphics Environment for Multimedia +// +// zmoelnig@iem.kug.ac.at +// +// Implementation file +// +// Copyright (c) 1997-2000 Mark Danks. +// Copyright (c) Günther Geiger. +// Copyright (c) 2001-2002 IOhannes m zmoelnig. forum::für::umläute. IEM +// Copyright (c) 2002 James Tittle & Chris Clepper +// For information on usage and redistribution, and for a DISCLAIMER OF ALL +// WARRANTIES, see the file, "GEM.LICENSE.TERMS" in this distribution. +// +///////////////////////////////////////////////////////// +// based on code written by Lluis Gomez i Bigorda ( lluisgomez _at_ hangar _dot_ org ) (pix_opencv) +// FaceTracker for pix_opencv + +#ifdef HAVE_FACETRACKER +#include "pix_opencv_facetracker.h" + +using namespace FACETRACKER; + +CPPEXTERN_NEW(pix_opencv_facetracker) + +static std::vector consecutive(int start, int end) { + int n = end - start; + std::vector result(n); + for(int i = 0; i < n; i++) { + result[i] = start + i; + } + return result; +} + +std::vector pix_opencv_facetracker::getFeatureIndices(int feature) { + switch(feature) { + case LEFT_JAW: return consecutive(0, 9); + case RIGHT_JAW: return consecutive(8, 17); + case JAW: return consecutive(0, 17); + case LEFT_EYEBROW: return consecutive(17, 22); + case RIGHT_EYEBROW: return consecutive(22, 27); + case LEFT_EYE: return consecutive(36, 42); + case RIGHT_EYE: return consecutive(42, 48); + case OUTER_MOUTH: return consecutive(48, 60); + case INNER_MOUTH: { + static int innerMouth[] = {48,60,61,62,54,63,64,65}; + return std::vector(innerMouth, innerMouth + 8); + } + case NOSE_BRIDGE: return consecutive(27, 31); + case NOSE_BASE: return consecutive(31, 36); + case FACE_OUTLINE: { + static int faceOutline[] = {17,18,19,20,21,22,23,24,25,26, 16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1,0}; + return std::vector(faceOutline, faceOutline + 27); + } + case ALL_FEATURES: return consecutive(0, 66); + } +} + +///////////////////////////////////////////////////////// +// +// pix_opencv_facetracker +// +///////////////////////////////////////////////////////// +// Constructor +// +///////////////////////////////////////////////////////// +pix_opencv_facetracker :: pix_opencv_facetracker() : m_fcheck(false), \ + m_scale(1), \ + m_fpd(-1), \ + m_show(true), \ + m_nIter(5), \ + m_clamp(3), \ + m_fTol(0.01), \ + m_failed(true), \ + m_fps(-1), \ + m_t1(0), \ + m_t0(0), \ + m_taboutput(0), \ + m_autoresize(0) +{ + m_dataout = outlet_new(this->x_obj, 0); + + //set other tracking parameters + m_wSize1.push_back(7); + m_wSize2.push_back(11); m_wSize2.push_back(9); m_wSize2.push_back(7); + + for ( int i = 0; i<13 ; i++) m_arraysname[i]=NULL; + + t_canvas* canvas=canvas_getcurrent(); + char *basename=canvas_getdir(canvas)->s_name; + + m_tracker.Load((std::string(basename) + "/model/face2.tracker").c_str()); + m_tri = IO::LoadTri((std::string(basename) + "/model/face.tri").c_str()); + m_con = IO::LoadCon((std::string(basename) + "/model/face.con").c_str()); +} + +///////////////////////////////////////////////////////// +// Destructor +// +///////////////////////////////////////////////////////// +pix_opencv_facetracker :: ~pix_opencv_facetracker() +{ + +} + +void pix_opencv_facetracker :: OutputMesh(cv::Mat &image,cv::Mat &shape,cv::Mat &con,cv::Mat &tri,cv::Mat &visi) +{ + int n = shape.rows/2; + int vecsize(0); + t_garray *array; + t_word *vec; + + for ( int i = 0; i<13 ; i++ ){ + + std::vector indices = getFeatureIndices(i); + cv::Point pt; + + if ( m_arraysname[i] == NULL ){ + continue; + } + if (!(array = (t_garray *)pd_findbyclass(m_arraysname[i], garray_class))){ + error("%s: no such array", m_arraysname[i]->s_name); + continue; + } + + if (!garray_getfloatwords(array, &vecsize, &vec)){ + error("%s: bad template for tabwrite", m_arraysname[i]->s_name); + continue; + } + //~if ( indices.size()*3 != vecsize ){ + //~garray_resize_long(array,indices.size()*3); + //~if (!garray_getfloatwords(array, &vecsize, &vec)){ + //~error("%s: can't resize correctly", m_arraysname[i]->s_name); + //~continue; + //~} + //~} + + int idx(0); + + for( size_t j = 0 ; j < indices.size(); j++ ) + { + idx=3*j; + vec[idx].w_float = (float) shape.at(indices[j],0)/image.cols; + vec[idx+1].w_float = (float) shape.at(indices[j]+n,0)/image.rows; + vec[idx+2].w_float = 0.; + //~printf("update %s, indice %d : %.2f,%.2f,%.2f\n",m_arraysname[i]->s_name, idx, vec[idx].w_float, vec[idx+1].w_float, vec[idx+2].w_float); + } + + garray_redraw(array); + } +} + +void pix_opencv_facetracker :: Draw(cv::Mat &image,cv::Mat &shape,cv::Mat &con,cv::Mat &tri,cv::Mat &visi) +{ + int i,n = shape.rows/2; cv::Point p1,p2; cv::Scalar c; + + //draw triangulation + c = CV_RGB(0,0,0); + for(i = 0; i < tri.rows; i++){ + if(visi.at(tri.at(i,0),0) == 0 || + visi.at(tri.at(i,1),0) == 0 || + visi.at(tri.at(i,2),0) == 0)continue; + p1 = cv::Point(shape.at(tri.at(i,0),0), + shape.at(tri.at(i,0)+n,0)); + p2 = cv::Point(shape.at(tri.at(i,1),0), + shape.at(tri.at(i,1)+n,0)); + cv::line(image,p1,p2,c); + p1 = cv::Point(shape.at(tri.at(i,0),0), + shape.at(tri.at(i,0)+n,0)); + p2 = cv::Point(shape.at(tri.at(i,2),0), + shape.at(tri.at(i,2)+n,0)); + cv::line(image,p1,p2,c); + p1 = cv::Point(shape.at(tri.at(i,2),0), + shape.at(tri.at(i,2)+n,0)); + p2 = cv::Point(shape.at(tri.at(i,1),0), + shape.at(tri.at(i,1)+n,0)); + cv::line(image,p1,p2,c); + } + //draw connections + c = CV_RGB(0,0,255); + for(i = 0; i < con.cols; i++){ + if(visi.at(con.at(0,i),0) == 0 || + visi.at(con.at(1,i),0) == 0)continue; + p1 = cv::Point(shape.at(con.at(0,i),0), + shape.at(con.at(0,i)+n,0)); + p2 = cv::Point(shape.at(con.at(1,i),0), + shape.at(con.at(1,i)+n,0)); + cv::line(image,p1,p2,c,1); + } + //draw points + for(i = 0; i < n; i++){ + if(visi.at(i,0) == 0)continue; + p1 = cv::Point(shape.at(i,0),shape.at(i+n,0)); + c = CV_RGB(255,0,0); cv::circle(image,p1,2,c); + }return; +} + +///////////////////////////////////////////////////////// +// processImage +// +///////////////////////////////////////////////////////// + +void pix_opencv_facetracker :: processImage(imageStruct &image) +{ + cv::Mat gray, im; + if ( image.ysize < 1 || image.xsize < 1 ) return; + if ( image.csize == 1 ){ + gray = cv::Mat( image.ysize, image.xsize, CV_8UC1, image.data, image.csize*image.xsize); // just transform imageStruct to IplImage without copying data + im = gray; + } else if ( image.csize == 3 ) { + im = cv::Mat( image.ysize, image.xsize, CV_8UC3, image.data, image.csize*image.xsize); // just transform imageStruct to IplImage without copying data + cv::cvtColor(im,gray,CV_RGB2GRAY); + } else if ( image.csize == 4 ) { + im = cv::Mat( image.ysize, image.xsize, CV_8UC4, image.data, image.csize*image.xsize); // just transform imageStruct to IplImage without copying data + cv::cvtColor(im,gray,CV_RGBA2GRAY); + } else { + error("pix_opencv_facetracker : unsupported video format %d",image.csize); + return; + } + + //track this image + std::vector wSize; + if(m_failed)wSize = m_wSize2; + else wSize = m_wSize1; + + if(m_tracker.Track(gray,wSize,m_fpd,m_nIter,m_clamp,m_fTol,m_fcheck) == 0){ + int idx = m_tracker._clm.GetViewIdx(); m_failed = false; + OutputMesh(im,m_tracker._shape,m_con,m_tri,m_tracker._clm._visi[idx]); + if (m_show) Draw(im,m_tracker._shape,m_con,m_tri,m_tracker._clm._visi[idx]); + }else{ + m_tracker.FrameReset(); m_failed = true; + } + //draw framerate on display image + if(m_fnum >= 9){ + m_t1 = cvGetTickCount(); + m_fps = 10.0/((double(m_t1-m_t0)/cvGetTickFrequency())/1e+6); + m_t0 = m_t1; m_fnum = 0; + }else m_fnum += 1; + if(m_show){ + char text[256]; + sprintf(text,"%.2f frames/sec",(float)m_fps); + cv::putText(im,text,cv::Point(10,20), CV_FONT_HERSHEY_SIMPLEX,0.5,CV_RGB(255,255,255)); + } +} + +///////////////////////////////////////////////////////// +// static member function +// +///////////////////////////////////////////////////////// +void pix_opencv_facetracker :: obj_setupCallback(t_class *classPtr) +{ + CPPEXTERN_MSG0(classPtr, "reset", resetMess); + CPPEXTERN_MSG1(classPtr, "show", showMess, int); + CPPEXTERN_MSG2(classPtr, "settab", tableMess, t_symbol*, t_symbol*); + CPPEXTERN_MSG1(classPtr, "tolerance", toleranceMess, float); + CPPEXTERN_MSG1(classPtr, "clamp", clampMess, float); + CPPEXTERN_MSG1(classPtr, "filter", filterMess, float); +} + +void pix_opencv_facetracker :: resetMess(void){ + m_tracker.FrameReset(); +} + +void pix_opencv_facetracker :: showMess(int flag){ + m_show = flag>0; +} + +void pix_opencv_facetracker :: tableMess(t_symbol*featurename, t_symbol*arrayname) +{ + std::string name(featurename->s_name); + + int i=-1; + if ( name == "LEFT_EYEBROW" ) i = 0; + else if ( name == "RIGHT_EYEBROW" ) i = 1; + else if ( name == "LEFT_EYE" ) i = 2; + else if ( name == "RIGHT_EYE" ) i = 3; + else if ( name == "LEFT_JAW" ) i = 4; + else if ( name == "RIGHT_JAW" ) i = 5; + else if ( name == "JAW" ) i = 6; + else if ( name == "OUTER_MOUTH" ) i = 7; + else if ( name == "INNER_MOUTH" ) i = 8; + else if ( name == "NOSE_BRIDGE" ) i = 9; + else if ( name == "NOSE_BASE" ) i = 10; + else if ( name == "FACE_OUTLINE" ) i = 11; + else if ( name == "ALL_FEATURES" ) i = 12; + if ( i < 0 ) error("can't find feature %s",name.c_str()); + else { m_arraysname[i] = arrayname; m_taboutput = 1; } +} + +void pix_opencv_facetracker :: toleranceMess(float arg){ + m_fTol=arg; +} + +void pix_opencv_facetracker :: clampMess(float arg){ + m_clamp=arg; +} + +void pix_opencv_facetracker :: filterMess(float arg){ + m_nIter=int(arg); +} +#endif /* HAVE_FACETRACKER */ -- cgit v1.2.1