2017-11-08 19:38:37 +00:00
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
// Copyright (C) 2017, Tadas Baltrusaitis, all rights reserved.
|
|
|
|
|
//
|
|
|
|
|
// ACADEMIC OR NON-PROFIT ORGANIZATION NONCOMMERCIAL RESEARCH USE ONLY
|
|
|
|
|
//
|
|
|
|
|
// BY USING OR DOWNLOADING THE SOFTWARE, YOU ARE AGREEING TO THE TERMS OF THIS LICENSE AGREEMENT.
|
|
|
|
|
// IF YOU DO NOT AGREE WITH THESE TERMS, YOU MAY NOT USE OR DOWNLOAD THE SOFTWARE.
|
|
|
|
|
//
|
|
|
|
|
// License can be found in OpenFace-license.txt
|
|
|
|
|
//
|
|
|
|
|
// * Any publications arising from the use of this software, including but
|
|
|
|
|
// not limited to academic journal and conference publications, technical
|
|
|
|
|
// reports and manuals, must cite at least one of the following works:
|
|
|
|
|
//
|
|
|
|
|
// OpenFace: an open source facial behavior analysis toolkit
|
|
|
|
|
// Tadas Baltru<72>aitis, Peter Robinson, and Louis-Philippe Morency
|
|
|
|
|
// in IEEE Winter Conference on Applications of Computer Vision, 2016
|
|
|
|
|
//
|
|
|
|
|
// Rendering of Eyes for Eye-Shape Registration and Gaze Estimation
|
|
|
|
|
// Erroll Wood, Tadas Baltru<72>aitis, Xucong Zhang, Yusuke Sugano, Peter Robinson, and Andreas Bulling
|
|
|
|
|
// in IEEE International. Conference on Computer Vision (ICCV), 2015
|
|
|
|
|
//
|
|
|
|
|
// Cross-dataset learning and person-speci?c normalisation for automatic Action Unit detection
|
|
|
|
|
// Tadas Baltru<72>aitis, Marwa Mahmoud, and Peter Robinson
|
|
|
|
|
// in Facial Expression Recognition and Analysis Challenge,
|
|
|
|
|
// IEEE International Conference on Automatic Face and Gesture Recognition, 2015
|
|
|
|
|
//
|
|
|
|
|
// Constrained Local Neural Fields for robust facial landmark detection in the wild.
|
|
|
|
|
// Tadas Baltru<72>aitis, Peter Robinson, and Louis-Philippe Morency.
|
|
|
|
|
// in IEEE Int. Conference on Computer Vision Workshops, 300 Faces in-the-Wild Challenge, 2013.
|
|
|
|
|
//
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
#include "SequenceCapture.h"
|
2017-12-15 19:56:58 +00:00
|
|
|
|
#include "ImageManipulationHelpers.h"
|
2017-11-08 19:38:37 +00:00
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
|
|
// Boost includes
|
|
|
|
|
#include <filesystem.hpp>
|
|
|
|
|
#include <filesystem/fstream.hpp>
|
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
|
|
2017-11-08 21:13:02 +00:00
|
|
|
|
// OpenCV includes
|
|
|
|
|
#include <opencv2/imgproc.hpp>
|
|
|
|
|
|
2017-12-17 12:59:55 +00:00
|
|
|
|
// For timing
|
|
|
|
|
#include <chrono>
|
|
|
|
|
#include <ctime>
|
|
|
|
|
|
2017-11-08 19:38:37 +00:00
|
|
|
|
using namespace Utilities;
|
|
|
|
|
|
2017-11-09 18:25:49 +00:00
|
|
|
|
#define INFO_STREAM( stream ) \
|
|
|
|
|
std::cout << stream << std::endl
|
|
|
|
|
|
|
|
|
|
#define WARN_STREAM( stream ) \
|
|
|
|
|
std::cout << "Warning: " << stream << std::endl
|
|
|
|
|
|
|
|
|
|
#define ERROR_STREAM( stream ) \
|
|
|
|
|
std::cout << "Error: " << stream << std::endl
|
|
|
|
|
|
2017-11-10 20:40:59 +00:00
|
|
|
|
bool SequenceCapture::Open(std::vector<std::string>& arguments)
|
2017-11-08 19:38:37 +00:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
// Consuming the input arguments
|
|
|
|
|
bool* valid = new bool[arguments.size()];
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < arguments.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
valid[i] = true;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-09 20:43:53 +00:00
|
|
|
|
// Some default values
|
2017-11-08 19:38:37 +00:00
|
|
|
|
std::string input_root = "";
|
2017-11-09 20:43:53 +00:00
|
|
|
|
fx = -1; fy = -1; cx = -1; cy = -1;
|
|
|
|
|
frame_num = 0;
|
2017-11-09 21:04:25 +00:00
|
|
|
|
time_stamp = 0;
|
2017-11-08 19:38:37 +00:00
|
|
|
|
|
|
|
|
|
std::string separator = std::string(1, boost::filesystem::path::preferred_separator);
|
|
|
|
|
|
|
|
|
|
// First check if there is a root argument (so that videos and input directories could be defined more easily)
|
|
|
|
|
for (size_t i = 0; i < arguments.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if (arguments[i].compare("-root") == 0)
|
|
|
|
|
{
|
|
|
|
|
input_root = arguments[i + 1] + separator;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
if (arguments[i].compare("-inroot") == 0)
|
|
|
|
|
{
|
|
|
|
|
input_root = arguments[i + 1] + separator;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string input_video_file;
|
|
|
|
|
std::string input_sequence_directory;
|
|
|
|
|
int device = -1;
|
|
|
|
|
|
|
|
|
|
bool file_found = false;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < arguments.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
if (!file_found && arguments[i].compare("-f") == 0)
|
|
|
|
|
{
|
|
|
|
|
input_video_file = (input_root + arguments[i + 1]);
|
|
|
|
|
valid[i] = false;
|
|
|
|
|
valid[i + 1] = false;
|
|
|
|
|
i++;
|
|
|
|
|
file_found = true;
|
|
|
|
|
}
|
|
|
|
|
else if (!file_found && arguments[i].compare("-fdir") == 0)
|
|
|
|
|
{
|
|
|
|
|
input_sequence_directory = (input_root + arguments[i + 1]);
|
|
|
|
|
valid[i] = false;
|
|
|
|
|
valid[i + 1] = false;
|
|
|
|
|
i++;
|
|
|
|
|
file_found = true;
|
|
|
|
|
}
|
|
|
|
|
else if (arguments[i].compare("-fx") == 0)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream data(arguments[i + 1]);
|
|
|
|
|
data >> fx;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
else if (arguments[i].compare("-fy") == 0)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream data(arguments[i + 1]);
|
|
|
|
|
data >> fy;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
else if (arguments[i].compare("-cx") == 0)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream data(arguments[i + 1]);
|
|
|
|
|
data >> cx;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
else if (arguments[i].compare("-cy") == 0)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream data(arguments[i + 1]);
|
|
|
|
|
data >> cy;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
else if (arguments[i].compare("-device") == 0)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream data(arguments[i + 1]);
|
|
|
|
|
data >> device;
|
|
|
|
|
valid[i] = false;
|
|
|
|
|
valid[i + 1] = false;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-09 20:43:53 +00:00
|
|
|
|
for (int i = (int)arguments.size() - 1; i >= 0; --i)
|
2017-11-08 19:38:37 +00:00
|
|
|
|
{
|
|
|
|
|
if (!valid[i])
|
|
|
|
|
{
|
|
|
|
|
arguments.erase(arguments.begin() + i);
|
|
|
|
|
}
|
2017-11-09 21:04:25 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-11-10 18:49:30 +00:00
|
|
|
|
no_input_specified = !file_found;
|
|
|
|
|
|
2017-12-12 08:55:23 +00:00
|
|
|
|
// Based on what was read in open the sequence
|
2017-11-08 20:08:17 +00:00
|
|
|
|
if (device != -1)
|
|
|
|
|
{
|
2017-12-12 08:55:23 +00:00
|
|
|
|
// TODO allow to specify webcam resolution
|
2017-11-08 20:08:17 +00:00
|
|
|
|
return OpenWebcam(device, 640, 480, fx, fy, cx, cy);
|
|
|
|
|
}
|
|
|
|
|
if (!input_video_file.empty())
|
|
|
|
|
{
|
|
|
|
|
return OpenVideoFile(input_video_file, fx, fy, cx, cy);
|
|
|
|
|
}
|
|
|
|
|
if (!input_sequence_directory.empty())
|
|
|
|
|
{
|
|
|
|
|
return OpenImageSequence(input_sequence_directory, fx, fy, cx, cy);
|
|
|
|
|
}
|
2017-11-10 18:49:30 +00:00
|
|
|
|
|
|
|
|
|
// If no input found return false and set a flag for it
|
|
|
|
|
no_input_specified = true;
|
|
|
|
|
|
2017-11-09 18:25:49 +00:00
|
|
|
|
return false;
|
2017-11-08 19:38:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-12-04 11:48:44 +00:00
|
|
|
|
// Get current date/time, format is YYYY-MM-DD.HH:mm, useful for saving data from webcam
|
2017-12-17 12:59:55 +00:00
|
|
|
|
const std::string currentDateTime()
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
time_t rawtime;
|
|
|
|
|
struct tm * timeinfo;
|
|
|
|
|
char buffer[80];
|
|
|
|
|
|
|
|
|
|
time(&rawtime);
|
|
|
|
|
timeinfo = localtime(&rawtime);
|
|
|
|
|
|
|
|
|
|
strftime(buffer, sizeof(buffer), "%Y-%m-%d-%H-%M", timeinfo);
|
|
|
|
|
|
|
|
|
|
return buffer;
|
2017-12-04 11:48:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2017-11-08 19:38:37 +00:00
|
|
|
|
bool SequenceCapture::OpenWebcam(int device, int image_width, int image_height, float fx, float fy, float cx, float cy)
|
|
|
|
|
{
|
2017-11-09 18:25:49 +00:00
|
|
|
|
INFO_STREAM("Attempting to read from webcam: " << device);
|
2017-11-08 19:38:37 +00:00
|
|
|
|
|
2017-11-10 18:49:30 +00:00
|
|
|
|
no_input_specified = false;
|
|
|
|
|
|
2017-11-08 19:38:37 +00:00
|
|
|
|
if (device < 0)
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Specify a valid device" << std::endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
latest_frame = cv::Mat();
|
|
|
|
|
latest_gray_frame = cv::Mat();
|
|
|
|
|
|
|
|
|
|
capture.open(device);
|
|
|
|
|
capture.set(CV_CAP_PROP_FRAME_WIDTH, image_width);
|
|
|
|
|
capture.set(CV_CAP_PROP_FRAME_HEIGHT, image_height);
|
|
|
|
|
|
|
|
|
|
is_webcam = true;
|
|
|
|
|
is_image_seq = false;
|
|
|
|
|
|
|
|
|
|
vid_length = 0;
|
|
|
|
|
|
2017-11-09 19:56:16 +00:00
|
|
|
|
this->frame_width = (int)capture.get(CV_CAP_PROP_FRAME_WIDTH);
|
|
|
|
|
this->frame_height = (int)capture.get(CV_CAP_PROP_FRAME_HEIGHT);
|
2017-11-08 19:38:37 +00:00
|
|
|
|
|
|
|
|
|
if (!capture.isOpened())
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Failed to open the webcam" << std::endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (frame_width != image_width || frame_height != image_height)
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Failed to open the webcam with desired resolution" << std::endl;
|
|
|
|
|
std::cout << "Defaulting to " << frame_width << "x" << frame_height << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->fps = capture.get(CV_CAP_PROP_FPS);
|
|
|
|
|
|
2017-11-08 21:35:27 +00:00
|
|
|
|
// Check if fps is nan or less than 0
|
|
|
|
|
if (fps != fps || fps <= 0)
|
|
|
|
|
{
|
2017-11-10 19:01:43 +00:00
|
|
|
|
INFO_STREAM("FPS of the webcam cannot be determined, assuming 30");
|
2017-11-08 21:35:27 +00:00
|
|
|
|
fps = 30;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-09 20:43:53 +00:00
|
|
|
|
SetCameraIntrinsics(fx, fy, cx, cy);
|
2017-12-04 11:48:44 +00:00
|
|
|
|
std::string time = currentDateTime();
|
|
|
|
|
this->name = "webcam_" + time;
|
2017-11-08 20:50:46 +00:00
|
|
|
|
|
2017-11-09 19:56:16 +00:00
|
|
|
|
start_time = cv::getTickCount();
|
2017-11-09 18:25:49 +00:00
|
|
|
|
|
2017-11-08 19:38:37 +00:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-15 19:56:58 +00:00
|
|
|
|
// Destructor that releases the capture
|
|
|
|
|
SequenceCapture::~SequenceCapture()
|
|
|
|
|
{
|
|
|
|
|
if (capture.isOpened())
|
|
|
|
|
capture.release();
|
|
|
|
|
}
|
2017-11-08 19:38:37 +00:00
|
|
|
|
|
|
|
|
|
bool SequenceCapture::OpenVideoFile(std::string video_file, float fx, float fy, float cx, float cy)
|
|
|
|
|
{
|
2017-11-09 18:25:49 +00:00
|
|
|
|
INFO_STREAM("Attempting to read from file: " << video_file);
|
|
|
|
|
|
2017-11-10 18:49:30 +00:00
|
|
|
|
no_input_specified = false;
|
|
|
|
|
|
2017-11-08 19:38:37 +00:00
|
|
|
|
latest_frame = cv::Mat();
|
|
|
|
|
latest_gray_frame = cv::Mat();
|
|
|
|
|
|
|
|
|
|
capture.open(video_file);
|
|
|
|
|
|
2017-11-13 09:07:52 +00:00
|
|
|
|
if (!capture.isOpened())
|
|
|
|
|
{
|
|
|
|
|
std::cout << "Failed to open the video file at location: " << video_file << std::endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-08 19:38:37 +00:00
|
|
|
|
this->fps = capture.get(CV_CAP_PROP_FPS);
|
|
|
|
|
|
2017-11-08 21:35:27 +00:00
|
|
|
|
// Check if fps is nan or less than 0
|
|
|
|
|
if (fps != fps || fps <= 0)
|
|
|
|
|
{
|
2017-11-09 18:25:49 +00:00
|
|
|
|
WARN_STREAM("FPS of the video file cannot be determined, assuming 30");
|
2017-11-08 21:35:27 +00:00
|
|
|
|
fps = 30;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-08 19:38:37 +00:00
|
|
|
|
is_webcam = false;
|
|
|
|
|
is_image_seq = false;
|
|
|
|
|
|
2017-11-09 19:56:16 +00:00
|
|
|
|
this->frame_width = (int)capture.get(CV_CAP_PROP_FRAME_WIDTH);
|
|
|
|
|
this->frame_height = (int)capture.get(CV_CAP_PROP_FRAME_HEIGHT);
|
2017-11-08 19:38:37 +00:00
|
|
|
|
|
2017-11-09 19:56:16 +00:00
|
|
|
|
vid_length = (int)capture.get(CV_CAP_PROP_FRAME_COUNT);
|
2017-11-08 19:38:37 +00:00
|
|
|
|
|
2017-11-09 20:43:53 +00:00
|
|
|
|
SetCameraIntrinsics(fx, fy, cx, cy);
|
2017-11-08 19:38:37 +00:00
|
|
|
|
|
2017-12-12 08:55:23 +00:00
|
|
|
|
this->name = video_file;
|
2017-11-09 18:25:49 +00:00
|
|
|
|
|
2017-11-08 19:38:37 +00:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-08 20:50:46 +00:00
|
|
|
|
bool SequenceCapture::OpenImageSequence(std::string directory, float fx, float fy, float cx, float cy)
|
2017-11-08 19:38:37 +00:00
|
|
|
|
{
|
2017-11-09 18:25:49 +00:00
|
|
|
|
INFO_STREAM("Attempting to read from directory: " << directory);
|
|
|
|
|
|
2017-11-10 18:49:30 +00:00
|
|
|
|
no_input_specified = false;
|
|
|
|
|
|
2017-11-08 19:38:37 +00:00
|
|
|
|
image_files.clear();
|
|
|
|
|
|
|
|
|
|
boost::filesystem::path image_directory(directory);
|
|
|
|
|
std::vector<boost::filesystem::path> file_in_directory;
|
|
|
|
|
copy(boost::filesystem::directory_iterator(image_directory), boost::filesystem::directory_iterator(), back_inserter(file_in_directory));
|
|
|
|
|
|
|
|
|
|
// Sort the images in the directory first
|
|
|
|
|
sort(file_in_directory.begin(), file_in_directory.end());
|
|
|
|
|
|
|
|
|
|
std::vector<std::string> curr_dir_files;
|
|
|
|
|
|
|
|
|
|
for (std::vector<boost::filesystem::path>::const_iterator file_iterator(file_in_directory.begin()); file_iterator != file_in_directory.end(); ++file_iterator)
|
|
|
|
|
{
|
|
|
|
|
// Possible image extension .jpg and .png
|
2017-11-08 21:13:02 +00:00
|
|
|
|
if (file_iterator->extension().string().compare(".jpg") == 0 || file_iterator->extension().string().compare(".jpeg") == 0 || file_iterator->extension().string().compare(".png") == 0 || file_iterator->extension().string().compare(".bmp") == 0)
|
2017-11-08 19:38:37 +00:00
|
|
|
|
{
|
|
|
|
|
curr_dir_files.push_back(file_iterator->string());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
image_files = curr_dir_files;
|
|
|
|
|
|
|
|
|
|
if (image_files.empty())
|
|
|
|
|
{
|
|
|
|
|
std::cout << "No images found in the directory: " << directory << std::endl;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-08 20:50:46 +00:00
|
|
|
|
// Assume all images are same size in an image sequence
|
2017-12-15 19:56:58 +00:00
|
|
|
|
cv::Mat tmp = cv::imread(image_files[0], CV_LOAD_IMAGE_COLOR);
|
2017-11-08 20:50:46 +00:00
|
|
|
|
this->frame_height = tmp.size().height;
|
|
|
|
|
this->frame_width = tmp.size().width;
|
|
|
|
|
|
2017-11-09 20:43:53 +00:00
|
|
|
|
SetCameraIntrinsics(fx, fy, cx, cy);
|
2017-11-08 20:50:46 +00:00
|
|
|
|
|
|
|
|
|
// No fps as we have a sequence
|
|
|
|
|
this->fps = 0;
|
|
|
|
|
|
2017-12-12 08:55:23 +00:00
|
|
|
|
this->name = directory;
|
2017-11-09 18:25:49 +00:00
|
|
|
|
|
2017-11-09 20:43:53 +00:00
|
|
|
|
is_webcam = false;
|
|
|
|
|
is_image_seq = true;
|
|
|
|
|
vid_length = image_files.size();
|
|
|
|
|
|
2017-11-08 19:38:37 +00:00
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
}
|
2017-11-08 20:50:46 +00:00
|
|
|
|
|
2017-11-09 20:43:53 +00:00
|
|
|
|
void SequenceCapture::SetCameraIntrinsics(float fx, float fy, float cx, float cy)
|
|
|
|
|
{
|
|
|
|
|
// If optical centers are not defined just use center of image
|
|
|
|
|
if (cx == -1)
|
|
|
|
|
{
|
|
|
|
|
this->cx = this->frame_width / 2.0f;
|
|
|
|
|
this->cy = this->frame_height / 2.0f;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
this->cx = cx;
|
|
|
|
|
this->cy = cy;
|
|
|
|
|
}
|
|
|
|
|
// Use a rough guess-timate of focal length
|
2017-11-09 21:04:25 +00:00
|
|
|
|
if (fx == -1)
|
2017-11-09 20:43:53 +00:00
|
|
|
|
{
|
|
|
|
|
this->fx = 500.0f * (this->frame_width / 640.0f);
|
|
|
|
|
this->fy = 500.0f * (this->frame_height / 480.0f);
|
|
|
|
|
|
2017-11-09 21:04:25 +00:00
|
|
|
|
this->fx = (this->fx + this->fy) / 2.0f;
|
|
|
|
|
this->fy = this->fx;
|
2017-11-09 20:43:53 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
this->fx = fx;
|
|
|
|
|
this->fy = fy;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-11-08 21:13:02 +00:00
|
|
|
|
|
2017-11-08 20:50:46 +00:00
|
|
|
|
cv::Mat SequenceCapture::GetNextFrame()
|
|
|
|
|
{
|
|
|
|
|
|
2017-11-09 19:56:16 +00:00
|
|
|
|
if (is_webcam || !is_image_seq)
|
2017-11-08 20:50:46 +00:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
bool success = capture.read(latest_frame);
|
|
|
|
|
|
|
|
|
|
if (!success)
|
|
|
|
|
{
|
|
|
|
|
// Indicate lack of success by returning an empty image
|
|
|
|
|
latest_frame = cv::Mat();
|
|
|
|
|
}
|
2017-11-09 19:56:16 +00:00
|
|
|
|
|
|
|
|
|
// Recording the timestamp
|
|
|
|
|
if (!is_webcam)
|
|
|
|
|
{
|
|
|
|
|
time_stamp = frame_num * (1.0 / fps);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
time_stamp = (cv::getTickCount() - start_time) / cv::getTickFrequency();
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-08 20:50:46 +00:00
|
|
|
|
}
|
|
|
|
|
else if (is_image_seq)
|
|
|
|
|
{
|
2017-11-23 17:44:27 +00:00
|
|
|
|
if (image_files.empty() || frame_num >= image_files.size())
|
2017-11-08 20:50:46 +00:00
|
|
|
|
{
|
|
|
|
|
// Indicate lack of success by returning an empty image
|
|
|
|
|
latest_frame = cv::Mat();
|
|
|
|
|
}
|
2017-11-23 17:44:27 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
2017-12-15 19:56:58 +00:00
|
|
|
|
latest_frame = cv::imread(image_files[frame_num], CV_LOAD_IMAGE_COLOR);
|
2017-11-23 17:44:27 +00:00
|
|
|
|
}
|
2017-11-09 19:56:16 +00:00
|
|
|
|
time_stamp = 0;
|
2017-11-08 20:50:46 +00:00
|
|
|
|
}
|
2017-12-15 19:56:58 +00:00
|
|
|
|
|
2017-11-08 20:50:46 +00:00
|
|
|
|
// Set the grayscale frame
|
2017-12-15 19:56:58 +00:00
|
|
|
|
ConvertToGrayscale_8bit(latest_frame, latest_gray_frame);
|
2017-11-08 20:50:46 +00:00
|
|
|
|
|
2017-11-23 17:44:27 +00:00
|
|
|
|
frame_num++;
|
|
|
|
|
|
2017-11-08 20:50:46 +00:00
|
|
|
|
return latest_frame;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double SequenceCapture::GetProgress()
|
|
|
|
|
{
|
|
|
|
|
if (is_webcam)
|
|
|
|
|
{
|
|
|
|
|
return -1.0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return (double)frame_num / (double)vid_length;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool SequenceCapture::IsOpened()
|
|
|
|
|
{
|
|
|
|
|
if (is_webcam || !is_image_seq)
|
|
|
|
|
return capture.isOpened();
|
|
|
|
|
else
|
|
|
|
|
return (image_files.size() > 0 && frame_num < image_files.size());
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-08 21:13:02 +00:00
|
|
|
|
cv::Mat_<uchar> SequenceCapture::GetGrayFrame()
|
|
|
|
|
{
|
|
|
|
|
return latest_gray_frame;
|
2017-11-08 20:50:46 +00:00
|
|
|
|
}
|