--- /dev/null
+/**
+ * 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.
+ */
+
+#include "gtest/gtest.h"
+#include <iostream>
+#include <memory>
+#include <opencv2/opencv.hpp>
+
+#include "InferenceServiceFactory.h"
+#include "IInferenceServiceInterface.h"
+#include "SingleoCommonTypes.h"
+#include "TaskManager.h"
+#include "InferenceNode.h"
+#include "CallbackNode.h"
+
+#define IMG_FACE TEST_RES_PATH "/usr/share/capi-media-vision/res/inference/images/faceDetection.jpg"
+
+using namespace std;
+using namespace testing;
+using namespace singleo;
+using namespace singleo::inference;
+using namespace singleo::services;
+
+void ExampleNodeCallback(vector<BaseResultType *> &results, shared_ptr<BaseDataType> inputData, void *user_data)
+{
+ shared_ptr<ImageDataType> imageData = dynamic_pointer_cast<ImageDataType>(inputData);
+ size_t buffer_size = imageData->width * imageData->height * imageData->byte_per_pixel;
+ CallbackNode *node = static_cast<CallbackNode *>(user_data);
+ ImageDataType newImage;
+
+ newImage = *imageData;
+ newImage.ptr = new unsigned char[buffer_size];
+ memcpy(newImage.ptr, imageData->ptr, buffer_size);
+ newImage.custom = true;
+
+ cv::Mat cv_image(cv::Size(newImage.width, newImage.height), CV_MAKETYPE(CV_8U, 3), newImage.ptr);
+
+ cout << "Face detection result" << endl;
+ for (auto r : results) {
+ if (r->_type != ResultType::FACE_DETECTION) {
+ cout << "invalid result type" << endl;
+ continue;
+ }
+
+ FdResultType *f_r = dynamic_cast<FdResultType *>(r);
+
+ for (auto rect : f_r->_rects)
+ cout << rect.left << " x " << rect.top << " ~ " << rect.right << " x " << rect.bottom << endl;
+ }
+
+ node->setOutput(make_shared<ImageDataType>(newImage));
+};
+
+// GraphA : input ----> face_detection ----> callback ----> face_landmark_detection ----> output
+TEST(SingloTaskManager, MultipleNodesBasedGraphAShouldWork)
+{
+ cv::Mat cv_image = cv::imread(IMG_FACE, cv::IMREAD_COLOR);
+ cv::cvtColor(cv_image, cv_image, cv::COLOR_BGR2RGB);
+
+ if (cv_image.empty()) {
+ cout << "Fail to read a given image file." << endl;
+ return;
+ }
+
+ ImageDataType image_data;
+
+ image_data.width = cv_image.cols;
+ image_data.height = cv_image.rows;
+ image_data.byte_per_pixel = cv_image.channels();
+ image_data.ptr = cv_image.data;
+
+ auto factory = InferenceServiceFactory::instance().create("MvInferenceServiceFactory");
+
+ auto taskManager = make_unique<TaskManager>();
+ const unsigned int maxIteration = 10;
+
+ for (unsigned int cnt = 0; cnt < maxIteration; ++cnt) {
+ taskManager->addInput(image_data);
+
+ auto face_detection_node = make_shared<InferenceNode>();
+ face_detection_node->setName("face_detection");
+ face_detection_node->setInferenceService(factory->createFaceDetection());
+ taskManager->addNode(face_detection_node);
+
+ auto callback_node = make_shared<CallbackNode>();
+ callback_node->setName("callback");
+ callback_node->setCb(&ExampleNodeCallback, callback_node.get());
+ callback_node->addDependency(face_detection_node);
+ taskManager->addNode(callback_node);
+
+ auto face_landmark_node = make_shared<InferenceNode>();
+ face_landmark_node->setName("face_landmark");
+ face_landmark_node->setInferenceService(factory->createFaceLandmarkDetection());
+ face_landmark_node->addDependency(callback_node);
+ taskManager->addNode(face_landmark_node);
+
+ taskManager->run();
+
+ cout << "Face landmark result" << endl;
+ auto result = dynamic_cast<FldResultType &>(taskManager->output());
+ for (auto &point : result._points)
+ cout << point.x << " x " << point.y << endl;
+
+ taskManager->clear();
+ }
+}
+
+// GraphB:
+// -----> face_detection
+// input | |----> callback ----> face_landmark_detection ----> output
+// -----> face_detection
+TEST(SingloTaskManager, MultipleNodesBasedGraphBShouldWork)
+{
+ cv::Mat cv_image = cv::imread(IMG_FACE, cv::IMREAD_COLOR);
+ cv::cvtColor(cv_image, cv_image, cv::COLOR_BGR2RGB);
+
+ if (cv_image.empty()) {
+ cout << "Fail to read a given image file." << endl;
+ return;
+ }
+
+ ImageDataType image_data;
+
+ image_data.width = cv_image.cols;
+ image_data.height = cv_image.rows;
+ image_data.byte_per_pixel = cv_image.channels();
+ image_data.ptr = cv_image.data;
+
+ auto factory = InferenceServiceFactory::instance().create("MvInferenceServiceFactory");
+
+ auto taskManager = make_unique<TaskManager>();
+ const unsigned int maxIteration = 10;
+
+ for (unsigned int cnt = 0; cnt < maxIteration; ++cnt) {
+ taskManager->addInput(image_data);
+
+ auto face_detection_node_a = make_shared<InferenceNode>();
+ face_detection_node_a->setName("face_detectionA");
+ face_detection_node_a->setInferenceService(factory->createFaceDetection());
+ taskManager->addNode(face_detection_node_a);
+
+ auto face_detection_node_b = make_shared<InferenceNode>();
+ face_detection_node_b->setName("face_detectionB");
+ face_detection_node_b->setInferenceService(factory->createFaceDetection());
+ taskManager->addNode(face_detection_node_b);
+
+ auto callback_node = make_shared<CallbackNode>();
+ callback_node->setName("callback");
+ callback_node->setCb(&ExampleNodeCallback, callback_node.get());
+ callback_node->addDependency(face_detection_node_a);
+ callback_node->addDependency(face_detection_node_b);
+ taskManager->addNode(callback_node);
+
+ auto face_landmark_node = make_shared<InferenceNode>();
+ face_landmark_node->setName("face_landmark");
+ face_landmark_node->setInferenceService(factory->createFaceLandmarkDetection());
+ face_landmark_node->addDependency(callback_node);
+ taskManager->addNode(face_landmark_node);
+
+ taskManager->run();
+
+ cout << "Face landmark result" << endl;
+ auto result = dynamic_cast<FldResultType &>(taskManager->output());
+ for (auto &point : result._points)
+ cout << point.x << " x " << point.y << endl;
+
+ taskManager->clear();
+ }
+}