diff --git a/components/rgbd-sources/src/sources/stereovideo/opencv.cpp b/components/rgbd-sources/src/sources/stereovideo/opencv.cpp index b395422ad99125bc0904ef2cd0e18e3355bc4df7..08e2a0f7523881e7a4e00c644a12994326d73b9a 100644 --- a/components/rgbd-sources/src/sources/stereovideo/opencv.cpp +++ b/components/rgbd-sources/src/sources/stereovideo/opencv.cpp @@ -46,7 +46,8 @@ using std::chrono::milliseconds; using std::this_thread::sleep_for; OpenCVDevice::OpenCVDevice(nlohmann::json &config, bool stereo) - : ftl::rgbd::detail::Device(config), timestamp_(0.0) { + : ftl::rgbd::detail::Device(config), timestamp_(0.0), + interpolation_(cv::INTER_CUBIC) { std::vector<ftl::rgbd::detail::DeviceDetails> devices_ = getDevices(); @@ -147,6 +148,12 @@ OpenCVDevice::OpenCVDevice(nlohmann::json &config, bool stereo) left_hm_ = cv::cuda::HostMem(dheight_, dwidth_, CV_8UC4); right_hm_ = cv::cuda::HostMem(dheight_, dwidth_, CV_8UC4); hres_hm_ = cv::cuda::HostMem(height_, width_, CV_8UC4); + + interpolation_ = value("inter_cubic", false) ? cv::INTER_CUBIC : cv::INTER_LINEAR; + on("inter_cubic", [this](){ + interpolation_ = value("inter_cubic_", false) ? + cv::INTER_CUBIC : cv::INTER_LINEAR; + }); } OpenCVDevice::~OpenCVDevice() { @@ -355,7 +362,7 @@ bool OpenCVDevice::get(ftl::rgbd::Frame &frame, cv::cuda::GpuMat &l_out, cv::cud if (hasHigherRes()) { // TODO: Use threads? - cv::resize(rfull, r, r.size(), 0.0, 0.0, cv::INTER_CUBIC); + cv::resize(rfull, r, r.size(), 0.0, 0.0, interpolation_); r_hres_out = rfull; } else { @@ -396,7 +403,7 @@ bool OpenCVDevice::get(ftl::rgbd::Frame &frame, cv::cuda::GpuMat &l_out, cv::cud // Need to resize //if (hasHigherRes()) { // TODO: Use threads? - // cv::resize(rfull, r, r.size(), 0.0, 0.0, cv::INTER_CUBIC); + // cv::resize(rfull, r, r.size(), 0.0, 0.0, interpolation_); //} } else { cv::cvtColor(frame_l_, lfull, cv::COLOR_BGR2BGRA); @@ -404,7 +411,7 @@ bool OpenCVDevice::get(ftl::rgbd::Frame &frame, cv::cuda::GpuMat &l_out, cv::cud if (hasHigherRes()) { //FTL_Profile("Frame Resize", 0.01); - cv::resize(lfull, l, l.size(), 0.0, 0.0, cv::INTER_CUBIC); + cv::resize(lfull, l, l.size(), 0.0, 0.0, interpolation_); l_hres_out.upload(hres, stream); } else { l_hres_out = cv::cuda::GpuMat(); diff --git a/components/rgbd-sources/src/sources/stereovideo/opencv.hpp b/components/rgbd-sources/src/sources/stereovideo/opencv.hpp index f33e6dc3f8eb80d43a2e09136640d3158bb0b327..37389e63f286458a1eeb4f8180c534a98e556941 100644 --- a/components/rgbd-sources/src/sources/stereovideo/opencv.hpp +++ b/components/rgbd-sources/src/sources/stereovideo/opencv.hpp @@ -64,6 +64,7 @@ class OpenCVDevice : public ftl::rgbd::detail::Device { cv::Mat frame_l_; cv::Mat frame_r_; + int interpolation_; }; } diff --git a/components/rgbd-sources/src/sources/stereovideo/pylon.cpp b/components/rgbd-sources/src/sources/stereovideo/pylon.cpp index d470f22bb31f289dad6b35bd9926ce5b20f5838e..48999538562bd26286fb258e7b131dc3d1ba4f74 100644 --- a/components/rgbd-sources/src/sources/stereovideo/pylon.cpp +++ b/components/rgbd-sources/src/sources/stereovideo/pylon.cpp @@ -24,7 +24,8 @@ using cv::Mat; using namespace Pylon; PylonDevice::PylonDevice(nlohmann::json &config) - : ftl::rgbd::detail::Device(config), ready_(false), lcam_(nullptr), rcam_(nullptr) { + : ftl::rgbd::detail::Device(config), ready_(false), lcam_(nullptr), rcam_(nullptr), + interpolation_(cv::INTER_CUBIC) { auto &inst = CTlFactory::GetInstance(); @@ -115,6 +116,12 @@ PylonDevice::PylonDevice(nlohmann::json &config) }); on("buffer_size", buffer_size_, 1); + + interpolation_ = value("inter_cubic", false) ? cv::INTER_CUBIC : cv::INTER_LINEAR; + on("inter_cubic", [this](){ + interpolation_ = value("inter_cubic", false) ? + cv::INTER_CUBIC : cv::INTER_LINEAR; + }); } PylonDevice::~PylonDevice() { @@ -299,7 +306,7 @@ bool PylonDevice::get(ftl::rgbd::Frame &frame, cv::cuda::GpuMat &l_out, cv::cuda c->rectify(rtmp2_, rfull, Channel::Right); if (hasHigherRes()) { - cv::resize(rfull, r, r.size(), 0.0, 0.0, cv::INTER_CUBIC); + cv::resize(rfull, r, r.size(), 0.0, 0.0, interpolation_); h_r = rfull; } else { @@ -340,7 +347,7 @@ bool PylonDevice::get(ftl::rgbd::Frame &frame, cv::cuda::GpuMat &l_out, cv::cuda } if (hasHigherRes()) { - cv::resize(lfull, l, l.size(), 0.0, 0.0, cv::INTER_CUBIC); + cv::resize(lfull, l, l.size(), 0.0, 0.0, interpolation_); h_l.upload(hres, stream); } else { h_l = cv::cuda::GpuMat(); diff --git a/components/rgbd-sources/src/sources/stereovideo/pylon.hpp b/components/rgbd-sources/src/sources/stereovideo/pylon.hpp index 3cc4d0908e40dd5027291b1b8688a6fe7add22eb..707e8f437dd971d71ed5ec95ed28592b2f9145be 100644 --- a/components/rgbd-sources/src/sources/stereovideo/pylon.hpp +++ b/components/rgbd-sources/src/sources/stereovideo/pylon.hpp @@ -59,6 +59,7 @@ class PylonDevice : public ftl::rgbd::detail::Device { cv::Mat rtmp_; cv::Mat rtmp2_; cv::Mat ltmp_; + int interpolation_; void _configureCamera(Pylon::CBaslerUniversalInstantCamera *cam); bool _retrieveFrames(Pylon::CGrabResultPtr &result, Pylon::CBaslerUniversalInstantCamera *cam); diff --git a/components/rgbd-sources/src/sources/stereovideo/rectification.cpp b/components/rgbd-sources/src/sources/stereovideo/rectification.cpp index edf221d6ddb0f1b0064b0522214ca403587cfecb..f755d5de89c62fc5272fc125d43ab7d2452cecfb 100644 --- a/components/rgbd-sources/src/sources/stereovideo/rectification.cpp +++ b/components/rgbd-sources/src/sources/stereovideo/rectification.cpp @@ -24,13 +24,10 @@ StereoRectification::StereoRectification(nlohmann::json &config, cv::Size image_ enabled_(false), valid_(false), interpolation_(cv::INTER_LINEAR), baseline_(0.0) { -} - -void StereoRectification::setSize(cv::Size size) { - image_resolution_ = size; - if (calibrated()) { - calculateParameters(); - } + map_l_.first.create(image_resolution_, map_format_); + map_l_.second.create(image_resolution_, map_format_); + map_r_.first.create(image_resolution_, map_format_); + map_r_.second.create(image_resolution_, map_format_); } void StereoRectification::setInterpolation(int interpolation) { @@ -53,11 +50,11 @@ void StereoRectification::setCalibration(CalibrationData &calib) { if (calib.hasCalibration(Channel::Left) && calib.hasCalibration(Channel::Right)) { calib_left_ = calib.get(Channel::Left); calib_right_ = calib.get(Channel::Right); - calculateParameters(); + updateCalibration_(); } } -void StereoRectification::calculateParameters() { +void StereoRectification::updateCalibration_() { using namespace ftl::calibration; // TODO: lock { @@ -80,34 +77,36 @@ void StereoRectification::calculateParameters() { tmp_r_ = cv::Mat(image_resolution_, CV_8UC4); } - cv::Mat K_l = calib_left_.intrinsic.matrix(image_resolution_); - cv::Mat K_r = calib_right_.intrinsic.matrix(image_resolution_); - cv::Mat dc_l = calib_left_.intrinsic.distCoeffs.Mat(); - cv::Mat dc_r = calib_right_.intrinsic.distCoeffs.Mat(); - // calculate rotation and translation from left to right using calibration cv::Mat T_l = calib_left_.extrinsic.matrix(); cv::Mat T_r = calib_right_.extrinsic.matrix(); cv::Mat T = T_r * transform::inverse(T_l); - cv::Mat R, t; - transform::getRotationAndTranslation(T, R, t); - baseline_ = cv::norm(t); + transform::getRotationAndTranslation(T, R_, t_); + baseline_ = cv::norm(t_); if (baseline_ == 0.0) { return; } + valid_ = true; + calculateParameters_(); +} + +void StereoRectification::calculateParameters_() { + if (!valid_) { return; } + + cv::Mat K_l = calib_left_.intrinsic.matrix(image_resolution_); + cv::Mat K_r = calib_right_.intrinsic.matrix(image_resolution_); + cv::Mat dc_l = calib_left_.intrinsic.distCoeffs.Mat(); + cv::Mat dc_r = calib_right_.intrinsic.distCoeffs.Mat(); // calculate rectification parameters cv::stereoRectify( K_l, dc_l, K_r, dc_r, image_resolution_, - R, t, R_l_, R_r_, P_l_, P_r_, Q_, 0, 0); + R_, t_, R_l_, R_r_, P_l_, P_r_, Q_, 0, 0); - // for CPU remap, CV_16SC2 should give best performance - // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html cv::initUndistortRectifyMap(K_l, dc_l, R_l_, P_l_, image_resolution_, - CV_16SC2, map_l_.first, map_l_.second); + map_format_, map_l_.first, map_l_.second); cv::initUndistortRectifyMap(K_r, dc_r, R_r_, P_r_, image_resolution_, - CV_16SC2, map_r_.first, map_r_.second); + map_format_, map_r_.first, map_r_.second); - valid_ = true; } void StereoRectification::rectify(cv::InputArray im, cv::OutputArray im_out, Channel c) { diff --git a/components/rgbd-sources/src/sources/stereovideo/rectification.hpp b/components/rgbd-sources/src/sources/stereovideo/rectification.hpp index 02e7aabc03b2899b7c3799c24790eec99e395aa1..d326d0d167b6cae7f06bdccd1bad6be1b6bfca40 100644 --- a/components/rgbd-sources/src/sources/stereovideo/rectification.hpp +++ b/components/rgbd-sources/src/sources/stereovideo/rectification.hpp @@ -29,10 +29,12 @@ class StereoRectification : public ftl::Configurable { public: StereoRectification(nlohmann::json &config, cv::Size image_size); - /** Set OpenCV interpolation mode, see cv::InterpolationFlags */ + /** Set OpenCV interpolation mode, see cv::InterpolationFlags. + * NOTE: Artifacts possible if modified and rectify() is called in another + * thread (no synchronization) + */ void setInterpolation(int interpolation); - void setSize(cv::Size); /** * Calculate rectification parameters from given calibration. */ @@ -62,7 +64,8 @@ public: double doff(cv::Size); protected: - void calculateParameters(); + void updateCalibration_(); // update calibration and calculate new params + void calculateParameters_(); // re-calculate rectification maps and params private: ftl::calibration::CalibrationData::Calibration calib_left_; @@ -75,6 +78,8 @@ private: bool valid_; int interpolation_; double baseline_; + cv::Mat R_; // rotation left to right + cv::Mat t_; // translation left to right cv::Mat Q_; cv::Mat R_l_; cv::Mat R_r_; @@ -84,6 +89,8 @@ private: // rectification maps for cv::remap(); should be CV_16SC2 if remap done on // CPU and CV_32SC2 for GPU (generated by calculateParameters(), used by // rectify()) + // https://docs.opencv.org/master/da/d54/group__imgproc__transform.html + int map_format_ = CV_16SC2; std::pair<cv::Mat,cv::Mat> map_l_; std::pair<cv::Mat,cv::Mat> map_r_; diff --git a/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp b/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp index 12da679572a0bbdd0933f2456aa7cffcc6d6557f..b7f3d6ce3123335fcbe77d7cf720beb27f9db6dc 100644 --- a/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp +++ b/components/rgbd-sources/src/sources/stereovideo/stereovideo.cpp @@ -185,6 +185,14 @@ void StereoVideoSource::init(const string &file) { do_update_params_ = true; }); + rectification_->setInterpolation( + host_->value("rectify_inter_cubic", false) ? cv::INTER_CUBIC : cv::INTER_LINEAR); + + host_->on("rectify_inter_cubic", [this]() { + bool v = host_->value("rectify_inter_cubic", false); + rectification_->setInterpolation(v ? cv::INTER_CUBIC : cv::INTER_LINEAR); + }); + host_->on("offset_z", [this]() { do_update_params_ = true; });