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),
42 mIsStereoCalibrated(false),
43 mUpdateStereoCalibration(false),
44 mImageSize(cv::Size(0,0)),
56 mControlJob.notify_all();
58 for (auto& t : mThreadPool) {
59 LOGI("thread joinable: %s", t.joinable() ? "true" : "false");
66 void DfsOCV::InitializeStereoCalibration(std::string filepath)
70 cv::Mat intrinsicTest;
72 cv::FileStorage fs(filepath, cv::FileStorage::READ);
74 LOGE("Failed to open calib file %s", filepath.c_str());
75 throw std::ios_base::failure("calibration");
78 fs["LEFT_CAM_INTRINSIC"] >> mStereoParam.baceCamera.intrinsic;
79 fs["LEFT_CAM_DISTCOEFFS"] >> mStereoParam.baceCamera.distCoeffs;
81 fs["RIGHT_CAM_INTRINSIC"] >> mStereoParam.extraCamera.intrinsic;
82 fs["RIGHT_CAM_DISTCOEFFS"] >> mStereoParam.extraCamera.distCoeffs;
84 fs["STEREO_TRANSLATION"] >> mStereoParam.translation;
85 fs["STEREO_ROTATION"] >> mStereoParam.rotation;
87 if (!fs["STEREO_DOFFSET"].empty()) {
88 mStereoParam.dispOffset = static_cast<float>(fs["STEREO_DOFFSET"]);
89 LOGI("%f", mStereoParam.dispOffset);
92 mDisp2DepthMat = cv::Mat(mImageSize, CV_32F, mStereoParam.baceCamera.intrinsic.at<double>(0,0) *
93 mStereoParam.translation.at<double>(0));
94 mDispOffsetMat = cv::Mat(mImageSize, CV_32F, mStereoParam.dispOffset);
96 } catch (const std::exception& e) {
97 LOGE("Failed to read calibration data %s", e.what());
98 throw std::ios_base::failure("calibration");
104 void DfsOCV::InitRectifyMap()
109 cv::Mat newBaseCameraIntrinsic = cv::getOptimalNewCameraMatrix(
110 mStereoParam.baceCamera.intrinsic,
111 mStereoParam.baceCamera.distCoeffs,
115 cv::Mat newExtraCameraIntrinsic = cv::getOptimalNewCameraMatrix(
116 mStereoParam.extraCamera.intrinsic,
117 mStereoParam.extraCamera.distCoeffs,
121 cv::Mat extraCameraRotation;
122 cv::Rodrigues(mStereoParam.rotation, extraCameraRotation);
124 cv::Mat baseRotation, extraRotation; // 3x3
125 cv::Mat baseProjection, extraProjection; // 3x4
126 cv::Mat disp2Depth; // 4x4
128 cv::stereoRectify(mStereoParam.baceCamera.intrinsic,
129 mStereoParam.baceCamera.distCoeffs,
130 mStereoParam.extraCamera.intrinsic,
131 mStereoParam.extraCamera.distCoeffs,
134 mStereoParam.translation,
141 cv::initUndistortRectifyMap(mStereoParam.baceCamera.intrinsic,
142 mStereoParam.baceCamera.distCoeffs,
144 newBaseCameraIntrinsic,
150 cv::initUndistortRectifyMap(mStereoParam.extraCamera.intrinsic,
151 mStereoParam.extraCamera.distCoeffs,
153 newExtraCameraIntrinsic,
159 mIsStereoCalibrated = true;
160 } catch (const std::exception& e) {
161 LOGE("Failed to InitRectifyMap");
169 void DfsOCV::Initialize(DfsParameter& param, size_t width, size_t height,
170 size_t minDisp, size_t maxDisp, std::string stereoConfigPath)
175 mImageSize = cv::Size(width, height);
176 mMinDisparity = minDisp;
177 mNumDisparities = static_cast<int>(static_cast<float>(maxDisp - minDisp+1)*mDispShiftInv);
178 mNumDisparities *= mDispShift;
179 LOGE("mMinDisparity: %zd, mNumDisparities: %zd", mMinDisparity, mNumDisparities);
181 mMinDisparity >>= mDownScale;
182 mNumDisparities >>= mDownScale;
184 mDfsOcv = cv::StereoSGBM::create(mMinDisparity,
191 10, // uniquenessRatio
192 50, // speckleWindowSize
195 this->SetParameters();
197 #if ENABLE_CALIBRATION
198 if (!stereoConfigPath.empty()) {
200 this->InitializeStereoCalibration(stereoConfigPath);
201 this->InitRectifyMap();
202 } catch (const std::exception& e) {
207 mDfsPostOcv = cv::ximgproc::createDisparityWLSFilter(mDfsOcv);
208 mDfsOcvExtra = cv::ximgproc::createRightMatcher(mDfsOcv);
209 mDfsPostOcv->setLRCthresh(24.0);
211 mDfsPostOcv->setSigmaColor(1.5);
212 mDfsPostOcv->setLambda(8000);
213 mDfsPostOcv->setDepthDiscontinuityRadius((int)ceil(0.5*5));
216 mThreadPool.reserve(MAX_THREADS_NUM - 1);
217 mThreadPool.emplace_back([this](){this->Runner();});
219 mThreadPool.reserve(MAX_THREADS_NUM);
220 mThreadPool.emplace_back([this](){this->Runner();});
221 mThreadPool.emplace_back([this](){this->Runner();});
226 void DfsOCV::SetParameters()
230 mDfsOcv->setMinDisparity(mMinDisparity);
231 mDfsOcv->setNumDisparities(mNumDisparities);
232 mDfsOcv->setBlockSize(mBlockSize);
233 mDfsOcv->setP1(mP1 * mBlockSize * mBlockSize);
234 mDfsOcv->setP2(mP2 * mBlockSize * mBlockSize);
235 mDfsOcv->setPreFilterCap(mPreFilterCap);
237 mDfsOcv->setMode(cv::StereoSGBM::MODE_SGBM_3WAY);
241 int DfsOCV::ConvertDfsDataTypeToCV(int type)
245 case DFS_DATA_TYPE_UINT8C1:
247 case DFS_DATA_TYPE_UINT8C3:
250 LOGE("Invalide type");
258 bool DfsOCV::computeL(const cv::Mat& baseMat, const cv::Mat& extraMat, cv::Mat& disp)
262 mDfsOcv->compute(baseMat, extraMat, disp);
268 bool DfsOCV::computeR(const cv::Mat& baseMat, const cv::Mat& extraMat, cv::Mat& disp)
272 mDfsOcvExtra->compute(baseMat, extraMat, disp);
278 void DfsOCV::Runner()
281 std::unique_lock<std::mutex> lock(mMutexJob);
282 mControlJob.wait(lock, [this]() {return !mJobs.empty() || mIsStopAll;});
283 if (mIsStopAll && mJobs.empty()) {
284 LOGI("Stop and all jobs are done");
288 std::function<void()> job = std::move(mJobs.front());
296 template <class F, class... Args>
297 std::future<bool> DfsOCV::EnqueueJob(F f, Args... args)
301 LOGE("Thread pool stopped");
302 throw std::runtime_error("thread pool stopped");
305 auto job = std::make_shared<std::packaged_task<bool()>>(
306 std::bind(f, this, args...));
308 std::future<bool> results = job->get_future();
310 std::lock_guard<std::mutex> lock(mMutexJob);
311 mJobs.push([job]() { (*job)(); });
313 mControlJob.notify_one();
319 void DfsOCV::Run(DfsData& base, DfsData& extra)
324 throw std::runtime_error("invalid data pointer");
328 int extraCvType = -1;
329 cv::Mat baseMat, extraMat;
332 LOGI("side-by-side");
333 if (cv::Size(base.width >> 1, base.height) != mImageSize) {
334 throw std::runtime_error("invalid size");
337 baseCvType = ConvertDfsDataTypeToCV(base.type);
338 if (baseCvType < 0) {
339 throw std::runtime_error("invalid data type");
341 cv::Mat mat(cv::Size(base.width, base.height), baseCvType, base.data);
342 LOGI("%zd x %zd", base.width, base.height);
343 baseMat = mat(cv::Rect(0, 0,
345 mImageSize.height)).clone();
346 extraMat = mat(cv::Rect(mImageSize.width, 0,
348 mImageSize.height)).clone();
350 if (cv::Size(base.width, base.height) != mImageSize ||
351 cv::Size(extra.width, extra.height) != mImageSize) {
352 throw std::runtime_error("invalid size");
354 baseCvType = ConvertDfsDataTypeToCV(base.type);
355 extraCvType = ConvertDfsDataTypeToCV(extra.type);
356 if (baseCvType < 0 || extraCvType < 0) {
357 LOGE("baseCvType: %d, extraCvType:%d", baseCvType, extraCvType);
358 throw std::runtime_error("invalid data type");
361 baseMat = cv::Mat(cv::Size(base.width, base.height),
364 extraMat = cv::Mat(cv::Size(extra.width,
370 if (baseMat.size() != extraMat.size()) {
371 throw std::runtime_error("base and extra should be the same size");
374 if (baseMat.type() != extraMat.type()) {
375 throw std::runtime_error("base and extra should be the type");
378 cv::Mat rBaseMat, rExtraMat, dispMat, dispFiltMat;
381 if (mIsStereoCalibrated) {
382 cv::remap(baseMat, rBaseMat, mBaseReMap[0], mBaseReMap[1], cv::INTER_LINEAR);
383 cv::remap(extraMat, rExtraMat, mExtraReMap[0], mExtraReMap[1], cv::INTER_LINEAR);
386 rExtraMat = extraMat;
390 cv::Mat srcBaseMat, srcExtraMat;
391 cv::resize(rBaseMat, srcBaseMat,
393 1.0/static_cast<double>((1<<mDownScale)),
394 1.0/static_cast<double>((1<<mDownScale)));
395 cv::resize(rExtraMat, srcExtraMat,
397 1.0/static_cast<double>((1<<mDownScale)),
398 1.0/static_cast<double>((1<<mDownScale)));
400 std::vector<std::future<bool>> results;
401 results.emplace_back(EnqueueJob(&DfsOCV::computeL,
402 std::cref(srcBaseMat),
403 std::cref(srcExtraMat),
407 cv::Mat dispMatExtra;
408 results.emplace_back(EnqueueJob(&DfsOCV::computeR,
409 std::cref(srcExtraMat),
410 std::cref(srcBaseMat),
411 std::ref(dispMatExtra)));
412 LOGI("left: %s, right: %s", results[0].get() ? "true" : "false",
413 results[1].get() ? "true" : "false");
417 cv::resize(dispMat, tmp,
421 dispMat = tmp * static_cast<double>(1<<mDownScale);
424 cv::resize(dispMatExtra, tmp,
428 dispMatExtra = tmp * static_cast<double>(1<<mDownScale);
430 mDfsPostOcv->filter(dispMat, rBaseMat, dispFiltMat,
432 cv::Rect(0,0,rBaseMat.cols, rBaseMat.rows),
435 LOGI("left : %s", results[0].get() ? "true" : "false");
438 cv::resize(dispMat, tmp,
440 static_cast<double>(1<<mDownScale),
441 static_cast<double>(1<<mDownScale));
442 dispMat = tmp * static_cast<double>(1<<mDownScale);
444 mDfsPostOcv->filter(dispMat, rBaseMat, dispFiltMat);
446 dispFiltMat.convertTo(mDispMat, CV_32F, mDispShiftInv);
448 LOGI("left : %s", results[0].get() ? "true" : "false");
451 cv::resize(dispMat, tmp,
453 static_cast<double>(1<<mDownScale),
454 static_cast<double>(1<<mDownScale));
456 tmp.convertTo(mDispMat, CV_32F, mDispShiftInv * static_cast<double>(1 << mDownScale));
458 dispMat.convertTo(mDispMat, CV_32F, mDispShiftInv);
462 /* calculate real depth from instrinsic */
463 // mDisp2DeptMat = fx * baseline
464 // depth = fx * baseline / (disparity + offset)
465 // convert depth from 32F to 16U
466 cv::Mat deptF = mDisp2DepthMat.mul(1.0/(mDispMat + mDispOffsetMat));
467 deptF.convertTo(mDepthMat, CV_16U);
469 mDepthData.data = mDepthMat.ptr<unsigned short>();
470 mDepthData.type = DFS_DATA_TYPE_UINT16C1;
471 mDepthData.width = mDepthMat.cols;
472 mDepthData.height = mDepthMat.rows;
473 mDepthData.stride = mDepthMat.elemSize() * mDepthMat.cols;
475 mDepthData.pointCloudData = nullptr;
476 mDepthData.pointCloudSize = 0;
481 DfsData& DfsOCV::GetDepthData()
492 class IDfsAdaptation *AdaptorInit(void)
494 //InferenceTFLite *engine = new InferenceTFLite();
495 DfsOCV *adaptor = new DfsOCV();
499 void AdaptorDestroy(class IDfsAdaptation *adaptor)