Newer
Older
* Copyright 2019 Nicolas Pope. All rights reserved.
*
* See LICENSE.
#include <string>
#include <map>
#include <vector>
#include <fstream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <opencv2/opencv.hpp>
#include <ftl/local.hpp>
#include <ftl/synched.hpp>
#include <ftl/calibrate.hpp>
#include <ftl/disparity.hpp>

Nicolas Pope
committed
#include <ftl/middlebury.hpp>

Nicolas Pope
committed
#include <ftl/streamer.hpp>
#include <ftl/net/universe.hpp>
#include <nlohmann/json.hpp>
#include "opencv2/imgproc.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/core/utility.hpp"
#ifdef WIN32
#pragma comment(lib, "Rpcrt4.lib")
#endif
using ftl::Calibrate;
using ftl::LocalSource;
using ftl::Display;

Nicolas Pope
committed
using ftl::Streamer;
using ftl::Disparity;
using ftl::SyncSource;

Nicolas Pope
committed
using ftl::net::Universe;
using std::string;
using std::vector;
using std::condition_variable;

Nicolas Pope
committed
using std::this_thread::sleep_for;
using std::chrono::milliseconds;
using std::mutex;
using std::unique_lock;
using json = nlohmann::json;

Nicolas Pope
committed
static void run(const string &file) {
ctpl::thread_pool pool(2);

Nicolas Pope
committed
Universe net(config["net"]);
LocalSource *lsrc;
if (ftl::is_video(file)) {
// Load video file

Nicolas Pope
committed
lsrc = new LocalSource(file, config["source"]);
} else if (file != "") {
auto vid = ftl::locateFile("video.mp4");
if (!vid) {
LOG(FATAL) << "No video.mp4 file found in provided paths";
} else {
lsrc = new LocalSource(*vid, config["source"]);
}
} else {
// Use cameras
lsrc = new LocalSource(config["source"]);
//auto sync = new SyncSource(); // TODO(nick) Pass protocol object
// Add any remote channels
sync->addChannel(c);
LOG(INFO) << "Locating calibration...";
// Perform or load calibration intrinsics + extrinsics
Calibrate calibrate(lsrc, config["calibration"]);
if (config["calibrate"]) calibrate.recalibrate();
if (!calibrate.isCalibrated()) LOG(WARNING) << "Cameras are not calibrated!";
else LOG(INFO) << "Calibration initiated.";
cv::Mat Q_32F;
calibrate.getQ().convertTo(Q_32F, CV_32F);
// Allow remote users to access camera calibration matrix

Nicolas Pope
committed
net.bind(string("ftl://utu.fi/")+(string)config["stream"]["name"]+string("/rgb-d/calibration"), [Q_32F]() -> vector<unsigned char> {
vector<unsigned char> buf;
buf.resize(Q_32F.step*Q_32F.rows);
LOG(INFO) << "Calib buf size = " << buf.size();
memcpy(buf.data(), Q_32F.data, buf.size());
Mat l, r, disp;
bool grabbed = false;
mutex datam;
condition_variable datacv;
// Wait for grab message to sync camera capture
net.bind("grab", [&calibrate,&l,&r,&datam,&datacv,&grabbed]() -> void {
unique_lock<mutex> datalk(datam);
if (grabbed) return;
calibrate.rectified(l, r);
grabbed = true;
datacv.notify_one();
});
// Choose and configure disparity algorithm
auto disparity = Disparity::create(config["disparity"]);
if (!disparity) LOG(FATAL) << "Unknown disparity algorithm : " << config["disparity"];
vector<unsigned char> rgb_buf;
vector<unsigned char> d_buf;
string uri = string("ftl://utu.fi/")+(string)config["stream"]["name"]+string("/rgb-d");

Nicolas Pope
committed
Streamer stream(net, config["stream"]);
mutex m;
condition_variable cv;
int jobs = 0;
// Fake grab if no peers to allow visualisation locally
if (net.numberOfPeers() == 0) {
grabbed = true;
calibrate.rectified(l, r);
}
unique_lock<mutex> datalk(datam);
datacv.wait(datalk, [&grabbed](){ return grabbed; });
grabbed = false;
auto start = std::chrono::high_resolution_clock::now();
disparity->compute(l, r, disp);
unique_lock<mutex> lk(m);
jobs++;
lk.unlock();
cv.notify_one();
std::chrono::duration<double> elapsed =
std::chrono::high_resolution_clock::now() - start;
LOG(INFO) << "Disparity in " << elapsed.count() << "s";
});
pool.push([&](int id) {
auto start = std::chrono::high_resolution_clock::now();
if (pl.rows != 0) stream.send(pl, pdisp);
unique_lock<mutex> lk(m);
jobs++;
lk.unlock();
cv.notify_one();
std::chrono::duration<double> elapsed =
std::chrono::high_resolution_clock::now() - start;
LOG(INFO) << "Stream in " << elapsed.count() << "s";
});
// Send RGB+Depth images for local rendering

Nicolas Pope
committed
if (pl.rows > 0) display.render(pl, pdisp);
// Wait for both pipelines to complete
unique_lock<mutex> lk(m);
cv.wait(lk, [&jobs]{return jobs == 2;});
// Store previous frame for next stage compression
l.copyTo(pl);
disp.copyTo(pdisp);
//net.publish(uri, rgb_buf, d_buf);

Nicolas Pope
committed
int main(int argc, char **argv) {
auto paths = ftl::configure(argc, argv, "vision");
config["paths"] = paths;

Nicolas Pope
committed
if (config["middlebury"]["dataset"] == "") {
run((paths.size() > 0) ? paths[0] : "");

Nicolas Pope
committed
} else {
ftl::middlebury::test(config);
}
}