--- /dev/null
+/**
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <pthread.h>
+#include <glib-2.0/glib.h>
+
+#include "gtest/gtest.h"
+#include "ImageHelper.h"
+#include "mv_3d.h"
+
+using namespace testing;
+
+// 0:image,1 camera, test sequence name if image, width, height, min disp, max disp, camera parameter
+typedef std::tuple<int, std::string, int, int, int, int, std::string> ParamTypes;
+#define IMAGE_RES_PATH "/usr/share/capi-media-vision/dfseval"
+#define PCD_OUTPUT_PATH "/tmp"
+#define DEPTH_INTRINSIC_FILENAME "calibOcv.yaml"
+#define PCD_WRITE_FILENAME "test_pontcloud.pcd"
+#define IMAGE_FILENAME_LEFT "im0.jpeg"
+#define IMAGE_FILENAME_RIGHT "im1.jpeg"
+#define PCD_SAMPLING_RATIO 0.05
+#define PCD_OUTLIER_REMOVAL_POINT 3
+#define PCD_OUTLIER_REMOVAL_RADIUS 0.5
+
+enum { TEST_MODE_IMAGE = 0, TEST_MODE_CAMERA = 1 };
+static GCond gThreadCond;
+static GMutex gThreadMutex;
+static void WaitUntil()
+{
+ g_mutex_lock(&gThreadMutex);
+ g_print("\t[__wait] waiting... until finishing\n");
+ g_cond_wait(&gThreadCond, &gThreadMutex);
+ g_print("\t[__wait] get signal from callback\n");
+ g_mutex_unlock(&gThreadMutex);
+}
+
+static void Signal()
+{
+ g_mutex_lock(&gThreadMutex);
+ g_cond_signal(&gThreadCond);
+ g_print("\t[__signal] send signal to test proc\n");
+ g_mutex_unlock(&gThreadMutex);
+}
+
+class Mv3DTestsFixture : public ::testing::TestWithParam<ParamTypes>
+{
+protected:
+ Mv3DTestsFixture() = default;
+ ~Mv3DTestsFixture() = default;
+
+ void SetUp() final
+ {
+ ASSERT_EQ(mv_3d_create(&mDepthHandle), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_create_engine_config(&mEngineCfgHandle),MEDIA_VISION_ERROR_NONE);
+
+ std::tie(mTestMode,
+ mImageName,
+ mWidth,
+ mHeight,
+ mMinDisparity,
+ mMaxDisparity,
+ mCameraCalibrationPath) = GetParam();
+
+ ASSERT_EQ(mv_engine_config_set_int_attribute(mEngineCfgHandle,
+ MV_3D_DEPTH_WIDTH,
+ mWidth), MEDIA_VISION_ERROR_NONE);
+
+
+ ASSERT_EQ(mv_engine_config_set_int_attribute(mEngineCfgHandle,
+ MV_3D_DEPTH_HEIGHT,
+ mHeight), MEDIA_VISION_ERROR_NONE);
+
+ ASSERT_EQ(mv_engine_config_set_int_attribute(mEngineCfgHandle,
+ MV_3D_DEPTH_MIN_DISPARITY,
+ mMinDisparity), MEDIA_VISION_ERROR_NONE);
+
+ ASSERT_EQ(mv_engine_config_set_int_attribute(mEngineCfgHandle,
+ MV_3D_DEPTH_MAX_DISPARITY,
+ mMaxDisparity), MEDIA_VISION_ERROR_NONE);
+
+ if (mTestMode == 0)
+ mCameraCalibrationPath = std::string(IMAGE_RES_PATH) + std::string("/")
+ + mImageName + std::string("/")
+ + std::string(DEPTH_INTRINSIC_FILENAME);
+ else
+ ASSERT_FALSE(mCameraCalibrationPath.empty()) << "there is no calibration file";
+
+ ASSERT_EQ(mv_engine_config_set_string_attribute(mEngineCfgHandle,
+ MV_3D_DEPTH_STEREO_CONFIG_FILE_PATH,
+ mCameraCalibrationPath.c_str()), MEDIA_VISION_ERROR_NONE);
+
+ ASSERT_EQ(mv_engine_config_set_double_attribute(mEngineCfgHandle,
+ MV_3D_POINTCLOUD_SAMPLING_RATIO,
+ PCD_SAMPLING_RATIO), MEDIA_VISION_ERROR_NONE);
+
+ ASSERT_EQ(mv_engine_config_set_int_attribute(mEngineCfgHandle,
+ MV_3D_POINTCLOUD_OUTLIER_REMOVAL_POINTS,
+ PCD_OUTLIER_REMOVAL_POINT), MEDIA_VISION_ERROR_NONE);
+
+ ASSERT_EQ(mv_engine_config_set_double_attribute(mEngineCfgHandle,
+ MV_3D_POINTCLOUD_OUTLIER_REMOVAL_RADIUS,
+ PCD_OUTLIER_REMOVAL_RADIUS), MEDIA_VISION_ERROR_NONE);
+
+ ASSERT_EQ(mv_engine_config_set_string_attribute(mEngineCfgHandle,
+ MV_3D_POINTCLOUD_OUTPUT_FILE_PATH,
+ PCD_OUTPUT_PATH), MEDIA_VISION_ERROR_NONE);
+ }
+
+
+ void TearDown() final
+ {
+ ASSERT_EQ(mv_3d_destroy(mDepthHandle), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_destroy_engine_config(mEngineCfgHandle), MEDIA_VISION_ERROR_NONE);
+
+ if (mLeftSourceHandle) {
+ ASSERT_EQ(mv_destroy_source(mLeftSourceHandle), MEDIA_VISION_ERROR_NONE);
+ }
+
+ if (mRightSourceHandle) {
+ ASSERT_EQ(mv_destroy_source(mRightSourceHandle), MEDIA_VISION_ERROR_NONE);
+ }
+ }
+
+ void LoadImage()
+ {
+ auto imagePath = std::string(IMAGE_RES_PATH) + std::string("/") + mImageName;
+ auto leftImageFilePath = imagePath + std::string("/") + std::string(IMAGE_FILENAME_LEFT);
+ auto rightImageFilePath = imagePath + std::string("/") + std::string(IMAGE_FILENAME_RIGHT);
+
+ ASSERT_EQ(access(leftImageFilePath.c_str(), F_OK | R_OK), 0) << leftImageFilePath << " doesn't exist";
+ ASSERT_EQ(mv_create_source(&mLeftSourceHandle), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(MediaVision::Common::ImageHelper::loadImageToSource(
+ leftImageFilePath.c_str(), mLeftSourceHandle), MEDIA_VISION_ERROR_NONE);
+
+ ASSERT_EQ(access(rightImageFilePath.c_str(), F_OK | R_OK), 0) << rightImageFilePath << " doesn't exist";
+ ASSERT_EQ(mv_create_source(&mRightSourceHandle), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(MediaVision::Common::ImageHelper::loadImageToSource(
+ rightImageFilePath.c_str(), mRightSourceHandle), MEDIA_VISION_ERROR_NONE);
+ }
+
+ mv_source_h mLeftSourceHandle {nullptr};
+ mv_source_h mRightSourceHandle {nullptr};
+ mv_engine_config_h mEngineCfgHandle {nullptr};
+
+ int mTestMode {TEST_MODE_IMAGE};
+ std::string mImageName {""};
+ int mWidth {0};
+ int mHeight {0};
+ int mMinDisparity {0};
+ int mMaxDisparity {0};
+ std::string mCameraCalibrationPath {""};
+
+public:
+ mv_3d_h mDepthHandle {nullptr};
+ bool mIsDepthCallbackInvoked {false};
+ bool mIsPointCloudCallbackInvoked {false};
+ bool mIsPointCloudWriteSuccess {false};
+ bool mIsRunAsync {false};
+};
+
+static void _depth_cb(mv_source_h source, unsigned short *depth, unsigned int width,
+ unsigned int height, void *user_data)
+{
+ auto mv3dTestsFixture = static_cast<Mv3DTestsFixture *>(user_data);
+ mv3dTestsFixture->mIsDepthCallbackInvoked = true;
+}
+
+static void _pointcloud_cb(mv_source_h source,
+ mv_3d_pointcloud_h pointcloud,
+ void *user_data)
+{
+ auto mv3dTestsFixture = static_cast<Mv3DTestsFixture *>(user_data);
+ mv3dTestsFixture->mIsPointCloudCallbackInvoked = true;
+ if (mv3dTestsFixture->mIsRunAsync)
+ Signal();
+}
+
+static void _pointcloud_write_file_cb(mv_source_h source,
+ mv_3d_pointcloud_h pointcloud,
+ void *user_data)
+{
+ auto mv3dTestsFixture = static_cast<Mv3DTestsFixture *>(user_data);
+ mv3dTestsFixture->mIsPointCloudCallbackInvoked = true;
+
+ int ret = mv_3d_pointcloud_write_file(mv3dTestsFixture->mDepthHandle, pointcloud, MV_3D_POINTCLOUD_TYPE_PCD_BIN, PCD_WRITE_FILENAME);
+ if (ret == MEDIA_VISION_ERROR_NONE)
+ mv3dTestsFixture->mIsPointCloudWriteSuccess = true;
+}
+
+TEST_P(Mv3DTestsFixture, Configure)
+{
+ ASSERT_EQ(mv_3d_configure(mDepthHandle, mEngineCfgHandle), MEDIA_VISION_ERROR_NONE);
+}
+
+TEST_P(Mv3DTestsFixture, SetCallback)
+{
+ ASSERT_EQ(mv_3d_set_depth_cb(mDepthHandle, _depth_cb, this), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_3d_set_pointcloud_cb(mDepthHandle, _pointcloud_cb, this), MEDIA_VISION_ERROR_NONE);
+}
+
+TEST_P(Mv3DTestsFixture, Prepare)
+{
+ ASSERT_EQ(mv_3d_configure(mDepthHandle, mEngineCfgHandle), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_3d_set_depth_cb(mDepthHandle, _depth_cb, this), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_3d_set_pointcloud_cb(mDepthHandle, _pointcloud_cb, this), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_3d_prepare(mDepthHandle), MEDIA_VISION_ERROR_NONE);
+}
+
+TEST_P(Mv3DTestsFixture, Runsync)
+{
+ ASSERT_EQ(mv_3d_configure(mDepthHandle, mEngineCfgHandle), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_3d_set_depth_cb(mDepthHandle, _depth_cb, this), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_3d_set_pointcloud_cb(mDepthHandle, _pointcloud_cb, this), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_3d_prepare(mDepthHandle), MEDIA_VISION_ERROR_NONE);
+
+ if (mTestMode == 0) {
+ LoadImage();
+ }
+ ASSERT_EQ(mv_3d_run(mDepthHandle, mLeftSourceHandle, mRightSourceHandle, nullptr), MEDIA_VISION_ERROR_NONE);
+ ASSERT_TRUE(mIsDepthCallbackInvoked);
+ ASSERT_TRUE(mIsPointCloudCallbackInvoked);
+}
+
+TEST_P(Mv3DTestsFixture, RunAsync)
+{
+ mIsRunAsync = true;
+ ASSERT_EQ(mv_3d_configure(mDepthHandle, mEngineCfgHandle), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_3d_set_depth_cb(mDepthHandle, _depth_cb, this), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_3d_set_pointcloud_cb(mDepthHandle, _pointcloud_cb, this), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_3d_prepare(mDepthHandle), MEDIA_VISION_ERROR_NONE);
+
+ if (mTestMode == 0) {
+ LoadImage();
+ }
+ ASSERT_EQ(mv_3d_run_async(mDepthHandle, mLeftSourceHandle, mRightSourceHandle, nullptr), MEDIA_VISION_ERROR_NONE);
+
+ WaitUntil();
+ ASSERT_TRUE(mIsDepthCallbackInvoked);
+ ASSERT_TRUE(mIsPointCloudCallbackInvoked);
+}
+
+TEST_P(Mv3DTestsFixture, PointCloudWriteFile)
+{
+ ASSERT_EQ(mv_3d_configure(mDepthHandle, mEngineCfgHandle), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_3d_set_depth_cb(mDepthHandle, _depth_cb, this), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_3d_set_pointcloud_cb(mDepthHandle, _pointcloud_write_file_cb, this), MEDIA_VISION_ERROR_NONE);
+ ASSERT_EQ(mv_3d_prepare(mDepthHandle), MEDIA_VISION_ERROR_NONE);
+
+ if (mTestMode == 0) {
+ LoadImage();
+ }
+ ASSERT_EQ(mv_3d_run(mDepthHandle, mLeftSourceHandle, mRightSourceHandle, nullptr), MEDIA_VISION_ERROR_NONE);
+ ASSERT_TRUE(mIsDepthCallbackInvoked);
+ ASSERT_TRUE(mIsPointCloudCallbackInvoked);
+ ASSERT_TRUE(mIsPointCloudWriteSuccess);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ Mv3DTests,
+ Mv3DTestsFixture,
+ ::Values(
+ ParamTypes(TEST_MODE_IMAGE, std::string("Adirondack"), 718, 496, 8, 72, std::string()))
+);
+
+int main(int argc, char **argv)
+{
+ InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
\ No newline at end of file