Skip to content
Snippets Groups Projects
Select Git revision
  • master
  • 1.1.20
  • 1.1.19
  • 1.1.18
  • 1.1.17
  • 1.1.16
  • 1.1.15
  • 1.1.14
  • 1.1.13
  • 1.1.12
  • 1.1.11
  • 1.1.10
  • 1.1.9
  • 1.1.8
  • 1.1.7
  • 1.1.6
  • 1.1.5
  • 1.1.4
  • 1.1.3
  • 1.1.2
  • 1.1.1
21 results

CONTRIBUTING.md

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    After you've reviewed these contribution guidelines, you'll be all set to contribute to this project.
    main.cpp 7.05 KiB
    /*
     * Copyright 2019 Nicolas Pope. All rights reserved.
     *
     * See LICENSE.
     */
    
    #define LOGURU_WITH_STREAMS 1
    #include <loguru.hpp>
    #include <ftl/configuration.hpp>
    #include <ctpl_stl.h>
    
    #include <string>
    #include <map>
    #include <vector>
    #include <fstream>
    #include <thread>
    
    #include <opencv2/opencv.hpp>
    #include <ftl/rgbd.hpp>
    #include <ftl/data/framepool.hpp>
    #include <ftl/data/creators.hpp>
    //#include <ftl/middlebury.hpp>
    #include <ftl/net/universe.hpp>
    #include <ftl/master.hpp>
    #include <nlohmann/json.hpp>
    #include <ftl/operators/disparity.hpp>
    #include <ftl/operators/detectandtrack.hpp>
    
    #include <ftl/streams/netstream.hpp>
    #include <ftl/streams/sender.hpp>
    
    #include <ftl/audio/source.hpp>
    
    #include "opencv2/imgproc.hpp"
    #include "opencv2/imgcodecs.hpp"
    #include "opencv2/highgui.hpp"
    #include "opencv2/core/utility.hpp"
    
    #ifdef HAVE_PYLON
    #include <pylon/PylonIncludes.h>
    #endif
    
    #ifdef WIN32
    #pragma comment(lib, "Rpcrt4.lib")
    #endif
    
    using ftl::rgbd::Source;
    using ftl::rgbd::Camera;
    using ftl::codecs::Channel;
    using ftl::net::Universe;
    using std::string;
    using std::vector;
    using std::map;
    using std::condition_variable;
    using std::this_thread::sleep_for;
    using std::chrono::milliseconds;
    using cv::Mat;
    using json = nlohmann::json;
    
    static void run(ftl::Configurable *root) {
    	Universe *net = ftl::create<Universe>(root, "net");
    
    	ftl::timer::setHighPrecision(true);
    
    	if (root->value("time_master", false)) {
    		net->bind("time_master", [net]() {
    			return net->id();
    		});
    		LOG(INFO) << "Becoming a time master";
    	}
    
    	if (root->get<string>("time_peer")) {
    		if (!net->connect(*root->get<string>("time_peer"))->waitConnection()) {
    			LOG(ERROR) << "Could not connect to time master";
    		} else {
    			LOG(INFO) << "Connected to time master";
    		}
    	}
    
    	auto opt_time_master = net->findOne<ftl::UUID>(string("time_master"));
    	ftl::UUID time_peer(0);
    	if (opt_time_master) {
    		time_peer = *opt_time_master;
    		LOG(INFO) << "Found a time master: " << time_peer.to_string();
    	}
    	int sync_counter = 0;
    
    	ftl::ctrl::Master ctrl(root, net);
    
    	// Sync clocks!
    	auto timer = ftl::timer::add(ftl::timer::kTimerMain, [&time_peer,&sync_counter,net](int64_t ts) {
    		if (sync_counter-- <= 0 && time_peer != ftl::UUID(0) ) {
    			sync_counter = 20;
    			auto start = std::chrono::high_resolution_clock::now();
    
    			try {
    				net->asyncCall<int64_t>(time_peer, "__ping__", [start](const int64_t &mastertime) {
    					auto elapsed = std::chrono::high_resolution_clock::now() - start;
    					int64_t latency = std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count();
    					auto clock_adjust = mastertime + ((latency+500)/2000) - ftl::timer::get_time();
    
    					//LOG(INFO) << "LATENCY: " << float(latency)/1000.0f << "ms";
    
    					if (clock_adjust != 0) {
    						LOG(INFO) << "Clock adjustment: " << clock_adjust << ", latency=" << float(latency)/1000.0f << "ms";
    						ftl::timer::setClockAdjustment(clock_adjust);
    					}		
    				});
    			} catch (const std::exception &e) {
    				LOG(ERROR) << "Ping failed, could not time sync: " << e.what();
    				return true;
    			}
    		}
    		return true;
    	});
    
    	auto paths = root->get<vector<string>>("paths");
    	string file = "";
    	//if (paths && (*paths).size() > 0) file = (*paths)[(*paths).size()-1];
    
    	for (auto &x : *paths) {
    		//LOG(INFO) << "PATH - " << x;
    		if (x != "") {
    			ftl::URI uri(x);
    			if (uri.isValid()) {
    				switch (uri.getScheme()) {
    				case ftl::URI::SCHEME_WS		:
    				case ftl::URI::SCHEME_TCP		: net->connect(x)->waitConnection(); break;
    				case ftl::URI::SCHEME_DEVICE	:
    				case ftl::URI::SCHEME_FILE		: file = x; break;
    				default: break;
    				}
    			}
    		}
    	}
    
    	Source *source = nullptr;
    	source = ftl::create<Source>(root, "source", net);
    	if (file != "") {
    		//source->set("uri", file);
    		ftl::URI uri(file);
    		uri.to_json(source->getConfig());
    		source->set("uri", uri.getBaseURI());
    	}
    	
    	//ftl::stream::Sender *sender = ftl::create<ftl::stream::Sender>(root, "sender");
    	ftl::stream::Net *outstream = ftl::create<ftl::stream::Net>(root, "stream", net);
    	outstream->set("uri", outstream->getID());
    	outstream->begin();
    	//sender->setStream(outstream);
    
    	/*auto *grp = new ftl::rgbd::Group();
    	source->setChannel(Channel::Depth);
    	grp->addSource(source);*/
    
    	ftl::data::Pool pool(2,5);
    	auto creator = pool.creator<ftl::data::IntervalFrameCreator>(0, source);
    
    	// Listen for any flush events for frameset 0
    	auto flushh = pool.group(0).onFlush([](ftl::data::Frame &f, ftl::codecs::Channel c) {
    		// Send to sender for encoding
    
    		if (c == ftl::codecs::Channel::Colour) {
    			cv::Mat tmp;
    			f.get<cv::cuda::GpuMat>(ftl::codecs::Channel::Colour).download(tmp);
    			cv::imshow("Image", tmp);
    			cv::waitKey(1);
    		}
    		return true;
    	});
    
    	// Callback for when a source has populated a frame with data
    	auto h = source->onFrame([](ftl::data::Frame &f) {
    		// Lock and send colour right now to encode in parallel
    		f.flush(ftl::codecs::Channel::Colour);
    
    		// Do pipeline here...
    		return true;
    	});
    
    	// Start the timed generation of frames
    	creator.start();
    
    	int stats_count = 0;
    
    	/*grp->onFrameSet([sender,&stats_count](ftl::rgbd::FrameSet &fs) {
    		fs.id = 0;
    		sender->post(fs);
    
    		if (--stats_count <= 0) {
    			auto [fps,latency] = ftl::rgbd::Builder::getStatistics();
    			LOG(INFO) << "Frame rate: " << fps << ", Latency: " << latency;
    			stats_count = 20;
    		}
    		return true;
    	});
    
    	// TODO: TEMPORARY
    	ftl::audio::Source *audioSrc = ftl::create<ftl::audio::Source>(root, "audio_test");
    	audioSrc->onFrameSet([sender](ftl::audio::FrameSet &fs) {
    		sender->post(fs);
    		return true;
    	});
    	
    	auto pipeline = ftl::config::create<ftl::operators::Graph>(root, "pipeline");
    	pipeline->append<ftl::operators::DetectAndTrack>("facedetection")->value("enabled", false);
    	pipeline->append<ftl::operators::ArUco>("aruco")->value("enabled", false);
    	pipeline->append<ftl::operators::DepthChannel>("depth");  // Ensure there is a depth channel
    	grp->addPipeline(pipeline);*/
    	
    	net->start();
    
    	LOG(INFO) << "Running...";
    	ftl::timer::start(true);
    	LOG(INFO) << "Stopping...";
    	ctrl.stop();
    	
    	net->shutdown();
    
    	ftl::pool.stop();
    
    	//delete grp;
    	//delete sender;
    	delete outstream;
    
    	//delete source;  // TODO(Nick) Add ftl::destroy
    	delete net;
    }
    
    static void threadSetCUDADevice() {
    	// Ensure all threads have correct cuda device
    	std::atomic<int> ijobs = 0;
    	for (int i=0; i<ftl::pool.size(); ++i) {
    		ftl::pool.push([&ijobs](int id) {
    			ftl::cuda::setDevice();
    			++ijobs;
    			while (ijobs < ftl::pool.size()) std::this_thread::sleep_for(std::chrono::milliseconds(10));
    		});
    	}
    	while (ijobs < ftl::pool.size()) std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    
    int main(int argc, char **argv) {
    #ifdef HAVE_PYLON
    	Pylon::PylonAutoInitTerm autoInitTerm;
    #endif
    
    #ifdef WIN32
    	SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
    #endif
    	std::cout << "FTL Vision Node " << FTL_VERSION_LONG << std::endl;
    	auto root = ftl::configure(argc, argv, "vision_default");
    
    	// Use other GPU if available.
    	//ftl::cuda::setDevice(ftl::cuda::deviceCount()-1);
    	
    	std::cout << "Loading..." << std::endl;
    	run(root);
    
    	delete root;
    	LOG(INFO) << "Terminating with code " << ftl::exit_code;
    	LOG(INFO) << "Branch: " << ftl::branch_name;
    	return ftl::exit_code;
    }