Skip to content
Snippets Groups Projects
calibrate.cpp 4.2 KiB
Newer Older
Nicolas Pope's avatar
Nicolas Pope committed
/*
 * Copyright 2019 Nicolas Pope
 */

Nicolas Pope's avatar
Nicolas Pope committed
#include <loguru.hpp>
Nicolas Pope's avatar
Nicolas Pope committed
#include <ftl/config.h>
#include <ftl/configuration.hpp>
Sebastian Hahta's avatar
Sebastian Hahta committed
#include <ftl/threads.hpp>
Nicolas Pope's avatar
Nicolas Pope committed

#include <iostream>
#include <sstream>
#include <string>
#include <ctime>

#include "calibrate.hpp"

#include <opencv2/core.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/calib3d.hpp>

using ftl::rgbd::detail::Calibrate;
Nicolas Pope's avatar
Nicolas Pope committed
using cv::FileStorage;
Nicolas Pope's avatar
Nicolas Pope committed
using cv::INTER_LINEAR;
Nicolas Pope's avatar
Nicolas Pope committed
using cv::FileNode;
using cv::FileNodeIterator;
Nicolas Pope's avatar
Nicolas Pope committed
using cv::Mat;
using cv::cuda::GpuMat;
using cv::cuda::Stream;

Nicolas Pope's avatar
Nicolas Pope committed
using cv::Size;
Nicolas Pope's avatar
Nicolas Pope committed
using cv::Point2f;
using cv::Point3f;
using cv::Matx33d;
using cv::Scalar;
Nicolas Pope's avatar
Nicolas Pope committed
using std::string;
using std::vector;

Calibrate::Calibrate(nlohmann::json &config, cv::Size image_size, cv::cuda::Stream &stream) : ftl::Configurable(config) {
	std::pair<Mat, Mat> map1, map2;
	calibrated_ = _loadCalibration(image_size, map1, map2);
	if (calibrated_) {
Sebastian Hahta's avatar
Sebastian Hahta committed
		_updateIntrinsics();
		LOG(INFO) << "Calibration loaded from file";
	}
	else {
		LOG(WARNING) << "Calibration not loaded";
	}
Sebastian Hahta's avatar
Sebastian Hahta committed
	
	this->on("use_intrinsics", [this](const ftl::config::Event &e) {
		_updateIntrinsics();
	});
}

void Calibrate::_updateIntrinsics() {
	Mat R1, R2, P1, P2;
	std::pair<Mat, Mat> map1, map2;

	if (this->value("use_intrinsics", true)) {
		R1 = R1_;
		R2 = R2_;
		P1 = P1_;
		P2 = P2_;
	}
	else {
		R1 = Mat::eye(Size(3, 3), CV_64FC1);
		R2 = R1;
		P1 = M1_;
		P2 = M2_;
	}

	initUndistortRectifyMap(M1_, D1_, R1, P1, img_size_, CV_32FC1, map1.first, map2.first);
	initUndistortRectifyMap(M2_, D2_, R2, P2, img_size_, CV_32FC1, map1.second, map2.second);
	
	map1_gpu_.first.upload(map1.first);
	map1_gpu_.second.upload(map1.second);
	map2_gpu_.first.upload(map2.first);
	map2_gpu_.second.upload(map2.second);
bool Calibrate::_loadCalibration(cv::Size img_size, std::pair<Mat, Mat> &map1, std::pair<Mat, Mat> &map2) {
	FileStorage fs;
	// reading intrinsic parameters
	auto ifile = ftl::locateFile(value("intrinsics", std::string("intrinsics.yml")));
	if (ifile) {
Nicolas Pope's avatar
Nicolas Pope committed
		fs.open((*ifile).c_str(), FileStorage::READ);
		if (!fs.isOpened()) {
			LOG(WARNING) << "Could not open intrinsics file";
			return false;
Nicolas Pope's avatar
Nicolas Pope committed
		}
		
		LOG(INFO) << "Intrinsics from: " << *ifile;
	}
	else {
		LOG(WARNING) << "Calibration intrinsics file not found";
Nicolas Pope's avatar
Nicolas Pope committed
		return false;
Nicolas Pope's avatar
Nicolas Pope committed
	fs["M"] >> M1_;
	fs["D"] >> D1_;
Nicolas Pope's avatar
Nicolas Pope committed
	M2_ = M1_;
	D2_ = D1_;
Nicolas Pope's avatar
Nicolas Pope committed

	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;
Nicolas Pope's avatar
Nicolas Pope committed
		}
		
		LOG(INFO) << "Extrinsics from: " << *efile;
	} else {
		LOG(WARNING) << "Calibration extrinsics file not found";
		return false;
Nicolas Pope's avatar
Nicolas Pope committed
	fs["R"] >> R_;
	fs["T"] >> T_;
	fs["R1"] >> R1_;
	fs["R2"] >> R2_;
	fs["P1"] >> P1_;
	fs["P2"] >> P2_;
	fs["Q"] >> Q_;
Nicolas Pope's avatar
Nicolas Pope committed
	P_ = P1_;

	img_size_ = img_size;
	// cv::cuda::remap() works only with CV_32FC1
Nicolas Pope's avatar
Nicolas Pope committed
	initUndistortRectifyMap(M1_, D1_, R1_, P1_, img_size_, CV_32FC1, map1.first, map2.first);
	initUndistortRectifyMap(M2_, D2_, R2_, P2_, img_size_, CV_32FC1, map1.second, map2.second);
Nicolas Pope's avatar
Nicolas Pope committed
void Calibrate::updateCalibration(const ftl::rgbd::Camera &p) {
	std::pair<Mat, Mat> map1, map2;

	Q_.at<double>(3,2) = 1.0 / p.baseline;
Nicolas Pope's avatar
Nicolas Pope committed
	Q_.at<double>(2,3) = p.fx;
	Q_.at<double>(0,3) = p.cx;
	Q_.at<double>(1,3) = p.cy;
Nicolas Pope's avatar
Nicolas Pope committed
	// FIXME:(Nick) Update camera matrix also...
Nicolas Pope's avatar
Nicolas Pope committed

	initUndistortRectifyMap(M1_, D1_, R1_, P1_, img_size_, CV_32FC1, map1.first, map2.first);
	initUndistortRectifyMap(M2_, D2_, R2_, P2_, img_size_, CV_32FC1, map1.second, map2.second);

	// CHECK Is this thread safe!!!!
	map1_gpu_.first.upload(map1.first);
	map1_gpu_.second.upload(map1.second);
	map2_gpu_.first.upload(map2.first);
	map2_gpu_.second.upload(map2.second);
}

void Calibrate::rectifyStereo(GpuMat &l, GpuMat &r, Stream &stream) {
	// cv::cuda::remap() can not use same Mat for input and output
	
	GpuMat l_tmp(l.size(), l.type());
	GpuMat r_tmp(r.size(), r.type());
	cv::cuda::remap(l, l_tmp, map1_gpu_.first, map2_gpu_.first, cv::INTER_LINEAR, 0, cv::Scalar(), stream);
	cv::cuda::remap(r, r_tmp, map1_gpu_.second, map2_gpu_.second, cv::INTER_LINEAR, 0, cv::Scalar(), stream);
	stream.waitForCompletion();
	l = l_tmp;
	r = r_tmp;
Nicolas Pope's avatar
Nicolas Pope committed
}

bool Calibrate::isCalibrated() {
	return calibrated_;