You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
396 lines
10 KiB
396 lines
10 KiB
|
|
#include <iostream>
|
|
#include <algorithm>
|
|
#include <fstream>
|
|
#include <stdarg.h>
|
|
#include <trax/client.hpp>
|
|
#include <trax/opencv.hpp>
|
|
#include <opencv2/core/core.hpp>
|
|
#include <stdexcept>
|
|
|
|
#include <opencv2/highgui/highgui.hpp>
|
|
#include <opencv2/imgproc/imgproc.hpp>
|
|
|
|
#ifndef M_PI
|
|
#define M_PI 3.14159265358979323846
|
|
#endif
|
|
|
|
#if defined(__OS2__) || defined(__WINDOWS__) || defined(WIN32) || defined(WIN64) || defined(_MSC_VER)
|
|
#define NOMINMAX
|
|
#include <ctype.h>
|
|
#include <windows.h>
|
|
__inline void sleep(long time) {
|
|
Sleep(time * 1000);
|
|
}
|
|
#else
|
|
#ifdef _MAC_
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
#include <signal.h>
|
|
#endif
|
|
|
|
#include <time.h>
|
|
|
|
#include "getopt.h"
|
|
|
|
using namespace cv;
|
|
using namespace std;
|
|
using namespace trax;
|
|
|
|
#define WINDOW_NAME "TraX Player"
|
|
|
|
ConnectionMode connection = CONNECTION_DEFAULT;
|
|
VerbosityMode verbosity = VERBOSITY_DEFAULT;
|
|
|
|
void print_debug(const char *format, ...) {
|
|
if (verbosity != VERBOSITY_DEBUG)
|
|
return;
|
|
|
|
va_list args;
|
|
va_start(args, format);
|
|
|
|
fprintf(stdout, "CLIENT: ");
|
|
vfprintf(stdout, format, args);
|
|
|
|
va_end(args);
|
|
}
|
|
|
|
Image convert_image(Mat& sensor, int formats) {
|
|
|
|
Image image;
|
|
|
|
if TRAX_SUPPORTS(formats, TRAX_IMAGE_BUFFER) {
|
|
vector<uchar> buffer;
|
|
imencode(".jpg", sensor, buffer);
|
|
image = Image::create_buffer(buffer.size(), (char*) &buffer[0]);
|
|
} else if TRAX_SUPPORTS(formats, TRAX_IMAGE_MEMORY) {
|
|
image = trax::mat_to_image(sensor);
|
|
} else
|
|
throw std::runtime_error("No supported image format allowed");
|
|
|
|
return image;
|
|
|
|
}
|
|
|
|
typedef struct RegionCapture {
|
|
bool dragging;
|
|
Point start;
|
|
Point current;
|
|
Region region;
|
|
} RegionCapture;
|
|
|
|
void on_mouse(int event, int x, int y, int flags, void* data) {
|
|
|
|
Point point(x, y);
|
|
|
|
RegionCapture* rc = (RegionCapture *) data;
|
|
|
|
if ( event == EVENT_LBUTTONDOWN ) {
|
|
rc->dragging = true;
|
|
rc->start = point;
|
|
} else if ( event == EVENT_LBUTTONUP ) {
|
|
rc->dragging = false;
|
|
rc->region = Region::create_rectangle(rc->start.x, rc->start.y, point.x - rc->start.x, point.y - rc->start.y);
|
|
}
|
|
|
|
if (rc->dragging) {
|
|
rc->current = point;
|
|
}
|
|
|
|
}
|
|
|
|
Region get_region_interactive(const string& window, Mat& image) {
|
|
|
|
RegionCapture rc;
|
|
rc.dragging = false;
|
|
bool run = true;
|
|
|
|
string message("Drag mouse to enter region and SPACE to confirm, press Q to cancel input.");
|
|
|
|
Mat buffer;
|
|
|
|
setMouseCallback(window, on_mouse, &rc);
|
|
|
|
while (run) {
|
|
|
|
image.copyTo(buffer);
|
|
|
|
if (rc.dragging) {
|
|
rectangle(buffer, rc.start, rc.current, Scalar(0, 255, 0), 3);
|
|
}
|
|
|
|
if (!rc.region.empty()) {
|
|
draw_region(buffer, rc.region, Scalar(0, 255, 0), 1);
|
|
}
|
|
|
|
putText(buffer, message, Point(10, 10), FONT_HERSHEY_SIMPLEX, 0.4, Scalar(0, 255, 0));
|
|
imshow(window, buffer);
|
|
|
|
int i = waitKey(25);
|
|
|
|
switch ((char)i) {
|
|
case 'q': {
|
|
rc.region = Region();
|
|
break;
|
|
}
|
|
case ' ': {
|
|
run = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
setMouseCallback(window, NULL, NULL);
|
|
|
|
return rc.region;
|
|
}
|
|
|
|
|
|
bool read_frame(VideoCapture& reader, int frame, Mat& image) {
|
|
|
|
int current = reader.get(CV_CAP_PROP_POS_FRAMES);
|
|
|
|
if (frame < current) return false;
|
|
|
|
while (current != frame + 1) {
|
|
reader.read(image);
|
|
current++;
|
|
}
|
|
|
|
return !image.empty();
|
|
|
|
}
|
|
|
|
void configure_signals() {
|
|
|
|
#if defined(__OS2__) || defined(__WINDOWS__) || defined(WIN32) || defined(WIN64) || defined(_MSC_VER)
|
|
|
|
// TODO: anything to do here?
|
|
|
|
#else
|
|
|
|
struct sigaction sa;
|
|
sa.sa_handler = SIG_DFL;
|
|
sigemptyset(&sa.sa_mask);
|
|
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; //SA_NOCLDWAIT;
|
|
if (sigaction(SIGCHLD, &sa, 0) == -1) {
|
|
perror(0);
|
|
exit(1);
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#define GROUNDTRUTH_COLOR Scalar(100, 255, 100)
|
|
#define TRACKER_COLOR Scalar(100, 100, 255)
|
|
|
|
#define CMD_OPTIONS "hdV:G:t:p:e:xXg"
|
|
|
|
#ifndef TRAX_BUILD_DATE
|
|
#define TRAX_BUILD_DATE __DATE__
|
|
#endif
|
|
|
|
void print_help() {
|
|
|
|
cout << "OpenCV Video capture player client" << "\n\n";
|
|
cout << "Built on " << TRAX_BUILD_DATE << "\n";
|
|
cout << "TraX library version: " << trax_version() << "\n";
|
|
cout << "Protocol version: " << TRAX_VERSION << "\n\n";
|
|
|
|
cout << "Usage: traxplayer [-h] [-d] \n";
|
|
cout << "\t [-e name=value] [-V video_file]\n";
|
|
cout << "\t [-p name=value] [-t timeout] [-x] [-X]\n";
|
|
cout << "\t [-g] -- <command_part1> <command_part2> ...";
|
|
|
|
cout << "\n\nProgram arguments: \n";
|
|
cout << "\t-d\tEnable debug\n";
|
|
cout << "\t-e\tEnvironmental variable (multiple occurences allowed)\n";
|
|
cout << "\t-g\tVisualize result in a window\n";
|
|
cout << "\t-h\tPrint this help and exit\n";
|
|
cout << "\t-V\tVideo file for the input cubemap sequence.\n";
|
|
cout << "\t-p\tTracker parameter (multiple occurences allowed)\n";
|
|
cout << "\t-t\tSet timeout period\n";
|
|
cout << "\t-x\tUse explicit streams, not standard ones.\n";
|
|
cout << "\t-X\tUse TCP/IP sockets instead of file streams.\n";
|
|
cout << "\n";
|
|
|
|
cout << "\n";
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
|
|
int c;
|
|
opterr = 0;
|
|
int result = 0;
|
|
int timeout = 30;
|
|
|
|
string timing_file;
|
|
string tracker_command;
|
|
string video_file("input.avi");
|
|
|
|
Properties properties;
|
|
map<string, string> environment;
|
|
|
|
configure_signals();
|
|
|
|
try {
|
|
|
|
while ((c = getopt(argc, argv, CMD_OPTIONS)) != -1)
|
|
switch (c) {
|
|
case 'h':
|
|
print_help();
|
|
exit(0);
|
|
case 'd':
|
|
verbosity = VERBOSITY_DEBUG;
|
|
break;
|
|
case 'x':
|
|
connection = CONNECTION_EXPLICIT;
|
|
break;
|
|
case 'X':
|
|
connection = CONNECTION_SOCKETS;
|
|
break;
|
|
case 'V':
|
|
video_file = string(optarg);
|
|
break;
|
|
case 't':
|
|
timeout = MAX(0, atoi(optarg));
|
|
break;
|
|
case 'e': {
|
|
char* var = optarg;
|
|
char* ptr = strchr(var, '=');
|
|
if (!ptr) break;
|
|
environment[string(var, ptr - var)] = string(ptr + 1);
|
|
break;
|
|
}
|
|
case 'p': {
|
|
char* var = optarg;
|
|
char* ptr = strchr(var, '=');
|
|
if (!ptr) break;
|
|
string key(var, ptr - var);
|
|
string value(ptr + 1);
|
|
properties.set(key, value);
|
|
break;
|
|
}
|
|
default:
|
|
print_help();
|
|
throw std::runtime_error(string("Unknown switch -") + string(1, (char) optopt));
|
|
}
|
|
|
|
if (optind < argc) {
|
|
|
|
stringstream buffer;
|
|
|
|
for (int i = optind; i < argc; i++) {
|
|
buffer << " \"" << string(argv[i]) << "\" ";
|
|
}
|
|
|
|
tracker_command = buffer.str();
|
|
|
|
} else {
|
|
print_help();
|
|
exit(-1);
|
|
}
|
|
|
|
Mat cvimage;
|
|
VideoCapture reader(video_file);
|
|
int video_length = reader.get(CV_CAP_PROP_FRAME_COUNT);
|
|
|
|
print_debug("Video will be loaded from file %s.\n", video_file.c_str());
|
|
|
|
namedWindow(WINDOW_NAME);
|
|
|
|
print_debug("Sequence length: %d frames.\n", video_length);
|
|
|
|
TrackerProcess tracker(tracker_command, environment, timeout, connection, verbosity);
|
|
|
|
int frame = 0;
|
|
while (true) {
|
|
|
|
Region initialization_region;
|
|
|
|
if (!read_frame(reader, frame, cvimage)) {
|
|
print_debug("No data available. Stopping. \n");
|
|
break;
|
|
}
|
|
initialization_region = get_region_interactive(WINDOW_NAME, cvimage);
|
|
if (!initialization_region.empty()) {
|
|
print_debug("Using interactive region: %s\n", ((string) initialization_region).c_str());
|
|
} else break;
|
|
|
|
if (!tracker.ready()) {
|
|
throw std::runtime_error("Tracker process not alive anymore.");
|
|
}
|
|
|
|
Metadata metadata = tracker.metadata();
|
|
|
|
ImageList image;
|
|
image.set(convert_image(cvimage, metadata.image_formats()), TRAX_CHANNEL_COLOR);
|
|
|
|
if (!tracker.initialize(image, initialization_region, properties)) {
|
|
throw std::runtime_error("Unable to initialize tracker.");
|
|
}
|
|
|
|
draw_region(cvimage, initialization_region, GROUNDTRUTH_COLOR, 3);
|
|
imshow(WINDOW_NAME, cvimage);
|
|
waitKey(25);
|
|
|
|
while (frame < video_length) {
|
|
// Repeat while tracking the target.
|
|
Region status;
|
|
Properties additional;
|
|
|
|
bool result = tracker.wait(status, additional);
|
|
|
|
if (result) {
|
|
// Default option, the tracker returns a valid status.
|
|
|
|
Region storage;
|
|
|
|
} else {
|
|
if (tracker.ready()) {
|
|
// The tracker has requested termination of connection.
|
|
print_debug("Termination requested by tracker.\n");
|
|
break;
|
|
} else {
|
|
// In case of an error ...
|
|
throw std::runtime_error("Unable to contact tracker.");
|
|
}
|
|
}
|
|
|
|
draw_region(cvimage, status, TRACKER_COLOR, 1);
|
|
imshow(WINDOW_NAME, cvimage);
|
|
waitKey(25);
|
|
|
|
frame++;
|
|
|
|
if (!read_frame(reader, frame, cvimage)) {
|
|
print_debug("No more data available. Stopping. \n");
|
|
break;
|
|
}
|
|
|
|
image.set(convert_image(cvimage, metadata.image_formats()), TRAX_CHANNEL_COLOR);
|
|
|
|
Properties no_properties;
|
|
if (!tracker.frame(image, no_properties))
|
|
throw std::runtime_error("Unable to send new frame.");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
reader.release();
|
|
|
|
} catch (const std::runtime_error &e) {
|
|
|
|
fprintf(stderr, "Error: %s\n", e.what());
|
|
result = -1;
|
|
|
|
}
|
|
|
|
exit(result);
|
|
|
|
}
|