[WIP-13] Add asynchronous operation (performAsync)
authorTae-Young Chung <ty83.chung@samsung.com>
Thu, 9 May 2024 01:03:56 +0000 (10:03 +0900)
committerTae-Young Chung <ty83.chung@samsung.com>
Thu, 9 May 2024 01:03:56 +0000 (10:03 +0900)
Change-Id: I56e27d062904abb92cbe6d3ec00102ad80a9ceda
Signed-off-by: Tae-Young Chung <ty83.chung@samsung.com>
14 files changed:
capi/singleo_native_capi.h
inference/backends/private/src/PrivateInferenceFaceService.cpp
input/backends/opencv/src/OpencvBackend.cpp
services/auto_zoom/include/AutoZoom.h
services/auto_zoom/src/AutoZoom.cpp
services/common/include/IService.h
services/common/include/ServiceDataType.h
services/singleo_native_capi.cpp
services/smart_pointer/include/SmartPointer.h
services/smart_pointer/include/SmartPointerDataType.h [new file with mode: 0644]
services/smart_pointer/src/GazeEstimator.cpp
services/smart_pointer/src/SmartPointer.cpp
test/services/CMakeLists.txt
test/services/test_camera_dummy.cpp

index e740dd1f60ff1492a9868b28b1f83937c8d65ccf..2343cc73e30592e9e1694521cf97d9b7c757fd53 100644 (file)
@@ -211,6 +211,31 @@ int singleo_service_get_result_cnt(singleo_service_h handle, unsigned int *cnt);
  */
 int singleo_service_get_result_int(singleo_service_h handle, unsigned int idx, const char *key, unsigned int *value);
 
+/**
+ * @internal
+ * @brief Gets float type of result corresponding to a given index value.
+ *
+ * @since_tizen 9.0
+ *
+ * @param[in] handle   The handle to the service.
+ * @param[in] idx      Index value to results.
+ * @param[in] key      Key string to a certain member of the result.
+ * @param[out] value   Pointer to the float variable to be stored.
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @retval #SINGLEO_SERVICE_ERROR_NONE Successful
+ * @retval #SINGLEO_SERVICE_ERROR_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #SINGLEO_SERVICE_ERROR_ERROR_INVALID_OPERATION Invalid operation
+ *
+ * @pre Create a source handle by calling singleo_service_create()
+ * @pre Perform a requested service by
+ *      calling singleo_service_perform(),
+ *              singleo_service_perform_with_file(),
+ *              singleo_service_perform_with_image_data(),
+ *              or singleo_service_perform_with_raw_data()
+ */
+int singleo_service_get_result_float(singleo_service_h handle, unsigned int idx, const char *key, float *value);
+
 /**
  * @internal
  * @brief Gets string type of result corresponding to a given index value.
index 22e8cbbd67726f984c06be61a145f6962abee6b5..f3dc9541ee0cb8e33688a6fb18b7e369b2039112 100644 (file)
@@ -141,6 +141,7 @@ void PrivateInferenceFaceService::invoke(BaseDataType &input)
                throw invalid_argument("Input type not support.");
        }
 
+    SINGLEO_LOGD("PrivateInferenceFaceService: invoke");
     ImageDataType &data = dynamic_cast<ImageDataType &>(input);
     // cv::Mat cvData(cv::Size(data.width, data.height), CV_MAKE_TYPE(CV_8U, data.byte_per_pixel), data.ptr);
     cv::Mat cvData_(cv::Size(data.width, data.height), CV_MAKE_TYPE(CV_8U, data.byte_per_pixel), data.ptr);
index 8c5d925385072a99aa0136f05b441d96289810c1..18b5e0c453af9240daea905782376a68671adc8f 100644 (file)
@@ -110,8 +110,6 @@ void OpencvBackend::capture(BaseDataType &out_data)
 
 void OpencvBackend::threadLoop()
 {
-       SINGLEO_LOGD("OpencvBackend: stream off.");
-
        ImageDataType data;
 
        while (!_exit_thread) {
@@ -132,6 +130,8 @@ void OpencvBackend::streamOn()
 
 void OpencvBackend::streamOff()
 {
+       SINGLEO_LOGD("OpencvBackend: stream off.");
+
        _exit_thread = true;
        _thread_handle->join();
 }
index cd65836409d0c41cc7105592eaad1207bef5ea1e..8adb358fa430b783b35b795c66bbea460d7b5144 100644 (file)
@@ -74,6 +74,7 @@ public:
        void performAsync() override;
        void getResultCnt(unsigned int *cnt) override;
        void getResultInt(unsigned int idx, std::string key, unsigned int *value) override;
+       void getResultFloat(unsigned int idx, std::string key, float *value) override;
        void registerUserCallback(singleo_user_cb_t user_cb, void *user_data) override;
        void unregisterUserCallback() override;
 
index 010081fd9b3835ad5cb057ef763b88daf6810e46..3a9238a8a72519f22addd5a89ee9e875d0cbdc04 100644 (file)
@@ -248,6 +248,10 @@ void AutoZoom::getResultInt(unsigned int idx, std::string key, unsigned int *val
        }
 }
 
+void AutoZoom::getResultFloat(unsigned int idx, std::string key, float *value)
+{
+}
+
 void AutoZoom::registerUserCallback(singleo_user_cb_t user_cb, void *user_data)
 {
        _user_cb = user_cb;
index de774ac8f823cdc779aa9b73c349b9ef1cc44a25..36785e8f20f9e574d3d25651bf0f98e0279cef57 100644 (file)
@@ -36,6 +36,7 @@ public:
        virtual void performAsync() = 0;
        virtual void getResultCnt(unsigned int *cnt) = 0;
        virtual void getResultInt(unsigned int idx, std::string key, unsigned int *value) = 0;
+       virtual void getResultFloat(unsigned int idx, std::string key, float *value) = 0;
        virtual void registerUserCallback(singleo_user_cb_t user_cb, void *user_data) = 0;
        virtual void unregisterUserCallback() = 0;
 };
index b992d4df811cf0d825790c5c11044794dfb8f5b9..8091d1b4d430bd7489190258d8e8e2bfacf75fe7 100644 (file)
@@ -26,7 +26,7 @@ namespace services
 {
 // TODO
 
-enum class ServiceResultType { NONE, AUTO_ZOOM };
+enum class ServiceResultType { NONE, AUTO_ZOOM, SMART_POINTER };
 
 struct ServiceBaseResultType {
        ServiceResultType _result_type { ServiceResultType::NONE };
index 40d2af5061e3d8b3aff646c8a8d8869a9aa85a85..d02f39bf525edc6eca039be32d540b505a393db3 100644 (file)
@@ -171,6 +171,18 @@ int singleo_service_get_result_int(singleo_service_h handle, unsigned int idx, c
        return SINGLEO_ERROR_NONE;
 }
 
+int singleo_service_get_result_float(singleo_service_h handle, unsigned int idx, const char *key, float *value)
+{
+       try {
+               auto context = static_cast<Context *>(handle);
+               context->_service_handle->getResultFloat(idx, key, value);
+       } catch (const BaseException &e) {
+               return e.getError();
+       }
+
+       return SINGLEO_ERROR_NONE;
+}
+
 int singleo_service_register_user_callback(singleo_service_h handle, singleo_user_cb_t user_cb, void *user_data)
 {
        try {
index 6c8d27ee1145e973dd0d492e0a7a1bfaca859527..77e203421e7a66e1d828a58d0e2e963578847342 100644 (file)
@@ -23,6 +23,8 @@
 #include "SingleoInputManager.h"
 #include "GazeEstimator.h"
 #include "InputCamera.h"
+#include "AsyncManager.h"
+#include "SmartPointerDataType.h"
 
 namespace singleo
 {
@@ -37,11 +39,19 @@ private:
        std::unique_ptr<singleo::input::IInputService> _data_feeder;
     SingleoInputManager _input_image_data;
     PoseVector _head_pose;
+       PointerPosition _pointerPosition;
+       std::map<std::string, PoseAngle> _result_keys = { { "PITCH", PoseAngle::PITCH },
+                                                                                                               { "YAW", PoseAngle::YAW },
+                                                                                                               { "ROLL", PoseAngle::ROLL } };
 
+       bool _async_mode;
+       std::unique_ptr<AsyncManager<ImageDataType, PointerPosition> > _async_manager;
        singleo_user_cb_t _user_cb {};
-       static void internalDataFeederCb(BaseDataType &data, void *user_data);
        void *_user_data {};
 
+       static void internalDataFeederCb(BaseDataType &data, void *user_data);
+       void updateResult(PoseVector &result);
+
 public:
        explicit SmartPointer(input::InputConfigBase &config);
        virtual ~SmartPointer();
@@ -55,8 +65,19 @@ public:
        void performAsync() override;
        void getResultCnt(unsigned int *cnt) override;
        void getResultInt(unsigned int idx, std::string key, unsigned int *value) override;
+       void getResultFloat(unsigned int idx, std::string key, float *value) override;
        void registerUserCallback(singleo_user_cb_t user_cb, void *user_data) override;
        void unregisterUserCallback() override;
+
+       std::unique_ptr<AsyncManager<ImageDataType, PointerPosition> > &getAsyncManager()
+       {
+               return _async_manager;
+       }
+
+       std::unique_ptr<GazeEstimator> &getGazeEstimator()
+       {
+               return _gaze_estimator;
+       }
 };
 } // smartpointer
 } // services
diff --git a/services/smart_pointer/include/SmartPointerDataType.h b/services/smart_pointer/include/SmartPointerDataType.h
new file mode 100644 (file)
index 0000000..1e9920d
--- /dev/null
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2024 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 __SMART_POINTER_DATA_TYPES_H__
+#define __SMART_POINTER_DATA_TYPES_H__
+
+#include <vector>
+#include "SingleoCommonTypes.h"
+#include "ServiceDataType.h"
+#include "PoseVector.h"
+
+namespace singleo
+{
+namespace services
+{
+namespace smartpointer
+{
+enum class PoseAngle { PITCH, YAW, ROLL };
+
+struct PointerPosition : public ServiceBaseResultType {
+       PointerPosition() : ServiceBaseResultType(ServiceResultType::SMART_POINTER)
+       {}
+       unsigned int frame_number {};
+       PoseVector pose;
+};
+
+}
+}
+}
+
+#endif
\ No newline at end of file
index 97efb6a8cc2becce12a5acda2de50ad502c40385..4a2b5e288ccb9da29f00352d8e9caf12cb3c759e 100644 (file)
@@ -51,23 +51,22 @@ GazeEstimator::~GazeEstimator()
 
 PoseVector &GazeEstimator::estimateHeadpose(BaseDataType &input)
 {
-    _face_estimator->invoke(input);
-
-    auto &result = _face_estimator->result();
-
+     _face_estimator->invoke(input);
+     auto &result = _face_estimator->result();
     if (result._rects.empty())
         return _headPose;
-    
-    _headPose = _head_pose_estimator->estimate(result._landmarks[0]);
-    vector<Point2f> poseAxes = _head_pose_estimator->getPoseAxes();
 
-    ImageDataType &data = dynamic_cast<ImageDataType &>(input);
-    cv::Mat _dump(cv::Size(data.width, data.height), CV_MAKETYPE(CV_8U, data.byte_per_pixel), data.ptr);
-    cv::line(_dump, cv::Point(poseAxes[0].x, poseAxes[0].y), cv::Point(poseAxes[1].x, poseAxes[1].y), cv::Scalar(0, 0, 255), 2); // x - red
-    cv::line(_dump, cv::Point(poseAxes[0].x, poseAxes[0].y), cv::Point(poseAxes[2].x, poseAxes[2].y), cv::Scalar(0, 255, 0), 2); // y - green
-    cv::line(_dump, cv::Point(poseAxes[0].x, poseAxes[0].y), cv::Point(poseAxes[3].x, poseAxes[3].y), cv::Scalar(255, 0, 0), 2); // z - blue
+     _headPose = _head_pose_estimator->estimate(result._landmarks[0]);
+    // vector<Point2f> poseAxes = _head_pose_estimator->getPoseAxes();
+
+    // ImageDataType &data = dynamic_cast<ImageDataType &>(input);
+    // cv::Mat _dump(cv::Size(data.width, data.height), CV_MAKETYPE(CV_8U, data.byte_per_pixel), data.ptr);
+    // cv::line(_dump, cv::Point(poseAxes[0].x, poseAxes[0].y), cv::Point(poseAxes[1].x, poseAxes[1].y), cv::Scalar(0, 0, 255), 2); // x - red
+    // cv::line(_dump, cv::Point(poseAxes[0].x, poseAxes[0].y), cv::Point(poseAxes[2].x, poseAxes[2].y), cv::Scalar(0, 255, 0), 2); // y - green
+    // cv::line(_dump, cv::Point(poseAxes[0].x, poseAxes[0].y), cv::Point(poseAxes[3].x, poseAxes[3].y), cv::Scalar(255, 0, 0), 2); // z - blue
 
-    cv::imwrite("dump_headpose.jpg", _dump);
+    // cv::imwrite("dump_headpose.jpg", _dump);
 
     return _headPose;
 }
index 79ac0518463dc2cd716a37e9cd087dd77def7274..bbf22a90b29563ee24695abb1bfed78cc558c3e8 100644 (file)
@@ -46,31 +46,35 @@ SmartPointer::SmartPointer(InputConfigBase& config)
                SINGLEO_LOGD("Camera input service has been initialized.");
        }
 
+       _async_mode = false;
+
 }
 
 SmartPointer::~SmartPointer()
 {
+       if (_async_mode)
+               _data_feeder->streamOff();
 }
 
 void SmartPointer::internalDataFeederCb(BaseDataType &data, void *user_data)
 {
        auto smart_pointer = static_cast<SmartPointer *>(user_data);
 
-       ImagePreprocessor preprocessor(data);
-       ImageDataType preprocessed = dynamic_cast<ImageDataType &>(preprocessor.getData());
-       ImageDataType copied = preprocessed;
-       size_t buffer_size = copied.width * copied.height * copied.byte_per_pixel;
+       ImageDataType &image_data = dynamic_cast<ImageDataType &>(data);
+       size_t buffer_size = image_data.width * image_data.height * image_data.byte_per_pixel;
 
+       ImageDataType copied = image_data;
        // We have to avoid from grapping input feed stream so copy the captured data to new one.
        // Ps. This allocated buffer should be released as soon as the completion of invoke in async manager's thread loop.
        copied.ptr = new unsigned char[buffer_size];
-       memcpy(copied.ptr, preprocessed.ptr, buffer_size);
+       memcpy(copied.ptr, image_data.ptr, buffer_size);
 
        if (smart_pointer->_user_cb) {
                smart_pointer->_user_cb(copied.ptr, copied.width, copied.height, copied.byte_per_pixel, smart_pointer->_user_data);
        }
 
-       // delete copied.ptr;
+       if (smart_pointer->getAsyncManager()->pushInput(copied) != SINGLEO_ERROR_NONE)
+               delete [] copied.ptr;
 }
 
 void SmartPointer::add_input(BaseDataType &input_data)
@@ -107,23 +111,71 @@ void SmartPointer::perform()
        }
 
        _head_pose = _gaze_estimator->estimateHeadpose(preprocessor.getData());
+       updateResult(_head_pose);
 }
 
 
 void SmartPointer::performAsync()
 {
+       if (!_data_feeder) {
+               SINGLEO_LOGE("This API is valid only the case that data feed service is used.");
+               throw InvalidOperation("Invalid API request.");
+       }
+
+       _data_feeder->streamOn();
 
+       // asynchronous handling
+       _async_mode = true;
+       _async_manager = make_unique<AsyncManager<ImageDataType, PointerPosition> >();
+       _async_manager->registerInvokeCb(this, [this](IService *service, BaseDataType &data) {
+               auto smart_pointer = static_cast<SmartPointer *>(service);
+
+               auto head_pose = smart_pointer->getGazeEstimator()->estimateHeadpose(data);
+               smart_pointer->updateResult(head_pose);
+               auto alloc_data = dynamic_cast<ImageDataType &>(data);
+               delete [] alloc_data.ptr;
+       });
+}
+
+void SmartPointer::updateResult(PoseVector &result)
+{
+       PointerPosition pos;
+       pos.pose = result;
+
+       if (_async_mode)
+               _async_manager->pushOutput(pos);
+       else
+               _pointerPosition = pos;
 }
 
 void SmartPointer::getResultCnt(unsigned int *cnt)
 {
-    *cnt = 1;
+       if (_async_mode) {
+               _pointerPosition = _async_manager->popOutput();
+       }
+       *cnt = 1;
 }
 
 void SmartPointer::getResultInt(unsigned int idx, std::string key, unsigned int *value)
 {
 
 }
+
+void SmartPointer::getResultFloat(unsigned int idx, std::string key, float *value)
+{
+       switch (_result_keys[key]) {
+       case PoseAngle::PITCH:
+               *value = _pointerPosition.pose._rot_vec.x;
+               break;
+       case PoseAngle::YAW:
+               *value = _pointerPosition.pose._rot_vec.y;
+               break;
+       case PoseAngle::ROLL:
+               *value = _pointerPosition.pose._rot_vec.z;
+               break;
+       }
+}
+
 void SmartPointer::registerUserCallback(singleo_user_cb_t user_cb, void *user_data)
 {
        _user_cb = user_cb;
index 20b47edfc4a7bad2edd547d28dd73dc555af1908..91259bb435478cf82781405a9ac7c29b69bbdc0f 100644 (file)
@@ -37,5 +37,5 @@ ENDIF()
 SET(TEST_CAMERA_DUMMY test_camera_dummy.cpp)
 ADD_EXECUTABLE(test_camera_dummy ${TEST_CAMERA_DUMMY})
 TARGET_INCLUDE_DIRECTORIES(test_camera_dummy PRIVATE ../../capi/ ../../common/include ../../visualizer/include)
-TARGET_LINK_LIBRARIES(test_camera_dummy gtest gtest_main pthread singleo_service singleo_visualizer)
+TARGET_LINK_LIBRARIES(test_camera_dummy gtest gtest_main pthread singleo_service singleo_visualizer opencv_imgcodecs)
 INSTALL(TARGETS test_camera_dummy DESTINATION ${CMAKE_INSTALL_BINDIR})
index 17fce9e951137bde2cfa6ff9861f33d5986f9d57..ea40d036a13300334ccfeeb8eb472bdca2a7d2d2 100644 (file)
@@ -29,17 +29,55 @@ using namespace std;
 
 static singleo_service_h handle;
 
+void user_callback(void *user_data)
+{
+       singleo_service_h context = static_cast<singleo_service_h>(user_data);
+       bool is_loop_exit = false;
+       unsigned long frame_number = 0;
+
+       while (!is_loop_exit) {
+               unsigned int cnt;
+               int ret = singleo_service_get_result_cnt(handle, &cnt);
+               if (ret != SINGLEO_ERROR_NONE)
+                       continue;
+
+               float pitch, yaw, roll;
+               singleo_service_get_result_float(handle, 0, "PITCH", &pitch);
+               singleo_service_get_result_float(handle, 0, "YAW", &yaw);
+               singleo_service_get_result_float(handle, 0, "ROLL", &roll);
+
+               cout << "[Pitch, Yaw, Roll]: [ " << pitch << ", " << yaw << ", " << roll << " ]" << endl;
+       }
+}
+
+void data_feeder_cb(unsigned char *buffer, unsigned int width, unsigned int height, unsigned int bytes_per_pixel,
+                                  void *user_data)
+{
+       cv::Mat result(cv::Size(width, height), CV_MAKETYPE(CV_8U, bytes_per_pixel), buffer);
+       cv::Mat vizData;
+       cv::cvtColor(result, vizData, cv::COLOR_RGB2RGBA);
+
+       singleo_util_visualizer_2d(vizData, NULL);
+}
 
 TEST(CameraDummyTest, CameraDisplayed)
 {
-       int ret = singleo_service_create("service=smart_pointer, input_feed=camera, camera_id=4, fps=30, async=0",
+       int ret = singleo_service_create("service=smart_pointer, input_feed=camera, camera_id=4, fps=15, async=1",
                                                                         &handle);
        ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
 
-       for (int i = 0; i < 10; ++i) {
-               ret = singleo_service_perform(handle);
-               ASSERT_EQ(ret, SINGLEO_ERROR_NONE);     
-       }
+       ret = singleo_service_register_user_callback(handle, data_feeder_cb, &handle);
+       ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+       ret = singleo_service_perform(handle);
+       ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
+
+       unique_ptr<thread> thread_handle = make_unique<thread>(&user_callback, static_cast<void *>(handle));
+
+       thread_handle->join();
+
+       ret = singleo_service_unregister_user_callback(handle);
+       ASSERT_EQ(ret, SINGLEO_ERROR_NONE);
 
        ret = singleo_service_destroy(handle);
        ASSERT_EQ(ret, SINGLEO_ERROR_NONE);