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;
net.bind("grab", [&calibrate,&l,&r,&datam,&datacv,&grabbed]() -> void {
// LOG(INFO) << "GRAB";
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");
Display display(config["display"]);
display.setCalibration(Q_32F);

Nicolas Pope
committed
Streamer stream(net, config["stream"]);
mutex m;
condition_variable cv;
int jobs = 0;
pool.push([&](int id) {
// Read calibrated images.
//calibrate.rectified(l, r);
unique_lock<mutex> datalk(datam);
datacv.wait(datalk, [&grabbed](){ return grabbed; });
grabbed = false;
// Feed into sync buffer and network forward

Nicolas Pope
committed
//sync->feed(ftl::LEFT, l, lsrc->getTimestamp());
//sync->feed(ftl::RIGHT, r, lsrc->getTimestamp());
// Read back from buffer

Nicolas Pope
committed
//sync->get(ftl::LEFT, l);
//sync->get(ftl::RIGHT, r);
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";
});
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// Pipeline for jpeg compression
/*pool.push([&](int id) {
auto start = std::chrono::high_resolution_clock::now();
if (pl.rows != 0) cv::imencode(".jpg", pl, rgb_buf);
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) << "JPG in " << elapsed.count() << "s";
});*/
// Pipeline for zlib compression
/*pool.push([&](int id) {
auto start = std::chrono::high_resolution_clock::now();
if (pl.rows != 0) {
d_buf.resize(pdisp.step*pdisp.rows);
z_stream defstream;
defstream.zalloc = Z_NULL;
defstream.zfree = Z_NULL;
defstream.opaque = Z_NULL;
defstream.avail_in = pdisp.step*pdisp.rows;
defstream.next_in = (Bytef *)pdisp.data; // input char array
defstream.avail_out = (uInt)pdisp.step*pdisp.rows; // size of output
defstream.next_out = (Bytef *)d_buf.data(); // output char array
deflateInit(&defstream, Z_BEST_COMPRESSION);
deflate(&defstream, Z_FINISH);
deflateEnd(&defstream);
d_buf.resize(defstream.total_out);
}
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) << "ZLIB in " << elapsed.count() << "s";
});*/
// Pipeline for stream compression
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);
}
}