2 * Copyright (c) 2021 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include "dfs_opencv_private.h"
19 #include <opencv2/core/persistence.hpp>
20 #include <opencv2/imgcodecs.hpp>
22 #define MAX_THREADS_NUM 2
23 #define ENABLE_CALIBRATION 1
25 namespace DfsAdaptationImpl
29 mDfsOcvExtra(nullptr),
41 mIsStereoCalibrated(false),
42 mUpdateStereoCalibration(false),
43 mImageSize(cv::Size(0,0)),
55 mControlJob.notify_all();
57 for (auto& t : mThreadPool) {
58 LOGI("thread joinable: %s", t.joinable() ? "true" : "false");
65 void DfsOCV::InitializeStereoCalibration(std::string filepath)
69 cv::Mat intrinsicTest;
71 cv::FileStorage fs(filepath, cv::FileStorage::READ);
73 LOGE("Failed to open calib file %s", filepath.c_str());
74 throw std::ios_base::failure("calibration");
77 fs["LEFT_CAM_INTRINSIC"] >> mStereoParam.baceCamera.intrinsic;
78 fs["LEFT_CAM_DISTCOEFFS"] >> mStereoParam.baceCamera.distCoeffs;
80 fs["RIGHT_CAM_INTRINSIC"] >> mStereoParam.extraCamera.intrinsic;
81 fs["RIGHT_CAM_DISTCOEFFS"] >> mStereoParam.extraCamera.distCoeffs;
83 fs["STEREO_TRANSLATION"] >> mStereoParam.translation;
84 fs["STEREO_ROTATION"] >> mStereoParam.rotation;
86 } catch (const std::exception& e) {
87 LOGE("Failed to read calibration data %s", e.what());
88 throw std::ios_base::failure("calibration");
94 void DfsOCV::InitRectifyMap()
99 cv::Mat newBaseCameraIntrinsic = cv::getOptimalNewCameraMatrix(
100 mStereoParam.baceCamera.intrinsic,
101 mStereoParam.baceCamera.distCoeffs,
105 cv::Mat newExtraCameraIntrinsic = cv::getOptimalNewCameraMatrix(
106 mStereoParam.extraCamera.intrinsic,
107 mStereoParam.extraCamera.distCoeffs,
111 cv::Mat extraCameraRotation;
112 cv::Rodrigues(mStereoParam.rotation, extraCameraRotation);
114 cv::Mat baseRotation, extraRotation; // 3x3
115 cv::Mat baseProjection, extraProjection; // 3x4
116 cv::Mat disp2Depth; // 4x4
118 cv::stereoRectify(mStereoParam.baceCamera.intrinsic,
119 mStereoParam.baceCamera.distCoeffs,
120 mStereoParam.extraCamera.intrinsic,
121 mStereoParam.extraCamera.distCoeffs,
124 mStereoParam.translation,
131 cv::initUndistortRectifyMap(mStereoParam.baceCamera.intrinsic,
132 mStereoParam.baceCamera.distCoeffs,
134 newBaseCameraIntrinsic,
140 cv::initUndistortRectifyMap(mStereoParam.extraCamera.intrinsic,
141 mStereoParam.extraCamera.distCoeffs,
143 newExtraCameraIntrinsic,
149 mIsStereoCalibrated = true;
150 } catch (const std::exception& e) {
151 LOGE("Failed to InitRectifyMap");
159 void DfsOCV::Initialize(DfsParameter& param, size_t width, size_t height,
160 size_t minDisp, size_t maxDisp, std::string stereoConfigPath)
165 mImageSize = cv::Size(width, height);
166 mMinDisparity = minDisp;
167 mNumDisparities = static_cast<int>(static_cast<float>(maxDisp - minDisp+1)*mDispShiftInv);
168 mNumDisparities *= mDispShift;
169 LOGE("mMinDisparity: %zd, mNumDisparities: %zd", mMinDisparity, mNumDisparities);
171 mMinDisparity >>= mDownScale;
172 mNumDisparities >>= mDownScale;
174 mDfsOcv = cv::StereoSGBM::create(mMinDisparity,
181 10, // uniquenessRatio
182 50, // speckleWindowSize
185 this->SetParameters();
187 #if ENABLE_CALIBRATION
188 if (!stereoConfigPath.empty()) {
190 this->InitializeStereoCalibration(stereoConfigPath);
191 this->InitRectifyMap();
192 } catch (const std::exception& e) {
197 mDfsPostOcv = cv::ximgproc::createDisparityWLSFilter(mDfsOcv);
198 mDfsOcvExtra = cv::ximgproc::createRightMatcher(mDfsOcv);
199 mDfsPostOcv->setLRCthresh(24.0);
201 mDfsPostOcv->setSigmaColor(1.5);
202 mDfsPostOcv->setLambda(8000);
203 mDfsPostOcv->setDepthDiscontinuityRadius((int)ceil(0.5*5));
206 mThreadPool.reserve(MAX_THREADS_NUM - 1);
207 mThreadPool.emplace_back([this](){this->Runner();});
209 mThreadPool.reserve(MAX_THREADS_NUM);
210 mThreadPool.emplace_back([this](){this->Runner();});
211 mThreadPool.emplace_back([this](){this->Runner();});
216 void DfsOCV::SetParameters()
220 mDfsOcv->setMinDisparity(mMinDisparity);
221 mDfsOcv->setNumDisparities(mNumDisparities);
222 mDfsOcv->setBlockSize(mBlockSize);
223 mDfsOcv->setP1(mP1 * mBlockSize * mBlockSize);
224 mDfsOcv->setP2(mP2 * mBlockSize * mBlockSize);
225 mDfsOcv->setPreFilterCap(mPreFilterCap);
227 mDfsOcv->setMode(cv::StereoSGBM::MODE_SGBM_3WAY);
231 int DfsOCV::ConvertDfsDataTypeToCV(int type)
235 case DFS_DATA_TYPE_UINT8C1:
237 case DFS_DATA_TYPE_UINT8C3:
240 LOGE("Invalide type");
248 bool DfsOCV::computeL(const cv::Mat& baseMat, const cv::Mat& extraMat, cv::Mat& disp)
252 mDfsOcv->compute(baseMat, extraMat, disp);
258 bool DfsOCV::computeR(const cv::Mat& baseMat, const cv::Mat& extraMat, cv::Mat& disp)
262 mDfsOcvExtra->compute(baseMat, extraMat, disp);
268 void DfsOCV::Runner()
271 std::unique_lock<std::mutex> lock(mMutexJob);
272 mControlJob.wait(lock, [this]() {return !mJobs.empty() || mIsStopAll;});
273 if (mIsStopAll && mJobs.empty()) {
274 LOGI("Stop and all jobs are done");
278 std::function<void()> job = std::move(mJobs.front());
286 template <class F, class... Args>
287 std::future<bool> DfsOCV::EnqueueJob(F f, Args... args)
291 LOGE("Thread pool stopped");
292 throw std::runtime_error("thread pool stopped");
295 auto job = std::make_shared<std::packaged_task<bool()>>(
296 std::bind(f, this, args...));
298 std::future<bool> results = job->get_future();
300 std::lock_guard<std::mutex> lock(mMutexJob);
301 mJobs.push([job]() { (*job)(); });
303 mControlJob.notify_one();
309 void DfsOCV::Run(DfsData& base, DfsData& extra)
314 throw std::runtime_error("invalid data pointer");
318 int extraCvType = -1;
319 cv::Mat baseMat, extraMat;
322 LOGI("side-by-side");
323 if (cv::Size(base.width >> 1, base.height) != mImageSize) {
324 throw std::runtime_error("invalid size");
327 baseCvType = ConvertDfsDataTypeToCV(base.type);
328 if (baseCvType < 0) {
329 throw std::runtime_error("invalid data type");
331 cv::Mat mat(cv::Size(base.width, base.height), baseCvType, base.data);
332 LOGI("%zd x %zd", base.width, base.height);
333 baseMat = mat(cv::Rect(0, 0,
335 mImageSize.height)).clone();
336 extraMat = mat(cv::Rect(mImageSize.width, 0,
338 mImageSize.height)).clone();
340 if (cv::Size(base.width, base.height) != mImageSize ||
341 cv::Size(extra.width, extra.height) != mImageSize) {
342 throw std::runtime_error("invalid size");
344 baseCvType = ConvertDfsDataTypeToCV(base.type);
345 extraCvType = ConvertDfsDataTypeToCV(extra.type);
346 if (baseCvType < 0 || extraCvType < 0) {
347 LOGE("baseCvType: %d, extraCvType:%d", baseCvType, extraCvType);
348 throw std::runtime_error("invalid data type");
351 baseMat = cv::Mat(cv::Size(base.width, base.height),
354 extraMat = cv::Mat(cv::Size(extra.width,
360 if (baseMat.size() != extraMat.size()) {
361 throw std::runtime_error("base and extra should be the same size");
364 if (baseMat.type() != extraMat.type()) {
365 throw std::runtime_error("base and extra should be the type");
368 cv::Mat rBaseMat, rExtraMat, dispMat, dispFiltMat;
371 if (mIsStereoCalibrated) {
372 cv::remap(baseMat, rBaseMat, mBaseReMap[0], mBaseReMap[1], cv::INTER_LINEAR);
373 cv::remap(extraMat, rExtraMat, mExtraReMap[0], mExtraReMap[1], cv::INTER_LINEAR);
376 rExtraMat = extraMat;
380 cv::Mat srcBaseMat, srcExtraMat;
381 cv::resize(rBaseMat, srcBaseMat,
383 1.0/static_cast<double>((1<<mDownScale)),
384 1.0/static_cast<double>((1<<mDownScale)));
385 cv::resize(rExtraMat, srcExtraMat,
387 1.0/static_cast<double>((1<<mDownScale)),
388 1.0/static_cast<double>((1<<mDownScale)));
390 std::vector<std::future<bool>> results;
391 results.emplace_back(EnqueueJob(&DfsOCV::computeL,
392 std::cref(srcBaseMat),
393 std::cref(srcExtraMat),
397 cv::Mat dispMatExtra;
398 results.emplace_back(EnqueueJob(&DfsOCV::computeR,
399 std::cref(srcExtraMat),
400 std::cref(srcBaseMat),
401 std::ref(dispMatExtra)));
402 LOGI("left: %s, right: %s", results[0].get() ? "true" : "false",
403 results[1].get() ? "true" : "false");
407 cv::resize(dispMat, tmp,
411 dispMat = tmp * static_cast<double>(1<<mDownScale);
414 cv::resize(dispMatExtra, tmp,
418 dispMatExtra = tmp * static_cast<double>(1<<mDownScale);
420 mDfsPostOcv->filter(dispMat, rBaseMat, dispFiltMat,
422 cv::Rect(0,0,rBaseMat.cols, rBaseMat.rows),
425 LOGI("left : %s", results[0].get() ? "true" : "false");
428 cv::resize(dispMat, tmp,
430 static_cast<double>(1<<mDownScale),
431 static_cast<double>(1<<mDownScale));
432 dispMat = tmp * static_cast<double>(1<<mDownScale);
434 mDfsPostOcv->filter(dispMat, rBaseMat, dispFiltMat);
436 dispFiltMat.convertTo(mDispMat, CV_32F, mDispShiftInv);
438 LOGI("left : %s", results[0].get() ? "true" : "false");
441 cv::resize(dispMat, tmp,
443 static_cast<double>(1<<mDownScale),
444 static_cast<double>(1<<mDownScale));
446 tmp.convertTo(mDispMat, CV_32F, mDispShiftInv * static_cast<double>(1 << mDownScale));
448 dispMat.convertTo(mDispMat, CV_32F, mDispShiftInv);
452 mDepthData.data = mDispMat.ptr<float>();
453 mDepthData.type = DFS_DATA_TYPE_FLOAT32C1;
454 mDepthData.width = mDispMat.cols;
455 mDepthData.height = mDispMat.rows;
456 mDepthData.stride = mDispMat.elemSize() * mDispMat.cols;
458 mDepthData.pointCloudData = nullptr;
459 mDepthData.pointCloudSize = 0;
464 DfsData& DfsOCV::GetDepthData()
475 class IDfsAdaptation *AdaptorInit(void)
477 //InferenceTFLite *engine = new InferenceTFLite();
478 DfsOCV *adaptor = new DfsOCV();
482 void AdaptorDestroy(class IDfsAdaptation *adaptor)