/* * main.cpp * * Copyright (c) 2006 Machine Perception Laboratory * University of California San Diego. * * Authors: Andrew Salamon, Josh Susskind * * Please read the disclaimer and notes about redistribution * at the end of this file. * */ #include // for cout and cerr #include #include // For system independent path support #include #include "boost/filesystem/operations.hpp" namespace bf = boost::filesystem; #include "ImageDirIterator.h" //#define USE_IMAGEMAGICK #ifdef USE_IMAGEMAGICK #include #endif #ifdef WIN32 #ifndef WINVER #define WINVER 0x0502 #endif #include "afxwin.h" #endif #include "rimage.h" #include "rimage_ser.h" #include "mp_CERT.h" #ifdef USE_MLR #include "mp_MLR.h" mp_MLR *setupMLR(); #endif void printResults( std::vector &results, bool tabDelim ) { std::cout.precision(8); for( unsigned int i=0; i < results.size(); ++i ) { std::cout << results[i]; if( i < (results.size() - 1) ) { if( tabDelim ) std::cout << '\t'; else std::cout << ", "; } } if( !tabDelim ) std::cout << std::endl; } std::string getsvmweightspath(); std::string getimagepath(); bool loadRImage(RImage &pixels, const std::string &path, int argc); bool processImage( MP_CERT &cert, RImage &pixels, const std::string &path, int argc, bool tabDelim ); void processDir( MP_CERT &cert, RImage &pixels, const std::string &path, int argc ); bool doEmotions = false; // if this is set to true, emotion weights initialization code in MP_CERT also needs to be uncommented. bool inputIsFaces = false; // if this is set to true, faces have have already been found and cropped #ifdef USE_MLR mp_MLR *mlr = NULL; #endif int main (int argc, char *argv[]) { MP_CERT cert(getsvmweightspath()); #ifdef USE_MLR mlr = setupMLR(); #endif #ifdef USE_FEATURES cert.setUseFeatures( true ); #endif unsigned int pathIndex = 1; if( argc > 1 ) { std::string arg1( argv[pathIndex] ); if( "-f" == arg1) { ++pathIndex; inputIsFaces = true; } } std::cout << "Finished loading data files" << std::endl; RImage pixels; cert.setDoEmotions( doEmotions ); do { std::string path; if( pathIndex < argc ) path = argv[pathIndex++]; else path = getimagepath(); if( "quit" == path ) break; bf::path bfPath( path, bf::native ); if( bf::exists( bfPath ) && bf::is_directory( bfPath ) ) processDir( cert, pixels, path, argc ); else processImage( cert, pixels, path, argc, false ); } while( true ); #ifdef USE_MLR delete mlr; #endif } bool processImage( MP_CERT &cert, RImage &pixels, const std::string &path, int argc, bool tabDelim ) { if( loadRImage(pixels, path, argc) ) // handles loading an image from file into an RImage { std::vector aus; if( inputIsFaces ) aus = cert.calcAUsFromFace( pixels ); else aus = cert.calcAUs( pixels ); if( !tabDelim ) std::cout << "AU vector:" << std::endl; printResults( aus, tabDelim ); if( doEmotions ) { std::vector emotions = cert.getEmotions(); if( !tabDelim ) std::cout << std::endl << "Emotion Detectors: " << std::endl; printResults( emotions, tabDelim ); } #ifdef USE_MLR std::map< std::string, mp_AUResults > freqs = cert.getFrequencies(); double res = mlr->MLR( freqs ); if( !tabDelim ) std::cout << std::endl << "MLR 1+2+4: " << res << std::endl; else std::cout << '\t' << res; #endif return true; } return false; } /*************************************************************/ std::string getsvmweightspath() { std::string defaultpath = "../../mp_auCoder/SVMWeights"; #ifndef WIN32 defaultpath = "SVMWeights"; #endif // std::string path = ""; // std::cout << "Enter path to svmweights directory [" << defaultpath << "]: "; // std::cin >> path; // if ( path == "" ) path = defaultpath; std::cout << "Loading data files... " << std::endl; return(defaultpath); } /*************************************************************/ std::string getimagepath() { std::string path; std::cout << "Enter path to image"; #ifdef WIN32 #ifndef USE_IMAGEMAGICK std::cout << " (Windows demo only accepts 24 bit bitmaps)"; #endif #endif std::cout << " or ctrl-c to exit" << std::endl; std::cout << "--> "; std::cin >> path; if( std::cin.eof() ) path = "quit"; return(path); } /*************************************************************/ bool loadRImage(RImage &pixels, const std::string &path, int argc) { #ifdef USE_IMAGEMAGICK // Before trying to read the image we need to make sure the path is valid, // otherwise ImageMagick terminates the program. Magick::Image image; try { image.read( path.c_str() ); /* Or we could create an image from in memory data (e.g. video frame capture) Magick::Blob blob( inMemoryImageDataPtr, inMemoryImageDataLength ); Magick::Image image( blob ); */ if (image.columns() == 0 && image.rows() == 0) { std::cerr << "Image contains 0 rows and 0 columns! Exiting..." << std::endl; return false; } image.quantizeColors(256); // convert to 256 colors image.quantize(); // convert to grayscale pixels.setSize( image.columns(), image.rows() ); image.write( 0, 0, image.columns(), image.rows(), "I", Magick::FloatPixel, pixels.array ); return true; } catch( Magick::ErrorBlob &error ) { std::cerr << "Caught ImageMagick IO exception: " << error.what() << std::endl; return false; } catch( Magick::Exception &error ) { std::cerr << "Caught ImageMagick exception: " << error.what() << std::endl; return false; } catch( std::exception &error ) { std::cerr << "Caught standard exception: " << error.what() << std::endl; return false; } #elif WIN32 // Load bitmap HBITMAP hBitmap = (HBITMAP) LoadImage(NULL, path.c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); if (hBitmap) { CBitmap bmpBitmap; // Create a CBitmap bmpBitmap.Attach(hBitmap); BITMAP bm; // Get the Bitmap bmpBitmap.GetBitmap(&bm); if(bm.bmBitsPixel==24) // if it's 24 bits ... { // a bit tricky ... // align within 32 bits int align = (4-((bm.bmWidth)%4)) & 3; int nbr_byte = bm.bmHeight * bm.bmWidth + align * bm.bmHeight/3; BYTE* pBits= (BYTE*) bm.bmBits + (bm.bmHeight-1)*(3*bm.bmWidth+align); pixels.setSize(bm.bmWidth, bm.bmHeight); // read bitmap pixels, convert to grayscale, and copy into RImage for analysis for (int l=0;l> 10; pixels.setPixel( c, l, theGrayValue/255.0f ); // copy to RImage pBits=pBits+3; } pBits=pBits-align-2*3*bm.bmWidth; } return true; } else { std::cerr << "Unable to process bitmap. This demo only works with 24 bit bitmaps!" << std::endl; return false; } } else { if( !restoreRImageFromFile( pixels, path ) ) { std::cerr << "Unable to read RImage file. Exiting..." << std::endl; return false; } else { return true; } } #else if( !restoreRImageFromFile( pixels, path ) ) { std::cerr << "Unable to read RImage file. Exiting..." << std::endl; return false; } return true; #endif } void processDir( MP_CERT &cert, RImage &pixels, const std::string &path, int argc ) { ImageDirIterator images( path ); while( ++images ) { std::string fileName = *images; std::cout << fileName << '\t'; processImage( cert, pixels, fileName, argc, true ); std::cout << std::endl; } } #ifdef USE_MLR mp_MLR *setupMLR() { std::string weightsPath("../MLR/BHAT_1_2_4.xml"); inputAUVector inputs; // These input values are listed in ../MLR/bhat_requirements.txt inputs.push_back( std::pair( "CERT3_Weights", 0 ) ); inputs.push_back( std::pair( "CERT3_Weights", 1 ) ); inputs.push_back( std::pair( "CERT3_Weights", 2 ) ); inputs.push_back( std::pair( "CERT3_Weights", 8 ) ); mp_MLR *mlr = new mp_MLR( weightsPath, inputs ); return mlr; } #endif /* * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * 3. The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */