diff --git a/CMakeLists.txt b/CMakeLists.txt index ca8b5b291db1eb9dc2e6e7ec8297d16d52a1ce14..ef3b984099eeedcc3ce0d98c94e5266bd3239099 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,7 +42,7 @@ check_language(CUDA) if (CUDA_TOOLKIT_ROOT_DIR) enable_language(CUDA) set(CMAKE_CUDA_FLAGS "") -set(CMAKE_CUDA_FLAGS_DEBUG "-g -DDEBUG -D_DEBUG -Wall") +set(CMAKE_CUDA_FLAGS_DEBUG "-g -DDEBUG -D_DEBUG") set(CMAKE_CUDA_FLAGS_RELEASE "") set(HAVE_CUDA TRUE) include_directories(${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES}) @@ -114,6 +114,7 @@ endif() SET(CMAKE_USE_RELATIVE_PATHS ON) +add_subdirectory(common/cpp) add_subdirectory(renderer) add_subdirectory(net) add_subdirectory(vision) diff --git a/common/config/config.json b/common/config/config.json index bafcaf0b4fedcfaa3aa154fe2afd9ac0ee0be026..80d6589a63910e414ff02d2db35e46291eb69130 100644 --- a/common/config/config.json +++ b/common/config/config.json @@ -1,66 +1,68 @@ { - "middlebury": { - "dataset": "", - "threshold": 10.0, - "scale": 0.25 - }, - "source": { - "flip": false, - "nostereo": false, - "scale": 1.0, - "flip_vert": false - }, - "calibrate": false, - "calibration": { - "board_size": [9,6], - "square_size": 50, - "frame_delay": 1.0, - "num_frames": 35, - "assume_zero_tangential_distortion": true, - "fix_aspect_ratio": true, - "fix_principal_point_at_center": true, - "use_fisheye_model": false, - "fix_k1": false, - "fix_k2": false, - "fix_k3": false, - "fix_k4": true, - "fix_k5": true, - "save": true, - "use_intrinsics": true, - "use_extrinsics": true, - "flip_vertical": false - }, - "camera": { - "name": "Panasonic Lumix DMC-FZ300", - "focal_length": 25, - "sensor_width": 6.17, - "base_line": 0.1 - }, - "disparity": { - "algorithm": "rtcensus", - "use_cuda": true, - "minimum": 0, - "maximum": 208, - "tau": 0.0, - "gamma": 0.0, - "window_size": 5, - "sigma": 1.5, - "lambda": 8000.0 - }, - "display": { - "flip_vert": false, - "disparity": false, - "points": true, - "depth": false, - "left": false, - "right": false - }, - "net": { - "listen": "tcp://*:9001", - "peers": [] - }, - "stream": { - "name": "dummy" + "vision": { + "middlebury": { + "dataset": "", + "threshold": 10.0, + "scale": 0.25 + }, + "source": { + "flip": false, + "nostereo": false, + "scale": 1.0, + "flip_vert": false + }, + "calibrate": false, + "calibration": { + "board_size": [9,6], + "square_size": 50, + "frame_delay": 1.0, + "num_frames": 35, + "assume_zero_tangential_distortion": true, + "fix_aspect_ratio": true, + "fix_principal_point_at_center": true, + "use_fisheye_model": false, + "fix_k1": false, + "fix_k2": false, + "fix_k3": false, + "fix_k4": true, + "fix_k5": true, + "save": true, + "use_intrinsics": true, + "use_extrinsics": true, + "flip_vertical": false + }, + "camera": { + "name": "Panasonic Lumix DMC-FZ300", + "focal_length": 25, + "sensor_width": 6.17, + "base_line": 0.1 + }, + "disparity": { + "algorithm": "rtcensus", + "use_cuda": true, + "minimum": 0, + "maximum": 208, + "tau": 0.0, + "gamma": 0.0, + "window_size": 5, + "sigma": 1.5, + "lambda": 8000.0 + }, + "display": { + "flip_vert": false, + "disparity": false, + "points": true, + "depth": false, + "left": false, + "right": false + }, + "net": { + "listen": "tcp://*:9001", + "peers": [] + }, + "stream": { + "name": "dummy" + } }, "representation": { "net": { diff --git a/common/cpp/CMakeLists.txt b/common/cpp/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..2a9be0f3b3f32963d088d6af06809db57281d3b7 --- /dev/null +++ b/common/cpp/CMakeLists.txt @@ -0,0 +1,13 @@ +set(COMMONSRC + src/config.cpp + src/configuration.cpp +) + +add_library(ftlcommon ${COMMONSRC}) + +target_include_directories(ftlcommon PUBLIC + $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include> + $<INSTALL_INTERFACE:include> + PRIVATE src) +target_link_libraries(ftlcommon glog::glog) + diff --git a/common/cpp/include/ftl/configuration.hpp b/common/cpp/include/ftl/configuration.hpp new file mode 100644 index 0000000000000000000000000000000000000000..685c9b4ba30e08268d4a48c2b50ad852e84cf7b8 --- /dev/null +++ b/common/cpp/include/ftl/configuration.hpp @@ -0,0 +1,26 @@ +#ifndef _FTL_COMMON_CONFIGURATION_HPP_ +#define _FTL_COMMON_CONFIGURATION_HPP_ + +#include <nlohmann/json.hpp> +#include <string> +#include <vector> +#include <optional> + +namespace ftl { + +extern nlohmann::json config; + +bool is_directory(const std::string &path); +bool is_file(const std::string &path); +bool create_directory(const std::string &path); + +bool is_video(const std::string &file); + +std::optional<std::string> locateFile(const std::string &name); + +std::vector<std::string> configure(int argc, char **argv, const std::string &app); + +}; + +#endif // _FTL_COMMON_CONFIGURATION_HPP_ + diff --git a/common/cpp/src/configuration.cpp b/common/cpp/src/configuration.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6a7df835da6b6b2ad8c914de3a8c0ee95528c219 --- /dev/null +++ b/common/cpp/src/configuration.cpp @@ -0,0 +1,233 @@ +#include <glog/logging.h> +#include <ftl/config.h> + +#ifdef WIN32 +#include <windows.h> +#else +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#endif + +#include <nlohmann/json.hpp> +#include <ftl/configuration.hpp> + +#include <fstream> +#include <string> +#include <map> +#include <iostream> + +using nlohmann::json; +using std::ifstream; +using std::string; +using std::map; +using std::vector; +using std::optional; +using ftl::is_file; +using ftl::is_directory; + +// Store loaded configuration +namespace ftl { +json config; +}; + +using ftl::config; + +bool ftl::is_directory(const std::string &path) { +#ifdef WIN32 + DWORD attrib = GetFileAttributesA(path.c_str()); + if (attrib == INVALID_FILE_ATTRIBUTES) return false; + else return (attrib & FILE_ATTRIBUTE_DIRECTORY); +#else + struct stat s; + if (::stat(path.c_str(), &s) == 0) { + return S_ISDIR(s.st_mode); + } else { + return false; + } +#endif +} + +bool ftl::is_file(const std::string &path) { +#ifdef WIN32 + DWORD attrib = GetFileAttributesA(path.c_str()); + if (attrib == INVALID_FILE_ATTRIBUTES) return false; + else return !(attrib & FILE_ATTRIBUTE_DIRECTORY); +#else + struct stat s; + if (::stat(path.c_str(), &s) == 0) { + return S_ISREG(s.st_mode); + } else { + return false; + } +#endif +} + +static bool endsWith(const string &s, const string &e) { + return s.size() >= e.size() && + s.compare(s.size() - e.size(), e.size(), e) == 0; +} + +bool ftl::is_video(const string &file) { + return endsWith(file, ".mp4"); +} + +bool ftl::create_directory(const std::string &path) { +#ifdef WIN32 + // TODO(nick) +#else + if (!is_directory(path)) { + int err = ::mkdir(path.c_str(), S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); + return err != -1; + } + return true; +#endif +} + +optional<string> ftl::locateFile(const string &name) { + auto paths = config["paths"]; + + if (!paths.is_null()) { + for (string p : paths) { + if (is_directory(p)) { + if (is_file(p+"/"+name)) { + return p+"/"+name; + } + } else if (p.size() >= name.size() && + p.compare(p.size() - name.size(), name.size(), name) == 0 && + is_file(p)) { + return p; + } + } + } + + if (is_file("./"+name)) return "./"+name; + if (is_file(string(FTL_LOCAL_CONFIG_ROOT) +"/"+ name)) return string(FTL_LOCAL_CONFIG_ROOT) +"/"+ name; + if (is_file(string(FTL_GLOBAL_CONFIG_ROOT) +"/"+ name)) return string(FTL_GLOBAL_CONFIG_ROOT) +"/"+ name; + return {}; +} + +/** + * Combine one json config with another patch json config. + */ +static bool mergeConfig(const string &path) { + ifstream i; + i.open(path); + if (i.is_open()) { + json t; + i >> t; + config.merge_patch(t); + return true; + } else { + return false; + } +} + +/** + * Find and load a JSON configuration file + */ +static bool findConfiguration(const string &file, const vector<string> &paths, + const std::string &app) { + bool found = false; + + found |= mergeConfig(FTL_GLOBAL_CONFIG_ROOT "/config.json"); + found |= mergeConfig(FTL_LOCAL_CONFIG_ROOT "/config.json"); + found |= mergeConfig("./config.json"); + + for (auto p : paths) { + if (is_directory(p)) { + found |= mergeConfig(p+"/config.json"); + } + } + + if (file != "") { + found |= mergeConfig(file); + } + + if (found) { + config = config[app]; + return true; + } else { + return false; + } +} + +/** + * Generate a map from command line option to value + */ +static map<string, string> read_options(char ***argv, int *argc) { + map<string, string> opts; + + while (*argc > 0) { + string cmd((*argv)[0]); + if (cmd[0] != '-') break; + + size_t p; + if ((p = cmd.find("=")) == string::npos) { + opts[cmd.substr(2)] = "true"; + } else { + auto val = cmd.substr(p+1); + if (std::isdigit(val[0]) || val == "true" || val == "false" || val == "null") { + opts[cmd.substr(2, p-2)] = val; + } else { + if (val[0] == '\\') opts[cmd.substr(2, p-2)] = val; + else opts[cmd.substr(2, p-2)] = "\""+val+"\""; + } + } + + (*argc)--; + (*argv)++; + } + + return opts; +} + +/** + * Put command line options into json config. If config element does not exist + * or is of a different type then report an error. + */ +static void process_options(const map<string, string> &opts) { + for (auto opt : opts) { + if (opt.first == "config") continue; + + if (opt.first == "version") { + std::cout << "FTL Vision Node - v" << FTL_VERSION << std::endl; + std::cout << FTL_VERSION_LONG << std::endl; + exit(0); + } + + try { + auto ptr = json::json_pointer("/"+opt.first); + // TODO(nick) Allow strings without quotes + auto v = json::parse(opt.second); + if (v.type() != config.at(ptr).type()) { + LOG(ERROR) << "Incorrect type for argument " << opt.first; + continue; + } + config.at(ptr) = v; + } catch(...) { + LOG(ERROR) << "Unrecognised option: " << opt.first; + } + } +} + +vector<string> ftl::configure(int argc, char **argv, const std::string &app) { + argc--; + argv++; + + // Process Arguments + auto options = read_options(&argv, &argc); + + vector<string> paths; + while (argc-- > 0) { + paths.push_back(argv[0]); + } + + if (!findConfiguration(options["config"], paths, app)) { + LOG(FATAL) << "Could not find any configuration!"; + } + process_options(options); + + return paths; +} + diff --git a/net/cpp/include/ftl/net/peer.hpp b/net/cpp/include/ftl/net/peer.hpp index cd0fe67d027a2803d450c842b49e23de8069dad0..fb789a46b65b9f892f093b9131f4f066b903d55e 100644 --- a/net/cpp/include/ftl/net/peer.hpp +++ b/net/cpp/include/ftl/net/peer.hpp @@ -289,6 +289,7 @@ int Peer::asyncCall( LOG(INFO) << "RPC " << name << "() -> " << uri_; + std::unique_lock<std::mutex> lk(send_mtx_); msgpack::pack(send_buf_, call_obj); // Register the CB diff --git a/net/cpp/src/dispatcher.cpp b/net/cpp/src/dispatcher.cpp index 34861a04fcd08044f8f2b579f739911bbf723dbd..269db7a6d38de8be0ac8fe25d82b222db63f0c04 100644 --- a/net/cpp/src/dispatcher.cpp +++ b/net/cpp/src/dispatcher.cpp @@ -129,7 +129,7 @@ void ftl::net::Dispatcher::dispatch_notification(Peer &s, msgpack::object const auto &&name = std::get<1>(the_call); auto &&args = std::get<2>(the_call); - //LOG(INFO) << "NOTIFICATION " << name << "() <- " << s.getURI(); + // LOG(INFO) << "NOTIFICATION " << name << "() <- " << s.getURI(); auto binding = _locateHandler(name); diff --git a/net/cpp/src/peer.cpp b/net/cpp/src/peer.cpp index a782bc67c1c249767e06c1797f2e952f1f3aca18..5c29ace9a708fcee6737b38976afc85b444ffd43 100644 --- a/net/cpp/src/peer.cpp +++ b/net/cpp/src/peer.cpp @@ -122,9 +122,9 @@ static int tcpConnect(URI &uri) { } // Make blocking again - /*rg = fcntl(csocket, F_GETFL, NULL)); + /*long arg = fcntl(csocket, F_GETFL, NULL); arg &= (~O_NONBLOCK); - fcntl(csocket, F_SETFL, arg) < 0)*/ + fcntl(csocket, F_SETFL, arg);*/ return csocket; } @@ -153,8 +153,6 @@ Peer::Peer(int s, Dispatcher *d) : sock_(s) { _trigger(open_handlers_); } }); - - //ftl::UUID uuid; send("__handshake__", ftl::net::kMagic, ftl::net::kVersion, ftl::net::this_peer); } @@ -171,14 +169,6 @@ Peer::Peer(const char *pUri, Dispatcher *d) : uri_(pUri) { scheme_ = uri.getProtocol(); if (uri.getProtocol() == URI::SCHEME_TCP) { sock_ = tcpConnect(uri); - -#ifdef WIN32 - u_long on = 1; - ioctlsocket(sock_, FIONBIO, &on); -#else - fcntl(sock_, F_SETFL, O_NONBLOCK); -#endif - status_ = kConnecting; } else if (uri.getProtocol() == URI::SCHEME_WS) { LOG(INFO) << "Websocket connect " << uri.getPath(); @@ -191,13 +181,6 @@ Peer::Peer(const char *pUri, Dispatcher *d) : uri_(pUri) { } else { LOG(ERROR) << "Connection refused to " << uri.getHost() << ":" << uri.getPort(); } - -#ifdef WIN32 - u_long on = 1; - ioctlsocket(sock_, FIONBIO, &on); -#else - fcntl(sock_, F_SETFL, O_NONBLOCK); -#endif status_ = kConnecting; } else { @@ -315,7 +298,7 @@ void Peer::data() { } bool Peer::_data() { - //std::unique_lock<std::mutex> lk(recv_mtx_); + // std::unique_lock<std::mutex> lk(recv_mtx_); recv_buf_.reserve_buffer(kMaxMessage); int rc = ftl::net::internal::recv(sock_, recv_buf_.buffer(), kMaxMessage, 0); @@ -483,6 +466,7 @@ void Peer::cancelCall(int id) { void Peer::_sendResponse(uint32_t id, const msgpack::object &res) { Dispatcher::response_t res_obj = std::make_tuple(1,id,std::string(""),res); + std::unique_lock<std::mutex> lk(send_mtx_); msgpack::pack(send_buf_, res_obj); _send(); } @@ -535,6 +519,13 @@ int Peer::_send() { int c = ftl::net::internal::writev(sock_, send_buf_.vector(), send_buf_.vector_size()); #endif send_buf_.clear(); + + // We are blocking, so -1 should mean actual error + if (c == -1) { + socketError(); + close(); + } + return c; } diff --git a/reconstruct/src/main.cpp b/reconstruct/src/main.cpp index e4385633ab87aff3380476ba3449fb4a50f52c0d..1885d8c397e9fa69456ffb2722dc5796d62bc490 100644 --- a/reconstruct/src/main.cpp +++ b/reconstruct/src/main.cpp @@ -7,6 +7,7 @@ #include <glog/logging.h> #include <ftl/config.h> #include <zlib.h> +// #include <lz4.h> #include <string> #include <map> @@ -131,9 +132,9 @@ static void run(const string &file) { cv::imdecode(jpg, cv::IMREAD_COLOR, &rgb); //LOG(INFO) << "Received JPG : " << rgb.cols; - depth = Mat(rgb.size(), CV_32FC1); + depth = Mat(rgb.size(), CV_16UC1); - z_stream infstream; + /*z_stream infstream; infstream.zalloc = Z_NULL; infstream.zfree = Z_NULL; infstream.opaque = Z_NULL; @@ -146,7 +147,12 @@ static void run(const string &file) { // the actual DE-compression work. inflateInit(&infstream); inflate(&infstream, Z_NO_FLUSH); - inflateEnd(&infstream); + inflateEnd(&infstream);*/ + + //LZ4_decompress_safe((char*)d.data(), (char*)depth.data, d.size(), depth.step*depth.rows); + + cv::imdecode(d, cv::IMREAD_UNCHANGED, &depth); + depth.convertTo(depth, CV_32FC1, 1.0f/16.0f); }); while (disp.active()) { @@ -156,7 +162,10 @@ static void run(const string &file) { if (depth.cols > 0) { // If no calibration data then get it from the remote machine if (Q.rows == 0) { + // Must unlock before calling findOne to prevent net block!! + lk.unlock(); auto buf = net.findOne<vector<unsigned char>>((string)config["source"]+"/calibration"); + lk.lock(); if (buf) { Q = Mat(cv::Size(4,4), CV_32F); memcpy(Q.data, (*buf).data(), (*buf).size()); diff --git a/vision/CMakeLists.txt b/vision/CMakeLists.txt index 47a39a6e4764d466876874994a8ae1d098e3df6c..a0cc3f6b9f57fb1d43d5c56ed035c17b11b0da44 100644 --- a/vision/CMakeLists.txt +++ b/vision/CMakeLists.txt @@ -5,7 +5,6 @@ include_directories(${PROJECT_SOURCE_DIR}/vision/include) add_subdirectory(lib) set(CVNODESRC - ../common/cpp/src/config.cpp src/main.cpp src/calibrate.cpp src/local.cpp @@ -38,6 +37,7 @@ if (CUDA_FOUND) endif (CUDA_FOUND) add_executable(ftl-vision ${CVNODESRC}) +add_dependencies(ftl-vision ftlcommon) add_dependencies(ftl-vision ftlnet) add_dependencies(ftl-vision ftlrender) add_dependencies(ftl-vision libelas) @@ -47,6 +47,6 @@ set_property(TARGET ftl-vision PROPERTY CUDA_SEPARABLE_COMPILATION ON) endif() #target_include_directories(cv-node PUBLIC ${PROJECT_SOURCE_DIR}/include) -target_link_libraries(ftl-vision ftlrender Threads::Threads ZLIB::ZLIB libelas ${OpenCV_LIBS} ${LIBSGM_LIBRARIES} ${CUDA_LIBRARIES} glog::glog ftlnet) +target_link_libraries(ftl-vision ftlcommon ftlrender Threads::Threads ZLIB::ZLIB libelas ${OpenCV_LIBS} ${LIBSGM_LIBRARIES} ${CUDA_LIBRARIES} glog::glog ftlnet) diff --git a/vision/src/algorithms/opencv_bm.cpp b/vision/src/algorithms/opencv_bm.cpp index acb9793e601f82edcfaac3e9e5b6088a49e25936..203ac37e221e5b086fcf32295dfbc9e09d1e1655 100644 --- a/vision/src/algorithms/opencv_bm.cpp +++ b/vision/src/algorithms/opencv_bm.cpp @@ -22,9 +22,12 @@ OpenCVBM::OpenCVBM(nlohmann::json &config) : Disparity(config) { void OpenCVBM::compute(const cv::Mat &l, const cv::Mat &r, cv::Mat &disp) { Mat left_disp; Mat right_disp; - left_matcher_-> compute(l, r,left_disp); - right_matcher_->compute(r,l, right_disp); - wls_filter_->filter(left_disp,l,disp,right_disp); + Mat lg, rg; + cv::cvtColor(l, lg, cv::COLOR_BGR2GRAY); + cv::cvtColor(r, rg, cv::COLOR_BGR2GRAY); + left_matcher_-> compute(lg, rg,left_disp); + right_matcher_->compute(rg, lg, right_disp); + wls_filter_->filter(left_disp, l, disp, right_disp); } diff --git a/vision/src/calibrate.cpp b/vision/src/calibrate.cpp index 46dadb8ab33f574fd1ce7df941f5293ea1270378..092f5015d9371d44e3ab9163c14ed5d3921e4563 100644 --- a/vision/src/calibrate.cpp +++ b/vision/src/calibrate.cpp @@ -4,6 +4,7 @@ #include <glog/logging.h> #include <ftl/config.h> +#include <ftl/configuration.hpp> #include <iostream> #include <sstream> @@ -214,12 +215,21 @@ bool Calibrate::_loadCalibration() { float scale = 1.0f; Rect roi1, roi2; + FileStorage fs; // reading intrinsic parameters - FileStorage fs(FTL_LOCAL_CONFIG_ROOT "/intrinsics.yml", FileStorage::READ); - if (!fs.isOpened()) { - LOG(WARNING) << "Calibration file not found"; - return false; + auto ifile = ftl::locateFile("intrinsics.yml"); + if (ifile) { + fs.open((*ifile).c_str(), FileStorage::READ); + if (!fs.isOpened()) { + LOG(WARNING) << "Could not open intrinsics file"; + return false; + } + + LOG(INFO) << "Intrinsics from: " << *ifile; + } else { + LOG(WARNING) << "Calibration intrinsics file not found"; + return false; } Mat M1, D1, M2, D2; @@ -231,10 +241,18 @@ bool Calibrate::_loadCalibration() { M1 *= scale; M2 *= scale; - fs.open(FTL_LOCAL_CONFIG_ROOT "/extrinsics.yml", FileStorage::READ); - if (!fs.isOpened()) { - LOG(WARNING) << "Calibration file not found"; - return false; + auto efile = ftl::locateFile("extrinsics.yml"); + if (efile) { + fs.open((*efile).c_str(), FileStorage::READ); + if (!fs.isOpened()) { + LOG(WARNING) << "Could not open extrinsics file"; + return false; + } + + LOG(INFO) << "Extrinsics from: " << *efile; + } else { + LOG(WARNING) << "Calibration extrinsics file not found"; + return false; } Mat R, T, R1, P1, R2, P2; diff --git a/vision/src/main.cpp b/vision/src/main.cpp index e7f4b9fe35a4c8f31abe1d43dc0cd3538b2173c2..59b61bae91e02c781a00edbce2d1a252081a33be 100644 --- a/vision/src/main.cpp +++ b/vision/src/main.cpp @@ -5,7 +5,7 @@ */ #include <glog/logging.h> -#include <ftl/config.h> +#include <ftl/configuration.hpp> #include <ctpl_stl.h> #include <zlib.h> @@ -48,91 +48,30 @@ using std::string; using std::vector; using std::map; using std::condition_variable; +using std::this_thread::sleep_for; +using std::chrono::milliseconds; using std::mutex; using std::unique_lock; using cv::Mat; using json = nlohmann::json; -using std::ifstream; +using ftl::config; -// Store loaded configuration -static json config; - -/** - * Find and load a JSON configuration file - */ -static bool findConfiguration(const string &file) { - ifstream i; - - if (file != "") i.open(file); - if (!i.is_open()) i.open("./config.json"); - if (!i.is_open()) i.open(FTL_LOCAL_CONFIG_ROOT "/config.json"); - if (!i.is_open()) i.open(FTL_GLOBAL_CONFIG_ROOT "/config.json"); - if (!i.is_open()) return false; - i >> config; - return true; -} - -/** - * Generate a map from command line option to value - */ -map<string, string> read_options(char ***argv, int *argc) { - map<string, string> opts; - - while (*argc > 0) { - string cmd((*argv)[0]); - if (cmd[0] != '-') break; - - size_t p; - if ((p = cmd.find("=")) == string::npos) { - opts[cmd.substr(2)] = "true"; - } else { - opts[cmd.substr(2, p-2)] = cmd.substr(p+1); - } - - (*argc)--; - (*argv)++; - } - - return opts; -} - -/** - * Put command line options into json config. If config element does not exist - * or is of a different type then report an error. - */ -static void process_options(const map<string, string> &opts) { - for (auto opt : opts) { - if (opt.first == "config") continue; - - if (opt.first == "version") { - std::cout << "FTL Vision Node - v" << FTL_VERSION << std::endl; - std::cout << FTL_VERSION_LONG << std::endl; - exit(0); - } - - try { - auto ptr = json::json_pointer("/"+opt.first); - // TODO(nick) Allow strings without quotes - auto v = json::parse(opt.second); - if (v.type() != config.at(ptr).type()) { - LOG(ERROR) << "Incorrect type for argument " << opt.first; - continue; - } - config.at(ptr) = v; - } catch(...) { - LOG(ERROR) << "Unrecognised option: " << opt.first; - } - } -} static void run(const string &file) { ctpl::thread_pool pool(2); Universe net(config["net"]); LocalSource *lsrc; - if (file != "") { + if (ftl::is_video(file)) { // Load video file 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"]); @@ -153,7 +92,7 @@ static void run(const string &file) { calibrate.getQ().convertTo(Q_32F, CV_32F); // Allow remote users to access camera calibration matrix - net.bind(string("ftl://utu.fi/")+(string)config["stream"]["name"]+string("/rgb-d/calibration"), [&calibrate,Q_32F]() -> vector<unsigned char> { + 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(); @@ -188,14 +127,13 @@ static void run(const string &file) { calibrate.rectified(l, r); // Feed into sync buffer and network forward - sync->feed(ftl::LEFT, l, lsrc->getTimestamp()); - sync->feed(ftl::RIGHT, r, lsrc->getTimestamp()); + //sync->feed(ftl::LEFT, l, lsrc->getTimestamp()); + //sync->feed(ftl::RIGHT, r, lsrc->getTimestamp()); // Read back from buffer - sync->get(ftl::LEFT, l); - sync->get(ftl::RIGHT, r); + //sync->get(ftl::LEFT, l); + //sync->get(ftl::RIGHT, r); - // TODO(nick) Pipeline this disparity->compute(l, r, disp); unique_lock<mutex> lk(m); @@ -266,7 +204,8 @@ static void run(const string &file) { LOG(INFO) << "Stream in " << elapsed.count() << "s"; }); - display.render(l, disp); + // Send RGB+Depth images for local rendering + if (pl.rows > 0) display.render(pl, pdisp); display.wait(1); // Wait for both pipelines to complete @@ -282,19 +221,13 @@ static void run(const string &file) { } int main(int argc, char **argv) { - argc--; - argv++; - - // Process Arguments - auto options = read_options(&argv, &argc); - if (!findConfiguration(options["config"])) { - LOG(FATAL) << "Could not find any configuration!"; - } - process_options(options); + auto paths = ftl::configure(argc, argv, "vision"); + + config["paths"] = paths; // Choose normal or middlebury modes if (config["middlebury"]["dataset"] == "") { - run((argc > 0) ? argv[0] : ""); + run((paths.size() > 0) ? paths[0] : ""); } else { ftl::middlebury::test(config); } diff --git a/vision/src/middlebury.cpp b/vision/src/middlebury.cpp index 9252a4374dfeaeb7efae1e1c87e26776c9f9d0e4..494e6a9ff6f0703750afdafece30f0d157e65667 100644 --- a/vision/src/middlebury.cpp +++ b/vision/src/middlebury.cpp @@ -244,9 +244,7 @@ void ftl::middlebury::test(nlohmann::json &config) { // Run algorithm auto disparity = ftl::Disparity::create(config["disparity"]); - cvtColor(l, l, cv::COLOR_BGR2GRAY); - cvtColor(r, r, cv::COLOR_BGR2GRAY); - + Mat disp; disparity->compute(l,r,disp); disp.convertTo(disp, CV_32F); diff --git a/vision/src/streamer.cpp b/vision/src/streamer.cpp index ac732684691656ea9a2811666b4612814cd8d8be..7527735cb6b6d207892b0bb2b8488ae3c12d16bf 100644 --- a/vision/src/streamer.cpp +++ b/vision/src/streamer.cpp @@ -2,6 +2,7 @@ #include <ftl/streamer.hpp> #include <vector> #include <zlib.h> +// #include <lz4.h> using ftl::Streamer; using ftl::net::Universe; @@ -24,23 +25,35 @@ void Streamer::send(const Mat &rgb, const Mat &depth) { vector<unsigned char> rgb_buf; cv::imencode(".jpg", rgb, rgb_buf); + Mat d2; + depth.convertTo(d2, CV_16UC1, 16); + vector<unsigned char> d_buf; - d_buf.resize(depth.step*depth.rows); + /*d_buf.resize(d2.step*d2.rows); z_stream defstream; defstream.zalloc = Z_NULL; defstream.zfree = Z_NULL; defstream.opaque = Z_NULL; - defstream.avail_in = depth.step*depth.rows; - defstream.next_in = (Bytef *)depth.data; // input char array - defstream.avail_out = (uInt)depth.step*depth.rows; // size of output + defstream.avail_in = d2.step*d2.rows; + defstream.next_in = (Bytef *)d2.data; // input char array + defstream.avail_out = (uInt)d2.step*d2.rows; // size of output defstream.next_out = (Bytef *)d_buf.data(); // output char array deflateInit(&defstream, Z_DEFAULT_COMPRESSION); deflate(&defstream, Z_FINISH); deflateEnd(&defstream); - d_buf.resize(defstream.total_out); - //LOG(INFO) << "Depth Size = " << ((float)d_buf.size() / (1024.0f*1024.0f)); + d2.copyTo(last); + + d_buf.resize(defstream.total_out);*/ + + // LZ4 Version + // d_buf.resize(LZ4_compressBound(depth.step*depth.rows)); + // int s = LZ4_compress_default((char*)depth.data, (char*)d_buf.data(), depth.step*depth.rows, d_buf.size()); + // d_buf.resize(s); + + cv::imencode(".png", d2, d_buf); + LOG(INFO) << "Depth Size = " << ((float)d_buf.size() / (1024.0f*1024.0f)); net_.publish(uri_, rgb_buf, d_buf); }