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 DEFAULT_STEREO_CALIB_FILE_NAME "stereoCalibZed.yaml"
23 #define DEFAULT_STEREO_VGA_CALIB_FILE_NAME "stereoCalibZedVGA.yaml"
24 #define DEFAULT_STEREO_HD_CALIB_FILE_NAME "stereoCalibZedHD.yaml"
26 #define MAX_THREADS_NUM 2
27 #define ENABLE_CALIBRATION 0
29 namespace DfsAdaptationImpl
33 mDfsOcvExtra(nullptr),
44 mCalibFilePath(DFS_CALIB_FILE_PATH),
46 mIsStereoCalibrated(false),
47 mUpdateStereoCalibration(false),
48 mImageSize(cv::Size(0,0)),
60 mControlJob.notify_all();
62 for (auto& t : mThreadPool) {
63 LOGI("thread joinable: %s", t.joinable() ? "true" : "false");
70 void DfsOCV::InitializeStereoCalibration()
74 cv::Mat intrinsicTest;
76 if (mImageSize == cv::Size(1280, 720))
77 mCalibFilePath += std::string(DEFAULT_STEREO_HD_CALIB_FILE_NAME);
78 else if (mImageSize == cv::Size(672, 376)) {
79 mCalibFilePath += std::string(DEFAULT_STEREO_VGA_CALIB_FILE_NAME);
81 throw std::ios_base::failure("no calibration file");
84 cv::FileStorage fs(mCalibFilePath, cv::FileStorage::READ);
86 LOGE("Failed to open calib file %s", mCalibFilePath.c_str());
87 throw std::ios_base::failure("calibration");
90 fs["LEFT_CAM_INTRINSIC"] >> mStereoParam.baceCamera.intrinsic;
91 fs["LEFT_CAM_DISTCOEFFS"] >> mStereoParam.baceCamera.distCoeffs;
93 fs["RIGHT_CAM_INTRINSIC"] >> mStereoParam.extraCamera.intrinsic;
94 fs["RIGHT_CAM_DISTCOEFFS"] >> mStereoParam.extraCamera.distCoeffs;
96 fs["STEREO_TRANSLATION"] >> mStereoParam.translation;
97 fs["STEREO_ROTATION"] >> mStereoParam.rotation;
99 mIsStereoCalibrated = true;
101 } catch (const std::exception& e) {
102 LOGE("Failed to read calibration data %s", e.what());
103 throw std::ios_base::failure("calibration");
109 void DfsOCV::InitRectifyMap()
114 cv::Mat newBaseCameraIntrinsic = cv::getOptimalNewCameraMatrix(
115 mStereoParam.baceCamera.intrinsic,
116 mStereoParam.baceCamera.distCoeffs,
120 cv::Mat newExtraCameraIntrinsic = cv::getOptimalNewCameraMatrix(
121 mStereoParam.extraCamera.intrinsic,
122 mStereoParam.extraCamera.distCoeffs,
126 cv::Mat extraCameraRotation;
127 cv::Rodrigues(mStereoParam.rotation, extraCameraRotation);
129 cv::Mat baseRotation, extraRotation; // 3x3
130 cv::Mat baseProjection, extraProjection; // 3x4
131 cv::Mat disp2Depth; // 4x4
133 cv::stereoRectify(mStereoParam.baceCamera.intrinsic,
134 mStereoParam.baceCamera.distCoeffs,
135 mStereoParam.extraCamera.intrinsic,
136 mStereoParam.extraCamera.distCoeffs,
139 mStereoParam.translation,
146 cv::initUndistortRectifyMap(mStereoParam.baceCamera.intrinsic,
147 mStereoParam.baceCamera.distCoeffs,
149 newBaseCameraIntrinsic,
155 cv::initUndistortRectifyMap(mStereoParam.extraCamera.intrinsic,
156 mStereoParam.extraCamera.distCoeffs,
158 newExtraCameraIntrinsic,
164 } catch (const std::exception& e) {
165 LOGE("Failed to InitRectifyMap");
173 void DfsOCV::Initialize(DfsParameter& param, size_t width, size_t height,
174 size_t minDisp, size_t maxDisp)
179 mImageSize = cv::Size(width, height);
180 mMinDisparity = minDisp;
181 mNumDisparities = maxDisp - minDisp + 1;
183 mMinDisparity >>= mDownScale;
184 mNumDisparities >>= mDownScale;
186 mDfsOcv = cv::StereoSGBM::create(mMinDisparity, mNumDisparities, mBlockSize);
188 this->SetParameters();
190 #if ENABLE_CALIBRATION
192 this->InitializeStereoCalibration();
193 this->InitRectifyMap();
194 } catch (const std::exception& e) {
198 mDfsPostOcv = cv::ximgproc::createDisparityWLSFilter(mDfsOcv);
199 mDfsOcvExtra = cv::ximgproc::createRightMatcher(mDfsOcv);
200 mDfsPostOcv->setLRCthresh(24.0);
202 mDfsPostOcv->setSigmaColor(10.0);
203 mDfsPostOcv->setLambda(8000);
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 throw std::runtime_error("invalid data type");
350 baseMat = cv::Mat(cv::Size(base.width, base.height),
353 extraMat = cv::Mat(cv::Size(extra.width,
359 if (baseMat.size() != extraMat.size()) {
360 throw std::runtime_error("base and extra should be the same size");
363 if (baseMat.type() != extraMat.type()) {
364 throw std::runtime_error("base and extra should be the type");
367 cv::Mat rBaseMat, rExtraMat, dispMat, dispFiltMat;
370 #if ENABLE_CALIBRATION
371 cv::remap(baseMat, rBaseMat, mBaseReMap[0], mBaseReMap[1], cv::INTER_LINEAR);
372 cv::remap(extraMat, rExtraMat, mExtraReMap[0], mExtraReMap[1], cv::INTER_LINEAR);
375 rExtraMat = extraMat;
378 cv::Mat srcBaseMat, srcExtraMat;
379 cv::resize(rBaseMat, srcBaseMat,
381 1.0/static_cast<double>((1<<mDownScale)),
382 1.0/static_cast<double>((1<<mDownScale)));
383 cv::resize(rExtraMat, srcExtraMat,
385 1.0/static_cast<double>((1<<mDownScale)),
386 1.0/static_cast<double>((1<<mDownScale)));
388 std::vector<std::future<bool>> results;
389 results.emplace_back(EnqueueJob(&DfsOCV::computeL,
390 std::cref(srcBaseMat),
391 std::cref(srcExtraMat),
395 cv::Mat dispMatExtra;
396 results.emplace_back(EnqueueJob(&DfsOCV::computeR,
397 std::cref(srcExtraMat),
398 std::cref(srcBaseMat),
399 std::ref(dispMatExtra)));
400 LOGI("left: %s, right: %s", results[0].get() ? "true" : "false",
401 results[1].get() ? "true" : "false");
405 cv::resize(dispMat, tmp,
409 dispMat = tmp * static_cast<double>(1<<mDownScale);
412 cv::resize(dispMatExtra, tmp,
416 dispMatExtra = tmp * static_cast<double>(1<<mDownScale);
418 mDfsPostOcv->filter(dispMat, rBaseMat, dispFiltMat,
420 cv::Rect(0,0,rBaseMat.cols, rBaseMat.rows),
423 LOGI("left : %s", results[0].get() ? "true" : "false");
426 cv::resize(dispMat, tmp,
428 static_cast<double>(1<<mDownScale),
429 static_cast<double>(1<<mDownScale));
430 dispMat = tmp * static_cast<double>(1<<mDownScale);
432 mDfsPostOcv->filter(dispMat, rBaseMat, dispFiltMat);
434 dispFiltMat.convertTo(mDispMat, CV_8UC1, 1.0/16.0);
436 LOGI("left : %s", results[0].get() ? "true" : "false");
439 cv::resize(dispMat, tmp,
441 static_cast<double>(1<<mDownScale),
442 static_cast<double>(1<<mDownScale));
444 tmp.convertTo(mDispMat, CV_8UC1, (1.0/16.0) * static_cast<double>(1 << mDownScale));
446 dispMat.convertTo(mDispMat, CV_8UC1, 1.0/16.0);
450 mDepthData.data = mDispMat.ptr<unsigned char>();
451 mDepthData.type = DFS_DATA_TYPE_UINT8C1;
452 mDepthData.width = mDispMat.cols;
453 mDepthData.height = mDispMat.rows;
454 mDepthData.stride = mDispMat.elemSize() * mDispMat.cols;
459 DfsData& DfsOCV::GetDepthData()
470 class IDfsAdaptation *AdaptorInit(void)
472 //InferenceTFLite *engine = new InferenceTFLite();
473 DfsOCV *adaptor = new DfsOCV();
477 void AdaptorDestroy(class IDfsAdaptation *adaptor)