Skip to content
Snippets Groups Projects
main.cpp 5.92 KiB
Newer Older
/*
 * Copyright 2019 Nicolas Pope. All rights reserved.
 *
 * See LICENSE.
 */

Nicolas Pope's avatar
Nicolas Pope committed
#define LOGURU_WITH_STREAMS 1
#include <loguru.hpp>
#include <ftl/configuration.hpp>
Nicolas Pope's avatar
Nicolas Pope committed
#include <ftl/depth_camera.hpp>
#include <ftl/scene_rep_hash_sdf.hpp>
Nicolas Pope's avatar
Nicolas Pope committed
#include <ftl/rgbd.hpp>
Nicolas Pope's avatar
Nicolas Pope committed
#include <ftl/virtual_source.hpp>
Sebastian Hahta's avatar
Sebastian Hahta committed

Nicolas Pope's avatar
Nicolas Pope committed
// #include <zlib.h>

#include <string>
#include <vector>
#include <thread>
#include <chrono>
#include <mutex>

#include <opencv2/opencv.hpp>
#include <ftl/net/universe.hpp>
Nicolas Pope's avatar
Nicolas Pope committed
#include <ftl/rgbd_display.hpp>
Nicolas Pope's avatar
Nicolas Pope committed
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core/utility.hpp>

#include <ftl/utility/opencv_to_pcl.hpp>
#include <ftl/registration.hpp>
Nicolas Pope's avatar
Nicolas Pope committed
#ifdef HAVE_PCL
#include <pcl/point_cloud.h>
#include <pcl/common/transforms.h>
#include <pcl/filters/uniform_sampling.h>
#endif
Sebastian Hahta's avatar
Sebastian Hahta committed

Nicolas Pope's avatar
Nicolas Pope committed
using ftl::rgbd::Display;
Nicolas Pope's avatar
Nicolas Pope committed
using ftl::rgbd::RGBDSource;
Nicolas Pope's avatar
Nicolas Pope committed
using ftl::config::json_t;
Sebastian Hahta's avatar
Sebastian Hahta committed

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

Nicolas Pope's avatar
Nicolas Pope committed
using std::vector;

using cv::Mat;
Sebastian Hahta's avatar
Sebastian Hahta committed

using ftl::registration::loadTransformations;
using ftl::registration::saveTransformations;
Nicolas Pope's avatar
Nicolas Pope committed
struct Cameras {
	RGBDSource *source;
	DepthCameraData gpu;
	DepthCameraParams params;
};

Nicolas Pope's avatar
Nicolas Pope committed
static void run(ftl::Configurable *root) {
	Universe *net = ftl::create<Universe>(root, "net");
Sebastian Hahta's avatar
Sebastian Hahta committed
	
	// Make sure connections are complete
	// sleep_for(milliseconds(500));
	// TODO: possible to do more reliably?
Nicolas Pope's avatar
Nicolas Pope committed
	net->waitConnections();
Sebastian Hahta's avatar
Sebastian Hahta committed
	
Nicolas Pope's avatar
Nicolas Pope committed
	std::vector<Cameras> inputs;
	auto sources = root->get<vector<json_t>>("sources");

	if (!sources) {
Sebastian Hahta's avatar
Sebastian Hahta committed
		LOG(ERROR) << "No sources configured!";
		return;
	}
Nicolas Pope's avatar
Nicolas Pope committed
	// TODO Allow for non-net source types
	for (auto &src : *sources) {
		RGBDSource *in = ftl::rgbd::RGBDSource::create(src, net);
Nicolas Pope's avatar
Nicolas Pope committed
		if (!in) {
			LOG(ERROR) << "Unrecognized source: " << src;
Nicolas Pope's avatar
Nicolas Pope committed
		} else {
Nicolas Pope's avatar
Nicolas Pope committed
			auto &cam = inputs.emplace_back();
			cam.source = in;
			cam.params.fx = in->getParameters().fx;
			cam.params.fy = in->getParameters().fy;
			cam.params.mx = -in->getParameters().cx;
			cam.params.my = -in->getParameters().cy;
			cam.params.m_imageWidth = in->getParameters().width;
			cam.params.m_imageHeight = in->getParameters().height;
			cam.params.m_sensorDepthWorldMax = in->getParameters().maxDepth;
			cam.params.m_sensorDepthWorldMin = in->getParameters().minDepth;
			cam.gpu.alloc(cam.params);
			
			LOG(INFO) << (string) src["uri"] << " loaded " << cam.params.fx;

	// TODO	move this block in its own method and add automated tests
	//		for error cases
	std::optional<json_t> merge = root->get<json_t>("merge");
	if (!merge) {
		LOG(WARNING) << "Input merging not configured, using only first input in configuration";
		inputs = { inputs[0] };

	if (inputs.size() > 1) {
		std::map<std::string, Eigen::Matrix4f> transformations;

		if ((*merge)["register"]) {
			LOG(INFO) << "Registration requested";

			ftl::registration::Registration *reg = ftl::registration::ChessboardRegistration::create(*merge);
			for (auto &input : inputs) { 
				while(!input.source->isReady()) { std::this_thread::sleep_for(std::chrono::milliseconds(50)); }
				reg->addSource(input.source);
			}
			
			reg->run();
			if (reg->findTransformations(transformations)) {
				if (!saveTransformations(string(FTL_LOCAL_CONFIG_ROOT) + "/registration.json", transformations)) {
					LOG(ERROR) << "Error saving new registration";
				};
			else {
				LOG(ERROR) << "Registration failed";
			}

			free(reg);
		else {
			if (loadTransformations(string(FTL_LOCAL_CONFIG_ROOT) + "/registration.json", transformations)) {
				LOG(INFO) << "Loaded camera trasformations from file";
			}
			else {
				LOG(ERROR) << "Error loading camera transformations from file";
			}
		for (auto &input : inputs) {
			string uri = input.source->getURI();
			auto T = transformations.find(uri);
			if (T == transformations.end()) {
				LOG(ERROR) << "Camera pose for " + uri + " not found in transformations";
				LOG(WARNING) << "Using only first configured source";
				// TODO: use target source if configured and found
				inputs = { inputs[0] };
				inputs[0].source->setPose(Eigen::Matrix4f::Identity());
				break;
			}
			input.source->setPose(T->second);

	// Displays and Inputs configured
	for (auto &input : inputs) { LOG(INFO) << "    " + (string) input.source->getURI(); }
Nicolas Pope's avatar
Nicolas Pope committed
	ftl::rgbd::Display *display = ftl::create<ftl::rgbd::Display>(root, "display");
	ftl::rgbd::VirtualSource *virt = ftl::create<ftl::rgbd::VirtualSource>(root, "virtual", net);
	ftl::voxhash::SceneRep *scene = ftl::create<ftl::voxhash::SceneRep>(root, "voxelhash");
	virt->setScene(scene);
	display->setSource(virt);
Nicolas Pope's avatar
Nicolas Pope committed

	unsigned char frameCount = 0;
	bool paused = false;

	// Keyboard camera controls
Nicolas Pope's avatar
Nicolas Pope committed
	display->onKey([&paused](int key) {
Nicolas Pope's avatar
Nicolas Pope committed
		if (key == 32) paused = !paused;
	});

	int active = inputs.size();
Nicolas Pope's avatar
Nicolas Pope committed
	while (active > 0 && display->active()) {
Sebastian Hahta's avatar
Sebastian Hahta committed
		active = 0;
Nicolas Pope's avatar
Nicolas Pope committed
		if (!paused) {
			//net.broadcast("grab");  // To sync cameras
Nicolas Pope's avatar
Nicolas Pope committed
			scene->nextFrame();
Nicolas Pope's avatar
Nicolas Pope committed
			for (size_t i = 0; i < inputs.size(); i++) {
Nicolas Pope's avatar
Nicolas Pope committed
				// Get the RGB-Depth frame from input
Nicolas Pope's avatar
Nicolas Pope committed
				RGBDSource *input = inputs[i].source;
				Mat rgb, depth;
				input->grab();
Nicolas Pope's avatar
Nicolas Pope committed
				input->getRGBD(rgb,depth);
				
				active += 1;

				if (depth.cols == 0) continue;

Nicolas Pope's avatar
Nicolas Pope committed
				// Must be in RGBA for GPU
Nicolas Pope's avatar
Nicolas Pope committed
				Mat rgba;
				cv::cvtColor(rgb,rgba, cv::COLOR_BGR2BGRA);

				inputs[i].params.flags = frameCount;

				// Send to GPU and merge view into scene
				inputs[i].gpu.updateParams(inputs[i].params);
				inputs[i].gpu.updateData(depth, rgba);
Nicolas Pope's avatar
Nicolas Pope committed
				scene->integrate(inputs[i].source->getPose(), inputs[i].gpu, inputs[i].params, nullptr);
Nicolas Pope's avatar
Nicolas Pope committed
			}
		} else {
			active = 1;
Nicolas Pope's avatar
Nicolas Pope committed
		}
Nicolas Pope's avatar
Nicolas Pope committed

		frameCount++;
Nicolas Pope's avatar
Nicolas Pope committed
		display->update();
Nicolas Pope's avatar
Nicolas Pope committed
	run(ftl::configure(argc, argv, "reconstruction_default"));
Nicolas Pope's avatar
Nicolas Pope committed
}