mv3d: add new vector type
authorsangho park <sangho.g.park@samsung.com>
Mon, 24 Apr 2023 05:22:11 +0000 (14:22 +0900)
committerKwanghoon Son <k.son@samsung.com>
Wed, 28 Jun 2023 09:51:32 +0000 (18:51 +0900)
[Issue type] : new feature

Add new vector type for 3D and Plane equation

Change-Id: I5bd1145585226d1da0be0379f4e55424395d66ad
Signed-off-by: sangho park <sangho.g.park@samsung.com>
include/mv_3d.h
include/mv_3d_private.h [deleted file]
include/mv_3d_type.h
include/mv_common.h
mv_3d/3d/CMakeLists.txt
mv_3d/3d/include/Mv3d.h
mv_3d/3d/src/Mv3d.cpp
mv_3d/3d/src/mv_3d_internal.cpp
packaging/capi-media-vision.spec

index e912ae6c72562f7eb8d3a890f5672a1b5b22f2b1..43d940e45302b546852931d1d19334e8ca8af79a 100644 (file)
@@ -265,6 +265,7 @@ typedef void (*mv_3d_pointcloud_cb)(mv_source_h source, mv_3d_pointcloud_h point
 /**
  * @brief Sets mv_3d_pointcloud_cb() callback.
  * @details Use this function to set mv_3d_pointcloud_cb() callback.
+ *          pointcloud is only valid whithin the callback, so user need to copy the pointcloud if necessary.
  *
  * @since_tizen 7.0
  *
diff --git a/include/mv_3d_private.h b/include/mv_3d_private.h
deleted file mode 100644 (file)
index 33880e1..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef __TIZEN_MEDIAVISION_3D_PRIVATE_H__
-#define __TIZEN_MEDIAVISION_3D_PRIVATE_H__
-
-#include <cstdio>
-#include "mv_3d_type.h"
-
-#ifdef MV_3D_POINTCLOUD_IS_AVAILABLE
-#include <open3d/Open3D.h>
-
-using PointCloudPtr = std::shared_ptr<open3d::geometry::PointCloud>;
-
-#endif
-
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-
-/**
- * @file   mv_3d_private.h
- * @brief  This file contains the internal structure for depth or pointcloud.
- * @since_tizen 7.0
- */
-
-/**
-  * @brief structure of pointcloud.
-  *
-  * @since_tizen 7.0
-  *
-  */
-typedef struct {
-       mv_3d_pointcloud_type_e type { MV_3D_POINTCLOUD_TYPE_PCD_BIN };
-#ifdef MV_3D_POINTCLOUD_IS_AVAILABLE
-       PointCloudPtr pointcloud;
-#endif
-} mv_3d_pointcloud_s;
-
-/**
- * @}
- */
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
-
-#endif /* __TIZEN_MEDIAVISION_3D_PRIVATE_H__ */
index 007405073f11093ed9a8377c0b2ddc35ddc7c70b..024c5c45a1b8202f03938332f37bc6139224b330 100644 (file)
@@ -52,6 +52,22 @@ typedef enum {
        MV_3D_POINTCLOUD_TYPE_PLY_BIN /**< Polygon format as binary */
 } mv_3d_pointcloud_type_e;
 
+/**
+ * @brief A point cloud consists of point coordinates and colors and normals.
+ * @details Points are required. colors and normals are optional,
+ *          but if present, they always have the same number as num_points.
+ * @since_tizen 8.0
+ *
+ */
+typedef struct {
+       size_t num_points; /**< The number of points */
+       bool has_colors; /**< indicate whether the struct has color */
+       bool has_normals; /**< indicate whether the struct has normal */
+       mv_vec3d_s *points; /**< arrays of 3-dimensional vectors for points */
+       mv_vec3d_s *colors; /**< arrays of 3-dimensional vectors for colors */
+       mv_vec3d_s *normals; /**< arrays of 3-dimensional vectors for normals */
+} mv_3d_pointcloud_s;
+
 /**
  * @brief The mv3d handle.
  * @since_tizen 7.0
index 494cb2f10522e7cba38f80303fb24142f8b1e605..64a5c505c52ecd0fc95fa495b7e7220639dc7b93 100644 (file)
@@ -121,6 +121,16 @@ typedef enum {
        MEDIA_VISION_COLORSPACE_RGBA, /**< The colorspace type is RGBA */
 } mv_colorspace_e;
 
+/**
+ * @brief 3×1 vector of type double.
+ * @since_tizen 8.0
+ */
+typedef struct mv_vec3d {
+       double x; /**< The x-component of the vector */
+       double y; /**< The y-component of the vector */
+       double z; /**< The z-component of the vector */
+} mv_vec3d_s;
+
 /**
  * @brief The handle to the Media Vision API engine algorithms configuration.
  * @details Configuration is a dictionary consists of key and value pairs to
index 82397b93dc7d8d61cf5d5337bd6ff32026511b34..1e62f5e2361663073fd57ecfc631318696ec6f0e 100644 (file)
@@ -39,5 +39,4 @@ install(
     PATTERN "mv_3d.h"
     PATTERN "mv_3d_type.h"
     PATTERN "mv_3d_internal.h"
-    PATTERN "mv_3d_private.h"
-    )
\ No newline at end of file
+    )
index 54298dbd49536d2980f542e172477ddb1954d5d2..34dd90ff6b683397c0286dc92372aec1a786c6fe 100644 (file)
@@ -23,7 +23,6 @@
 #include "dfs_adaptation_impl.h"
 #include "mv_3d.h"
 #include "mv_3d_type.h"
-#include "mv_3d_private.h"
 
 /**
  * @file Depth.h
@@ -74,7 +73,7 @@ private:
        static gpointer DfsThreadLoop(gpointer data);
 
 #ifdef MV_3D_POINTCLOUD_IS_AVAILABLE
-       PointCloudPtr GetPointcloudFromSource(DfsInputData &intput, DfsOutputData &depthData);
+       mv_3d_pointcloud_s *GetPointcloudFromSource(DfsInputData &intput, DfsOutputData &depthData);
 #endif
 public:
        Mv3d();
index c3f9a81e576280040c6b1b396d5c40d2a3c33e42..f8738535ddfb005f13f981bc3eb2cbc2a7ae0671 100644 (file)
@@ -264,7 +264,7 @@ void Mv3d::GetDfsDataFromSources(mv_source_h baseSource, mv_source_h extraSource
 }
 
 #ifdef MV_3D_POINTCLOUD_IS_AVAILABLE
-PointCloudPtr Mv3d::GetPointcloudFromSource(DfsInputData &input, DfsOutputData &depthData)
+mv_3d_pointcloud_s *Mv3d::GetPointcloudFromSource(DfsInputData &input, DfsOutputData &depthData)
 {
        camera::PinholeCameraIntrinsic intrinsic;
        io::ReadIJsonConvertible(mIntrinsicPath, intrinsic);
@@ -302,7 +302,31 @@ PointCloudPtr Mv3d::GetPointcloudFromSource(DfsInputData &input, DfsOutputData &
                std::tie(pcd, pt_map) = pcd->RemoveRadiusOutliers(mOutlierRemovalPoints, mOutlierRemovalRadius, true);
        }
 
-       return pcd;
+       mv_3d_pointcloud_s *_pcd = new mv_3d_pointcloud_s;
+       _pcd->num_points = pcd->points_.size();
+
+       if (pcd->HasPoints()) {
+               _pcd->points = new mv_vec3d_s[_pcd->num_points];
+               memcpy(_pcd->points, pcd->points_.data(), sizeof(double) * 3 * _pcd->num_points);
+       }
+
+       if (pcd->HasColors()) {
+               _pcd->colors = new mv_vec3d_s[_pcd->num_points];
+               _pcd->has_colors = true;
+               memcpy(_pcd->colors, pcd->colors_.data(), sizeof(double) * 3 * _pcd->num_points);
+       } else {
+               _pcd->has_colors = false;
+       }
+
+       if (pcd->HasNormals()) {
+               _pcd->normals = new mv_vec3d_s[_pcd->num_points];
+               _pcd->has_normals = true;
+               memcpy(_pcd->normals, pcd->normals_.data(), sizeof(double) * 3 * _pcd->num_points);
+       } else {
+               _pcd->has_normals = false;
+       }
+
+       return _pcd;
 }
 #endif
 
@@ -350,10 +374,17 @@ int Mv3d::Run(mv_source_h baseSource, mv_source_h extraSource)
                }
 #ifdef MV_3D_POINTCLOUD_IS_AVAILABLE
                if (mPointcloudCallback) {
-                       mv_3d_pointcloud_s p { .type = MV_3D_POINTCLOUD_TYPE_PCD_BIN,
-                                                                  .pointcloud = GetPointcloudFromSource(input, depthData) };
+                       mv_3d_pointcloud_s *pcd = GetPointcloudFromSource(input, depthData);
 
-                       mPointcloudCallback(baseSource, static_cast<mv_3d_pointcloud_h>(&p), mPointcloudUserData);
+                       mPointcloudCallback(baseSource, static_cast<mv_3d_pointcloud_h>(pcd), mPointcloudUserData);
+
+                       if (pcd->num_points > 0)
+                               delete[] pcd->points;
+                       if (pcd->has_colors)
+                               delete[] pcd->colors;
+                       if (pcd->has_normals)
+                               delete[] pcd->normals;
+                       delete pcd;
                }
 #endif
                delete[] static_cast<unsigned char *>(input.data);
@@ -450,11 +481,18 @@ gpointer Mv3d::DfsThreadLoop(gpointer data)
                                                           handle->mDepthUserData);
 #ifdef MV_3D_POINTCLOUD_IS_AVAILABLE
                if (handle->mPointcloudCallback) {
-                       mv_3d_pointcloud_s p { .type = MV_3D_POINTCLOUD_TYPE_PCD_BIN,
-                                                                  .pointcloud = handle->GetPointcloudFromSource(*pInput, depthData) };
+                       mv_3d_pointcloud_s *pcd = handle->GetPointcloudFromSource(*pInput, depthData);
 
-                       handle->mPointcloudCallback(handle->mInternalSource, static_cast<mv_3d_pointcloud_h>(&p),
+                       handle->mPointcloudCallback(handle->mInternalSource, static_cast<mv_3d_pointcloud_h>(pcd),
                                                                                handle->mPointcloudUserData);
+
+                       if (pcd->num_points > 0)
+                               delete[] pcd->points;
+                       if (pcd->has_colors)
+                               delete[] pcd->colors;
+                       if (pcd->has_normals)
+                               delete[] pcd->normals;
+                       delete pcd;
                }
 #endif
                delete[] static_cast<unsigned char *>(pInput->data);
@@ -469,11 +507,37 @@ int Mv3d::WritePointcloudFile(mv_3d_pointcloud_h pointcloud, mv_3d_pointcloud_ty
 {
 #ifdef MV_3D_POINTCLOUD_IS_AVAILABLE
        auto s = static_cast<mv_3d_pointcloud_s *>(pointcloud);
-       if (!s) {
+       if (!s)
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+
+       if (!s->num_points) {
                LOGE("Pointcloud data is NULL");
                return MEDIA_VISION_ERROR_INVALID_PARAMETER;
        }
 
+       auto _pcd = std::make_shared<geometry::PointCloud>();
+       _pcd->points_.clear();
+       _pcd->colors_.clear();
+       _pcd->normals_.clear();
+
+       if (s->num_points > 0) {
+               _pcd->points_.resize(s->num_points);
+               memcpy(_pcd->points_.data(), s->points, sizeof(double) * 3 * s->num_points);
+       }
+       utility::LogInfo("pcd points = {}", _pcd->points_.size());
+
+       if (s->has_colors) {
+               _pcd->colors_.resize(s->num_points);
+               memcpy(_pcd->colors_.data(), s->colors, sizeof(double) * 3 * s->num_points);
+       }
+       utility::LogInfo("pcd colors = {}", _pcd->colors_.size());
+
+       if (s->has_normals) {
+               _pcd->normals_.resize(s->num_points);
+               memcpy(_pcd->normals_.data(), s->normals, sizeof(double) * 3 * s->num_points);
+       }
+       utility::LogInfo("OUT >> pcd normals = {}", _pcd->normals_.size());
+
        if (access(mPointcloudOutputPath.c_str(), W_OK) != 0) {
                if (errno == EACCES || errno == EPERM) {
                        utility::LogInfo("Fail to access path[%s]: Permission Denied", mPointcloudOutputPath.c_str());
@@ -488,13 +552,17 @@ int Mv3d::WritePointcloudFile(mv_3d_pointcloud_h pointcloud, mv_3d_pointcloud_ty
 
        std::string fullPath = mPointcloudOutputPath + std::string("/") + std::string(fileName);
 
-       if (!io::WritePointCloud(fullPath.c_str(), *(s->pointcloud), { bText, false, false, {} })) {
+       if (!io::WritePointCloud(fullPath.c_str(), *_pcd, { bText, false, false, {} })) {
                utility::LogError("Failed to write {}", fullPath.c_str());
                return MEDIA_VISION_ERROR_INTERNAL;
        }
 
        utility::LogInfo("Successfully wrote {}", fullPath.c_str());
 
+       _pcd->points_.clear();
+       _pcd->colors_.clear();
+       _pcd->normals_.clear();
+
        return MEDIA_VISION_ERROR_NONE;
 #else
        return MEDIA_VISION_ERROR_NOT_SUPPORTED;
index 685f10cec1480711f1f1cfdf9c38786d424c123c..196cbb13e1e3c32f157a249008786e255dce41cb 100644 (file)
@@ -21,7 +21,6 @@
 
 #include "mv_3d_internal.h"
 #include "mv_private.h"
-#include "mv_3d_private.h"
 #include "Mv3d.h"
 
 #define DISTANCE_THRESHOLD 0.01
@@ -33,6 +32,66 @@ using namespace open3d;
 using namespace mediavision::mv3d;
 #endif
 
+#ifdef MV_3D_POINTCLOUD_IS_AVAILABLE
+static int _convert_to_open3d(mv_3d_pointcloud_s *src, geometry::PointCloud &dst)
+{
+       if (!src)
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+
+       dst.points_.clear();
+       dst.colors_.clear();
+       dst.normals_.clear();
+
+       if (src->num_points > 0) {
+               dst.points_.resize(src->num_points);
+               memcpy(dst.points_.data(), src->points, sizeof(double) * 3 * src->num_points);
+       }
+
+       if (src->has_colors) {
+               dst.colors_.resize(src->num_points);
+               memcpy(dst.colors_.data(), src->colors, sizeof(double) * 3 * src->num_points);
+       }
+
+       if (src->has_normals) {
+               dst.normals_.resize(src->num_points);
+               memcpy(dst.normals_.data(), src->normals, sizeof(double) * 3 * src->num_points);
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+
+static int _convert_to_mv3d(std::shared_ptr<geometry::PointCloud> src, mv_3d_pointcloud_s *dst)
+{
+       if (!dst)
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+
+       dst->num_points = src->points_.size();
+
+       if (src->HasPoints()) {
+               dst->points = new mv_vec3d_s[dst->num_points];
+               memcpy(dst->points, src->points_.data(), sizeof(double) * 3 * dst->num_points);
+       }
+
+       if (src->HasColors()) {
+               dst->colors = new mv_vec3d_s[dst->num_points];
+               dst->has_colors = true;
+               memcpy(dst->colors, src->colors_.data(), sizeof(double) * 3 * dst->num_points);
+       } else {
+               dst->has_colors = false;
+       }
+
+       if (src->HasNormals()) {
+               dst->normals = new mv_vec3d_s[dst->num_points];
+               dst->has_normals = true;
+               memcpy(dst->normals, src->normals_.data(), sizeof(double) * 3 * dst->num_points);
+       } else {
+               dst->has_normals = false;
+       }
+
+       return MEDIA_VISION_ERROR_NONE;
+}
+#endif
+
 #ifdef MV_3D_POINTCLOUD_IS_AVAILABLE
 int mv_3d_pointcloud_plane_model_create(mv_3d_pointcloud_plane_model_h *handle)
 {
@@ -127,11 +186,20 @@ int mv_3d_pointcloud_segment_plane(mv_3d_h mv3d, mv_3d_pointcloud_h pointcloud,
 
        auto s = static_cast<mv_3d_pointcloud_s *>(pointcloud);
 
+       if (!s->num_points) {
+               LOGE("Pointcloud data is NULL");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
        Eigen::Vector4d *best_plane_model = new Eigen::Vector4d;
        std::vector<size_t> *plane_inlier = new std::vector<size_t>;
 
-       std::tie(*best_plane_model, *plane_inlier) =
-                       s->pointcloud->SegmentPlane(DISTANCE_THRESHOLD, RANSAC_NUMBER, NUM_ITERATIONS);
+       auto _pcd = std::make_shared<geometry::PointCloud>();
+       int ret = _convert_to_open3d(s, *_pcd);
+       if (ret != MEDIA_VISION_ERROR_NONE)
+               return ret;
+
+       std::tie(*best_plane_model, *plane_inlier) = _pcd->SegmentPlane(DISTANCE_THRESHOLD, RANSAC_NUMBER, NUM_ITERATIONS);
 
        *model = (mv_3d_pointcloud_plane_model_h) best_plane_model;
        *inlier = (mv_3d_pointcloud_plane_inlier_h) plane_inlier;
@@ -158,14 +226,37 @@ int mv_3d_pointcloud_plane_write_file(mv_3d_h mv3d, mv_3d_pointcloud_plane_model
        MEDIA_VISION_NULL_ARG_CHECK(inlier);
        MEDIA_VISION_FUNCTION_ENTER();
 
-       auto plane_inlier = static_cast<std::vector<size_t> *>(inlier);
        auto s = static_cast<mv_3d_pointcloud_s *>(pointcloud);
 
-       mv_3d_pointcloud_s _pcd { .type = MV_3D_POINTCLOUD_TYPE_PCD_BIN,
-                                                         .pointcloud = s->pointcloud->SelectByIndex(*plane_inlier) };
+       if (!s->num_points) {
+               LOGE("Pointcloud data is NULL");
+               return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+       }
+
+       auto _pcd = std::make_shared<geometry::PointCloud>();
+       int ret = _convert_to_open3d(s, *_pcd);
+       if (ret != MEDIA_VISION_ERROR_NONE)
+               return ret;
+
+       auto plane_inlier = static_cast<std::vector<size_t> *>(inlier);
+       auto _pcd_inlier = _pcd->SelectByIndex(*plane_inlier);
+
+       mv_3d_pointcloud_s *pcd_inlier = new mv_3d_pointcloud_s;
+       ret = _convert_to_mv3d(_pcd_inlier, pcd_inlier);
+       if (ret != MEDIA_VISION_ERROR_NONE)
+               return ret;
 
        auto pMv3d = static_cast<Mv3d *>(mv3d);
-       int ret = pMv3d->WritePointcloudFile(static_cast<mv_3d_pointcloud_h>(&_pcd), type, filename);
+       ret = pMv3d->WritePointcloudFile(static_cast<mv_3d_pointcloud_h>(pcd_inlier), type, filename);
+
+       if (pcd_inlier->num_points > 0)
+               delete[] pcd_inlier->points;
+       if (pcd_inlier->has_colors)
+               delete[] pcd_inlier->colors;
+       if (pcd_inlier->has_normals)
+               delete[] pcd_inlier->normals;
+       delete pcd_inlier;
+
        if (ret != MEDIA_VISION_ERROR_NONE) {
                LOGE("Failed to write pointcloud plane file");
                ret = MEDIA_VISION_ERROR_INTERNAL;
index 623ed6d103715e8a4d8f7915f9a5187b3a72b6e6..27cd706306b9c159caa0b3d2e039429100b6ef7b 100644 (file)
@@ -379,7 +379,6 @@ find . -name '*.gcno' -not -path "./test/*" -exec cp --parents '{}' "$gcno_obj_d
 %{_includedir}/media/mv_3d.h
 %{_includedir}/media/mv_3d_type.h
 %{_includedir}/media/mv_3d_internal.h
-%{_includedir}/media/mv_3d_private.h
 %{_libdir}/pkgconfig/*3d.pc
 %endif