2016-02-03 13:20:08 +01:00
|
|
|
#include <iostream>
|
|
|
|
#include <memory>
|
|
|
|
#include <chrono>
|
|
|
|
#include <fstream>
|
|
|
|
|
2016-06-06 05:52:17 +02:00
|
|
|
#include <opencv2/highgui/highgui.hpp>
|
2016-02-03 13:20:08 +01:00
|
|
|
#include <opencv2/imgproc/imgproc.hpp>
|
|
|
|
#include <boost/filesystem.hpp>
|
|
|
|
#include <boost/timer/timer.hpp>
|
|
|
|
#include <boost/program_options.hpp>
|
|
|
|
|
|
|
|
#include "VideoDetector.h"
|
2016-04-05 17:25:50 +02:00
|
|
|
#include "PhotoDetector.h"
|
2016-02-03 13:20:08 +01:00
|
|
|
#include "AffdexException.h"
|
|
|
|
|
|
|
|
#include "AFaceListener.hpp"
|
|
|
|
#include "PlottingImageListener.hpp"
|
|
|
|
#include "StatusListener.hpp"
|
|
|
|
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace affdex;
|
|
|
|
|
|
|
|
int main(int argsc, char ** argsv)
|
|
|
|
{
|
2016-04-08 16:12:02 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-05 17:25:50 +02:00
|
|
|
std::map<boost::filesystem::path, bool> VIDEO_EXTS = { {boost::filesystem::path(".avi"), 1},
|
|
|
|
{boost::filesystem::path(".mov"), 1},
|
|
|
|
{boost::filesystem::path(".flv"), 1},
|
|
|
|
{boost::filesystem::path(".webm"), 1},
|
|
|
|
{boost::filesystem::path(".wmv"), 1},
|
|
|
|
{boost::filesystem::path(".mp4"), 1} };
|
2016-02-03 13:20:08 +01:00
|
|
|
affdex::path DATA_FOLDER;
|
|
|
|
affdex::path videoPath;
|
2016-09-13 19:23:03 +02:00
|
|
|
|
2016-02-03 13:20:08 +01:00
|
|
|
int process_framerate = 30;
|
|
|
|
bool draw_display = true;
|
|
|
|
bool loop = false;
|
|
|
|
unsigned int nFaces = 1;
|
2016-04-05 17:25:50 +02:00
|
|
|
int faceDetectorMode = (int)FaceDetectorMode::LARGE_FACES;
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-02-03 13:20:08 +01:00
|
|
|
const int precision = 2;
|
|
|
|
std::cerr.precision(precision);
|
|
|
|
std::cout.precision(precision);
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-02-03 13:20:08 +01:00
|
|
|
namespace po = boost::program_options; // abbreviate namespace
|
2016-04-08 16:12:02 +02:00
|
|
|
po::options_description description("Project for demoing the Affdex SDK VideoDetector class (processing video files).");
|
2016-02-03 13:20:08 +01:00
|
|
|
description.add_options()
|
|
|
|
("help,h", po::bool_switch()->default_value(false), "Display this help message.")
|
|
|
|
#ifdef _WIN32
|
|
|
|
("data,d", po::wvalue< affdex::path >(&DATA_FOLDER)->default_value(affdex::path(L"data"), std::string("data")), "Path to the data folder")
|
|
|
|
("input,i", po::wvalue< affdex::path >(&videoPath)->required(), "Video file to processs")
|
|
|
|
#else // _WIN32
|
|
|
|
("data,d", po::value< affdex::path >(&DATA_FOLDER)->default_value(affdex::path("data"), std::string("data")), "Path to the data folder")
|
|
|
|
("input,i", po::value< affdex::path >(&videoPath)->required(), "Video file to processs")
|
|
|
|
#endif // _WIN32
|
|
|
|
("pfps", po::value< int >(&process_framerate)->default_value(30), "Processing framerate.")
|
|
|
|
("draw", po::value< bool >(&draw_display)->default_value(true), "Draw video on screen.")
|
|
|
|
("faceMode", po::value< int >(&faceDetectorMode)->default_value((int)FaceDetectorMode::SMALL_FACES), "Face detector mode (large faces vs small faces).")
|
|
|
|
("numFaces", po::value< unsigned int >(&nFaces)->default_value(1), "Number of faces to be tracked.")
|
|
|
|
("loop", po::value< bool >(&loop)->default_value(false), "Loop over the video being processed.")
|
|
|
|
;
|
|
|
|
po::variables_map args;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
po::store(po::command_line_parser(argsc, argsv).options(description).run(), args);
|
|
|
|
if (args["help"].as<bool>())
|
|
|
|
{
|
|
|
|
std::cout << description << std::endl;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
po::notify(args);
|
|
|
|
}
|
|
|
|
catch (po::error& e)
|
|
|
|
{
|
|
|
|
std::cerr << "ERROR: " << e.what() << std::endl << std::endl;
|
|
|
|
std::cerr << "For help, use the -h option." << std::endl << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-02-03 13:20:08 +01:00
|
|
|
// Parse and check the data folder (with assets)
|
|
|
|
if (!boost::filesystem::exists(DATA_FOLDER))
|
|
|
|
{
|
|
|
|
std::cerr << "Data folder doesn't exist: " << std::string(DATA_FOLDER.begin(), DATA_FOLDER.end()) << std::endl;
|
|
|
|
std::cerr << "Try specifying the folder through the command line" << std::endl;
|
|
|
|
std::cerr << description << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
try
|
|
|
|
{
|
2016-04-05 17:25:50 +02:00
|
|
|
std::shared_ptr<Detector> detector;
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-02-03 13:20:08 +01:00
|
|
|
//Initialize out file
|
|
|
|
boost::filesystem::path csvPath(videoPath);
|
2016-04-05 17:25:50 +02:00
|
|
|
boost::filesystem::path fileExt = csvPath.extension();
|
2016-02-03 13:20:08 +01:00
|
|
|
csvPath.replace_extension(".csv");
|
|
|
|
std::ofstream csvFileStream(csvPath.c_str());
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-02-03 13:20:08 +01:00
|
|
|
if (!csvFileStream.is_open())
|
|
|
|
{
|
|
|
|
std::cerr << "Unable to open csv file " << csvPath << std::endl;
|
|
|
|
return 1;
|
|
|
|
}
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-04-05 17:25:50 +02:00
|
|
|
if (VIDEO_EXTS[fileExt]) // IF it is a video file.
|
|
|
|
{
|
|
|
|
detector = std::make_shared<VideoDetector>(process_framerate, nFaces, (affdex::FaceDetectorMode) faceDetectorMode);
|
|
|
|
}
|
|
|
|
else //Otherwise it's a photo
|
|
|
|
{
|
|
|
|
detector = std::make_shared<PhotoDetector>(nFaces, (affdex::FaceDetectorMode) faceDetectorMode);
|
|
|
|
}
|
2016-04-08 16:12:02 +02:00
|
|
|
|
|
|
|
|
2016-04-05 17:25:50 +02:00
|
|
|
//VideoDetector videoDetector(process_framerate, nFaces, (affdex::FaceDetectorMode) faceDetectorMode);
|
2016-04-08 16:12:02 +02:00
|
|
|
|
|
|
|
|
|
|
|
|
2016-04-05 17:25:50 +02:00
|
|
|
std::cout << "Max num of faces set to: " << detector->getMaxNumberFaces() << std::endl;
|
2016-02-03 13:20:08 +01:00
|
|
|
std::string mode;
|
2016-04-05 17:25:50 +02:00
|
|
|
switch (detector->getFaceDetectorMode())
|
2016-02-03 13:20:08 +01:00
|
|
|
{
|
|
|
|
case FaceDetectorMode::LARGE_FACES:
|
|
|
|
mode = "LARGE_FACES";
|
|
|
|
break;
|
|
|
|
case FaceDetectorMode::SMALL_FACES:
|
|
|
|
mode = "SMALL_FACES";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-02-03 13:20:08 +01:00
|
|
|
std::cout << "Face detector mode set to: " << mode << std::endl;
|
|
|
|
shared_ptr<PlottingImageListener> listenPtr(new PlottingImageListener(csvFileStream, draw_display));
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-04-05 17:25:50 +02:00
|
|
|
detector->setDetectAllEmotions(true);
|
|
|
|
detector->setDetectAllExpressions(true);
|
|
|
|
detector->setDetectAllEmojis(true);
|
2016-07-14 21:50:07 +02:00
|
|
|
detector->setDetectAllAppearances(true);
|
2016-04-05 17:25:50 +02:00
|
|
|
detector->setClassifierPath(DATA_FOLDER);
|
|
|
|
detector->setImageListener(listenPtr.get());
|
2016-04-08 16:12:02 +02:00
|
|
|
|
|
|
|
|
2016-04-05 17:25:50 +02:00
|
|
|
detector->start(); //Initialize the detectors .. call only once
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-02-03 13:20:08 +01:00
|
|
|
do
|
|
|
|
{
|
|
|
|
shared_ptr<StatusListener> videoListenPtr = std::make_shared<StatusListener>();
|
2016-04-05 17:25:50 +02:00
|
|
|
detector->setProcessStatusListener(videoListenPtr.get());
|
|
|
|
if (VIDEO_EXTS[fileExt])
|
|
|
|
{
|
|
|
|
((VideoDetector *)detector.get())->process(videoPath); //Process a video
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
//videoPath is of type std::wstring on windows, but std::string on other platforms.
|
|
|
|
cv::Mat img = cv::imread(std::string(videoPath.begin(), videoPath.end()));
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-04-05 17:25:50 +02:00
|
|
|
// Create a frame
|
|
|
|
Frame frame(img.size().width, img.size().height, img.data, Frame::COLOR_FORMAT::BGR);
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-04-05 17:25:50 +02:00
|
|
|
((PhotoDetector *)detector.get())->process(frame); //Process an image
|
|
|
|
}
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-04-05 20:30:11 +02:00
|
|
|
do
|
2016-02-03 13:20:08 +01:00
|
|
|
{
|
|
|
|
if (listenPtr->getDataSize() > 0)
|
|
|
|
{
|
|
|
|
std::pair<Frame, std::map<FaceId, Face> > dataPoint = listenPtr->getData();
|
|
|
|
Frame frame = dataPoint.first;
|
|
|
|
std::map<FaceId, Face> faces = dataPoint.second;
|
2016-04-08 16:12:02 +02:00
|
|
|
|
|
|
|
|
2016-02-03 13:20:08 +01:00
|
|
|
if (draw_display)
|
|
|
|
{
|
|
|
|
listenPtr->draw(faces, frame);
|
|
|
|
}
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-02-03 13:20:08 +01:00
|
|
|
std::cerr << "timestamp: " << frame.getTimestamp()
|
|
|
|
<< " cfps: " << listenPtr->getCaptureFrameRate()
|
|
|
|
<< " pfps: " << listenPtr->getProcessingFrameRate()
|
|
|
|
<< " faces: "<< faces.size() << endl;
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-02-03 13:20:08 +01:00
|
|
|
listenPtr->outputToFile(faces, frame.getTimestamp());
|
|
|
|
}
|
2016-06-22 23:25:38 +02:00
|
|
|
} while (VIDEO_EXTS[fileExt] && (videoListenPtr->isRunning() || listenPtr->getDataSize() > 0));
|
2016-02-03 13:20:08 +01:00
|
|
|
} while(loop);
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-04-05 17:25:50 +02:00
|
|
|
detector->stop();
|
2016-02-03 13:20:08 +01:00
|
|
|
csvFileStream.close();
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-02-03 13:20:08 +01:00
|
|
|
std::cout << "Output written to file: " << csvPath << std::endl;
|
|
|
|
}
|
|
|
|
catch (AffdexException ex)
|
|
|
|
{
|
|
|
|
std::cerr << ex.what();
|
|
|
|
}
|
2016-04-08 16:12:02 +02:00
|
|
|
|
2016-02-03 13:20:08 +01:00
|
|
|
return 0;
|
|
|
|
}
|