diff --git a/CMakeLists.txt b/CMakeLists.txt index ac657f10407f1a6ce66f2543cb47418709538dd1..7703869c258de2efcc9a6ba5b20dad79ca653dea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -82,6 +82,11 @@ find_library(UUID_LIBRARIES NAMES uuid libuuid) else() endif() +# Check for optional opencv components +set(CMAKE_REQUIRED_INCLUDES ${OpenCV_INCLUDE_DIRS}) +check_include_file_cxx("opencv2/viz.hpp" HAVE_VIZ) +check_include_file_cxx("opencv2/cudastereo.hpp" HAVE_OPENCVCUDA) + # Optional source problem check find_program(CPPCHECK_FOUND cppcheck) if (CPPCHECK_FOUND) @@ -110,6 +115,7 @@ SET(CMAKE_USE_RELATIVE_PATHS ON) add_subdirectory(net) add_subdirectory(cv-node) +add_subdirectory(rep-server) ### Generate Build Configuration Files ========================================= diff --git a/cv-node/CMakeLists.txt b/cv-node/CMakeLists.txt index cafa37799cef27a37f5b9358116ec8c8b7e9d390..926be4de8cd1ac4e0fd77ea7b5acb896d64161cc 100644 --- a/cv-node/CMakeLists.txt +++ b/cv-node/CMakeLists.txt @@ -4,11 +4,6 @@ include_directories(${PROJECT_SOURCE_DIR}/cv-node/include) add_subdirectory(lib) -# Check for optional opencv components -set(CMAKE_REQUIRED_INCLUDES ${OpenCV_INCLUDE_DIRS}) -check_include_file_cxx("opencv2/viz.hpp" HAVE_VIZ) -check_include_file_cxx("opencv2/cudastereo.hpp" HAVE_OPENCVCUDA) - set(CVNODESRC ../common/cpp/src/config.cpp src/main.cpp @@ -17,6 +12,7 @@ set(CVNODESRC src/sync.cpp src/display.cpp src/disparity.cpp + src/streamer.cpp src/middlebury.cpp src/algorithms/rtcensus.cpp src/algorithms/rtcensus_sgm.cpp diff --git a/cv-node/config/config.json b/cv-node/config/config.json index 1979288d6ae9921c0b25fa14a4de2be2f077cde3..104b18dc607ed2328c183e35292e3251e33e27e0 100644 --- a/cv-node/config/config.json +++ b/cv-node/config/config.json @@ -48,11 +48,25 @@ "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": { + "peers": ["tcp://localhost:9001"] + }, + "source": "ftl://utu.fi/dummy/rgb-d" } } diff --git a/cv-node/src/main.cpp b/cv-node/src/main.cpp index ddc805e4d901a519ca0c72ab645004a60756264f..31e1c4100689d47ed0a7b0b64cca45336b2a915f 100644 --- a/cv-node/src/main.cpp +++ b/cv-node/src/main.cpp @@ -19,6 +19,8 @@ #include <ftl/disparity.hpp> #include <ftl/middlebury.hpp> #include <ftl/display.hpp> +#include <ftl/streamer.hpp> +#include <ftl/net/universe.hpp> #include <nlohmann/json.hpp> #include "opencv2/imgproc.hpp" @@ -33,8 +35,10 @@ using ftl::Calibrate; using ftl::LocalSource; using ftl::Display; +using ftl::Streamer; using ftl::Disparity; using ftl::SyncSource; +using ftl::net::Universe; using std::string; using std::vector; using std::map; @@ -114,7 +118,7 @@ static void process_options(const map<string, string> &opts) { } static void run(const string &file) { - // TODO(nick) Initiate the network + Universe net(config["net"]); LocalSource *lsrc; if (file != "") { @@ -142,6 +146,7 @@ static void run(const string &file) { Mat l, r, disp; Display display(calibrate, config["display"]); + Streamer stream(net, config["stream"]); while (display.active()) { // Read calibrated images. @@ -160,7 +165,7 @@ static void run(const string &file) { // Send RGB+Depth images for local rendering display.render(l, disp); - // streamer.send(l, disparity32F); + stream.send(l, disp); } } diff --git a/rep-server/CMakeLists.txt b/rep-server/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..164e2f2f429f53c69436960770497d186d02aa27 --- /dev/null +++ b/rep-server/CMakeLists.txt @@ -0,0 +1,17 @@ +# Need to include staged files and libs +include_directories(${PROJECT_SOURCE_DIR}/rep-server/include) +#include_directories(${PROJECT_BINARY_DIR}) + + +set(REPSRC + ../common/cpp/src/config.cpp + src/main.cpp +) + +add_executable(rep-server ${REPSRC}) +add_dependencies(rep-server ftlnet) + +#target_include_directories(cv-node PUBLIC ${PROJECT_SOURCE_DIR}/include) +target_link_libraries(rep-server Threads::Threads ${OpenCV_LIBS} glog::glog ftlnet) + + diff --git a/rep-server/src/main.cpp b/rep-server/src/main.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b01fcf16b0cc01685fe151b11088432706b05a74 --- /dev/null +++ b/rep-server/src/main.cpp @@ -0,0 +1,152 @@ +/* + * Copyright 2019 Nicolas Pope. All rights reserved. + * + * See LICENSE. + */ + +#include <glog/logging.h> +#include <ftl/config.h> + +#include <string> +#include <map> +#include <vector> +#include <fstream> +#include <thread> +#include <chrono> +#include <mutex> + +#include <opencv2/opencv.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::net::Universe; +using std::string; +using std::vector; +using std::map; +using cv::Mat; +using json = nlohmann::json; +using std::ifstream; +using std::this_thread::sleep_for; +using std::chrono::milliseconds; +using std::mutex; +using std::unique_lock; + +// 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; + config = config["representation"]; + 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) { + Universe net(config["net"]); + Mat rgb; + mutex m; + + // Make sure connections are complete + sleep_for(milliseconds(500)); + + net.subscribe(config["source"], [&rgb,&m](const vector<unsigned char> &jpg) { + unique_lock<mutex> lk(m); + cv::imdecode(jpg, cv::IMREAD_COLOR, &rgb); + //LOG(INFO) << "Received JPG : " << rgb.cols; + }); + + while (true) { + unique_lock<mutex> lk(m); + if (rgb.cols > 0) { + cv::imshow("RGB", rgb); + } + lk.unlock(); + if (cv::waitKey(5) == 27) break; + } +} + +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); + + run((argc > 0) ? argv[0] : ""); +} +