"Name of the library will be built for surveillance module (without extension).")
set(MV_INFERENCE_LIB_NAME "mv_inference" CACHE STRING
"Name of the library will be built for inference module (without extension).")
+set(MV_TRAINING_LIB_NAME "mv_training" CACHE STRING
+ "Name of the library will be built for training module (without extension).")
+set(MV_FACE_RECOG_LIB_NAME "mv_face_recognition" CACHE STRING
+ "Name of the library will be built for face recognition module (without extension).")
include(FindPkgConfig)
include(GNUInstallDirs)
--- /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.
+ */
+
+#ifndef __MEDIAVISION_FACE_RECOGNITION_H__
+#define __MEDIAVISION_FACE_RECOGNITION_H__
+
+#include <mv_common.h>
+#include <mv_face_recognition_type.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief Creates face recognition handle.
+ * @details Use this function to create an face recognition handle. After the creation
+ * the handle has to be prepared with mv_face_recognition_prepare() function to prepare
+ * face recognition resources.
+ *
+ * @since_tizen 7.0
+ *
+ * @remarks The @a handle should be released using mv_face_recognition_destroy().
+ *
+ * @param[out] handle The handle to the face recognition to be created
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory
+ *
+ * @see mv_face_recognition_destroy()
+ * @see mv_face_recognition_prepare()
+ */
+int mv_face_recognition_create(mv_face_recognition_h *handle);
+
+/**
+ * @brief Destroy face recognition handle and release all its resources.
+ *
+ * @since_tizen 7.0
+ *
+ * @param[in] handle The handle to the face recognition object to be destroyed
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ *
+ * @pre Create face recognition handle by using mv_face_recognition_create()
+ *
+ * @see mv_face_recognition_create()
+ */
+int mv_face_recognition_destroy(mv_face_recognition_h handle);
+
+/**
+ * @brief Prepare the resources for face recognition.
+ * @details Use this function to prepare the resources for face recognition.
+ *
+ * @since_tizen 7.0
+ *
+ * @param[in] handle The handle to the inference
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED Not supported
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ */
+int mv_face_recognition_prepare(mv_face_recognition_h handle);
+
+ /**
+ * @brief Register a new face on the @a source
+ * @details Use this function to register a new face.
+ * Each time when this function is called, a new face on the media source
+ * will be registered to internal database.
+ *
+ * @since_tizen 7.0
+ *
+ * @param [in] handle The handle to the face recognition object.
+ * @param [in] source The handle to the source of the media.
+ * @param [in] label The label to be registered.
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Source colorspace
+ * isn't supported
+ * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory
+ *
+ * @pre Create a source handle by calling @ref mv_create_source()
+ * @pre Create an face recognition handle by calling @ref mv_face_recognition_create()
+ * @pre Prepare an face recognition by calling @ref mv_face_recognition_prepare()
+ */
+ int mv_face_recognition_register(mv_face_recognition_h handle, mv_source_h source, const char *label);
+
+ /**
+ * @brief Unregister a new face on the @a source
+ * @details Use this function to unregister a given label.
+ * Each time when this function is called, all data related to the label
+ * will be removed from internal database.
+ *
+ * @since_tizen 7.0
+ *
+ * @param [in] handle The handle to the face recognition object.
+ * @param [in] label The label to be registered.
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Source colorspace
+ * isn't supported
+ * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory
+ *
+ * @pre Create an face recognition handle by calling @ref mv_face_recognition_create()
+ * @pre Prepare an face recognition by calling @ref mv_face_recognition_prepare()
+ */
+ int mv_face_recognition_unregister(mv_face_recognition_h handle, const char *label);
+
+ /**
+ * @brief Inference with a given face on the @a source
+ * @details Use this function to inference with a given source.
+ * This function returns an proper label string to a give source.
+ *
+ * @since_tizen 7.0
+ *
+ * @param [in] handle The handle to the face recognition object.
+ * @param [in] source The handle to the source of the media.
+ * @param [out] label The label to be inferenced.
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Source colorspace
+ * isn't supported
+ * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory
+ *
+ * @pre Create a source handle by calling @ref mv_create_source()
+ * @pre Create an face recognition handle by calling @ref mv_face_recognition_create()
+ * @pre Prepare an face recognition by calling @ref mv_face_recognition_prepare()
+ * @pre Register a new face by calling @ref mv_face_recognition_register()
+ */
+ int mv_face_recognition_inference(mv_face_recognition_h handle, mv_source_h source, char out_label[MAX_LABEL_SIZE]);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __TIZEN_MEDIAVISION_INFERENCE_H__ */
--- /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.
+ */
+
+#ifndef __MEDIAVISION_FACE_RECOGNITION_TYPE_H__
+#define __MEDIAVISION_FACE_RECOGNITION_TYPE_H__
+
+#include <mv_common.h>
+
+#define MAX_LABEL_SIZE 256
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+/**
+ * @brief The inference handle.
+ * @details Contains information about location of
+ * detected landmarks for one or more poses.
+ * @since_tizen 5.5
+ */
+typedef void *mv_face_recognition_h;
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MEDIAVISION_FACE_RECOGNITION_TYPE_H__ */
add_subdirectory(inference)
+add_subdirectory(training)
+add_subdirectory(face_recognition)
--- /dev/null
+project(${MV_FACE_RECOG_LIB_NAME})
+cmake_minimum_required(VERSION 2.6)
+
+pkg_check_modules(${PROJECT_NAME}_DEP REQUIRED inference-engine-interface-common training-engine-interface-common)
+file(GLOB MV_FACE_RECOG_SOURCE_LIST "${PROJECT_SOURCE_DIR}/src/*.c" "${PROJECT_SOURCE_DIR}/src/*.cpp")
+
+find_package(OpenCV REQUIRED dnn imgproc)
+if(NOT OpenCV_FOUND)
+ message(SEND_ERROR "OpenCV NOT FOUND")
+ return()
+endif()
+
+if(FORCED_STATIC_BUILD)
+ add_library(${PROJECT_NAME} STATIC ${MV_FACE_RECOG_SOURCE_LIST})
+else()
+ add_library(${PROJECT_NAME} SHARED ${MV_FACE_RECOG_SOURCE_LIST})
+endif()
+
+target_link_libraries(${PROJECT_NAME} ${MV_COMMON_LIB_NAME} ${OpenCV_LIBS} ${${PROJECT_NAME}_DEP_LIBRARIES} mv_inference mv_training)
+target_include_directories(${PROJECT_NAME} PRIVATE include ../inference/include ../training/include)
+install(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR})
--- /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.
+ */
+
+#ifndef BACKBONE_MODEL_INFO_H
+#define BACKBONE_MODEL_INFO_H
+
+#include "inference_engine_common_impl.h"
+
+typedef struct {
+ std::string layer_name;
+ inference_engine_tensor_info tensor_info;
+} model_layer_info;
+
+class BackboneModelInfo {
+public:
+ BackboneModelInfo(std::string model_file_path) { }
+ ~BackboneModelInfo() { }
+
+ virtual std::vector<model_layer_info>& GetInputLayerInfo() { return GetInputLayerInfo(); }
+ virtual std::vector<model_layer_info>& GetOutputLayerInfo() { return GetOutputLayerInfo(); }
+};
+
+#endif
\ No newline at end of file
--- /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.
+ */
+
+#ifndef FACE_NET_INFO_H
+#define FACE_NET_INFO_H
+
+#include "backbone_model_info.h"
+
+class FaceNetInfo : public BackboneModelInfo {
+private:
+ std::vector<model_layer_info> _input_layer_info;
+ std::vector<model_layer_info> _output_layer_info;
+ std::string _model_file_path;
+
+public:
+ FaceNetInfo(std::string model_file_path);
+ ~FaceNetInfo();
+
+ std::string GetModelFilePath();
+ std::vector<model_layer_info>& GetInputLayerInfo();
+ std::vector<model_layer_info>& GetOutputLayerInfo();
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 FACE_RECOGNITION_H
+#define FACE_RECOGNITION_H
+
+#include "training_engine_error.h"
+#include "training_engine_common_impl.h"
+#include "inference_engine_common_impl.h"
+#include "inference_engine_helper.h"
+#include "label_manager.h"
+#include "face_net_info.h"
+#include "simple_shot.h"
+
+class FaceRecognition {
+private:
+ std::unique_ptr<DataSetManager> CreateDSM(const training_engine_backend_type_e backend_type);
+ std::unique_ptr<FeatureVectorManager> CreateFVM(const training_engine_backend_type_e backend_type);
+ void UpdateDataSet(std::unique_ptr<DataSetManager>& data_set, std::vector<float>& feature_vec, const int label_idx, const int label_cnt);
+ void UpdateDataSet(std::unique_ptr<DataSetManager>& data_set);
+ int GetAnswer(std::vector<float>& result_tensor, unsigned int *out_idx);
+
+protected:
+ bool _initialized;
+ std::unique_ptr<InferenceEngineHelper> _internal;
+ std::unique_ptr<InferenceEngineHelper> _backbone;
+ std::unique_ptr<FaceNetInfo> _face_net_info;
+ std::unique_ptr<TrainingModel> _training_model;
+ LabelManager _label_manager;
+ std::string _internal_model_file;
+ training_engine_backend_type_e _backend_type;
+
+public:
+ FaceRecognition(const training_engine_backend_type_e backend_type = TRAINING_ENGINE_BACKEND_NNTRAINER,
+ const std::string internal_model_file = "model_and_weights.ini");
+ ~ FaceRecognition();
+
+ int Init(const std::string backend_name = "tflite", unsigned int device_type = INFERENCE_TARGET_CPU);
+ int RegisterNewFace(std::vector<float>& vec, std::string label_name);
+ int RecognizeFace(std::vector<float>& vec, unsigned int *out_idx);
+ int DeleteLabel(std::string label_name);
+ int GetLabelWithIndex(std::string& out_label, unsigned int label_idx);
+
+ std::unique_ptr<InferenceEngineHelper>& GetInternal() { return _internal; }
+ std::unique_ptr<InferenceEngineHelper>& GetBackbone() { return _backbone; }
+};
+
+#endif
\ No newline at end of file
--- /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.
+ */
+
+#ifndef __MEDIA_VISION_FACE_RECOGNITION_OPEN_H__
+#define __MEDIA_VISION_FACE_RECOGNITION_OPEN_H__
+
+#include <mv_common.h>
+#include <mv_private.h>
+#include <mv_face_recognition_type.h>
+#include <face_recognition.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif /* __cplusplus */
+
+ /**
+ * @brief Create face recognition object handle.
+ * @details Use this function to create an face recognition object handle.
+ * After creation the handle has to be prepared with
+ * @ref mv_face_recognition_prepare_open() function to prepare
+ * an face recognition object.
+ *
+ * @since_tizen 7.0
+ *
+ * @param [out] handle The handle to the face recognition object to be created
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory
+ *
+ * @post Release @a handle by using
+ * @ref mv_face_recognition_destroy_open() function when it is not needed
+ * anymore
+ *
+ * @see mv_face_recognition_destroy_open()
+ */
+ int mv_face_recognition_create_open(mv_face_recognition_h *out_handle);
+
+ /**
+ * @brief Destroy face recognition handle and releases all its resources.
+ *
+ * @since_tizen 7.0
+ *
+ * @param [in] handle The handle to the face recognition object to be destroyed.
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ *
+ * @pre Create an face recognition handle by using @ref mv_face_recognition_create_open()
+ *
+ * @see mv_face_recognition_create_open()
+ */
+ int mv_face_recognition_destroy_open(mv_face_recognition_h handle);
+
+ /**
+ * @brief Prepare face recognition.
+ *
+ * @since_tizen 7.0
+ *
+ * @param [in] handle The handle to the face recognition object to be prepared.
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ *
+ * @pre Create an face recognition handle by using @ref mv_face_recognition_create_open()
+ *
+ * @see mv_face_recognition_create_open()
+ */
+ int mv_face_recognition_prepare_open(mv_face_recognition_h handle);
+
+ /**
+ * @brief Register a new face on the @a source
+ * @details Use this function to register a new face.
+ * Each time when this function is called, a new face on the media source
+ * will be registered to internal database.
+ *
+ * @since_tizen 7.0
+ *
+ * @param [in] handle The handle to the face recognition object.
+ * @param [in] source The handle to the source of the media.
+ * @param [in] label The label to be registered.
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Source colorspace
+ * isn't supported
+ * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory
+ *
+ * @pre Create a source handle by calling @ref mv_create_source()
+ * @pre Create an face recognition handle by calling @ref mv_face_recognition_create_open()
+ * @pre Prepare an face recognition by calling @ref mv_face_recognition_prepare_open()
+ */
+ int mv_face_recognition_register_open(mv_face_recognition_h handle, mv_source_h source, const char *label);
+
+ /**
+ * @brief Unregister a new face on the @a source
+ * @details Use this function to unregister a given label.
+ * Each time when this function is called, all data related to the label
+ * will be removed from internal database.
+ *
+ * @since_tizen 7.0
+ *
+ * @param [in] handle The handle to the face recognition object.
+ * @param [in] label The label to be registered.
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Source colorspace
+ * isn't supported
+ * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory
+ *
+ * @pre Create an face recognition handle by calling @ref mv_face_recognition_create_open()
+ * @pre Prepare an face recognition by calling @ref mv_face_recognition_prepare_open()
+ */
+ int mv_face_recognition_unregister_open(mv_face_recognition_h handle, const char *label);
+
+ /**
+ * @brief Inference with a given face on the @a source
+ * @details Use this function to inference with a given source.
+ * This function returns an proper label string to a give source.
+ *
+ * @since_tizen 7.0
+ *
+ * @param [in] handle The handle to the face recognition object.
+ * @param [in] source The handle to the source of the media.
+ * @param [out] label The label to be inferenced.
+ *
+ * @return @c 0 on success, otherwise a negative error value
+ * @retval #MEDIA_VISION_ERROR_NONE Successful
+ * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT Source colorspace
+ * isn't supported
+ * @retval #MEDIA_VISION_ERROR_OUT_OF_MEMORY Out of memory
+ *
+ * @pre Create a source handle by calling @ref mv_create_source()
+ * @pre Create an face recognition handle by calling @ref mv_face_recognition_create_open()
+ * @pre Prepare an face recognition by calling @ref mv_face_recognition_prepare_open()
+ * @pre Register a new face by calling @ref mv_face_recognition_register_open()
+ */
+ int mv_face_recognition_inference_open(mv_face_recognition_h handle, mv_source_h source, char out_label[MAX_LABEL_SIZE]);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MEDIA_VISION_INFERENCE_OPEN_H__ */
--- /dev/null
+/**
+ * Copyright (c) 2021 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 NNTRAINER_DSM_H
+#define NNTRAINER_DSM_H
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+
+#include "feature_vector_manager.h"
+#include "data_set_manager.h"
+
+class NNTrainerDSM : public DataSetManager {
+private:
+ void PrintHeader(FeaVecHeader& fvh);
+
+public:
+ NNTrainerDSM();
+ ~NNTrainerDSM();
+
+ void LoadDataSet(const std::string file_name);
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 NNTRAINER_FVM_H
+#define NNTRAINER_FVM_H
+
+#include <string.h>
+#include <iostream>
+#include <fstream>
+#include <istream>
+#include <algorithm>
+#include <vector>
+#include <map>
+
+#include "feature_vector_manager.h"
+#include "file_util.h"
+
+class NNTrainerFVM : public FeatureVectorManager {
+public:
+ NNTrainerFVM(const std::string feature_vector_file = "feature_vector_file.dat");
+ ~NNTrainerFVM();
+
+ void WriteHeader(size_t feature_size, size_t one_hot_table_size, unsigned int data_set_cnt);
+ void ReadHeader(FeaVecHeader& header);
+ void WriteFeatureVec(std::vector<float>& feature_vec, const int max_label, const int label_index);
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 SIMPLE_SHOT_H
+#define SIMPLE_SHOT_H
+
+#include "training_model.h"
+
+class SimpleShot : public TrainingModel {
+private:
+ TrainingEngineBackendInfo _engine_info;
+
+public:
+ SimpleShot(const training_engine_backend_type_e backend_type = TRAINING_ENGINE_BACKEND_NNTRAINER,
+ const std::string internal_model_file = "model_and_weights.ini");
+ ~SimpleShot();
+
+ // Configure layers for SimpleShot learning.
+ void ConfigureModel(int num_of_class);
+
+ void UpdateDataSet(const std::string data_file_path);
+
+ void Compile();
+
+ void Training();
+
+ void SaveModel(const std::string file_path);
+
+ TrainingEngineBackendInfo& GetTrainingEngineInfo() { return _engine_info; }
+};
+
+#endif
\ No newline at end of file
--- /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 "face_net_info.h"
+
+using namespace std;
+
+FaceNetInfo::FaceNetInfo(std::string model_file_path) : BackboneModelInfo(model_file_path)
+{
+ _model_file_path = model_file_path;
+
+ const std::string input_layer_name = { "input" };
+ const inference_engine_tensor_info input_tensor_info = {
+ { 112, 112, 3, 1 },
+ INFERENCE_TENSOR_SHAPE_NCHW,
+ INFERENCE_TENSOR_DATA_TYPE_FLOAT32,
+ (size_t)(1 * 3 * 112 * 112)
+ };
+
+ model_layer_info input_info = { input_layer_name, input_tensor_info };
+ _input_layer_info.push_back(input_info);
+
+ const std::string output_layer_name = { "embeddings" };
+ const inference_engine_tensor_info output_tensor_info = {
+ { 192, 1, 1, 1 },
+ INFERENCE_TENSOR_SHAPE_NCHW,
+ INFERENCE_TENSOR_DATA_TYPE_FLOAT32,
+ (size_t)(1 * 192)
+ };
+
+ model_layer_info output_info = { output_layer_name, output_tensor_info };
+ _output_layer_info.push_back(output_info);
+}
+
+FaceNetInfo::~FaceNetInfo()
+{
+ _input_layer_info.clear();
+ _output_layer_info.clear();
+}
+
+std::string FaceNetInfo::GetModelFilePath()
+{
+ return _model_file_path;
+}
+
+std::vector<model_layer_info>& FaceNetInfo::GetInputLayerInfo()
+{
+ return _input_layer_info;
+}
+
+std::vector<model_layer_info>& FaceNetInfo::GetOutputLayerInfo()
+{
+ return _output_layer_info;
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 <string.h>
+#include <fstream>
+#include <istream>
+#include <tuple>
+#include <map>
+#include <algorithm>
+
+#include <sys/stat.h>
+
+#include <dlog.h>
+#include <mv_common.h>
+#include <mv_private.h>
+
+#include "face_recognition.h"
+#include "nntrainer_fvm.h"
+#include "nntrainer_dsm.h"
+#include "file_util.h"
+
+using namespace std;
+using namespace TrainingEngineInterface::Common;
+
+FaceRecognition::FaceRecognition(const training_engine_backend_type_e backend_type, const string internal_model_file) :
+ _initialized(), _internal(), _backbone(), _internal_model_file(internal_model_file)
+{
+ try {
+ _face_net_info = make_unique<FaceNetInfo>("/usr/share/capi-media-vision/models/FD/tflite/facenet.tflite");
+ _training_model = make_unique<SimpleShot>(backend_type, _internal_model_file);
+ _backend_type = backend_type;
+
+ // Update label manager from a given label file.
+ int cnt = _label_manager.ImportLabel();
+
+ LOGD("%d labels have been imported", cnt);
+ } catch (string& exception) {
+ LOGE("%s", exception.c_str());
+ return;
+ } catch (const exception& e) {
+ LOGE("%s", e.what());
+ return;
+ }
+}
+
+FaceRecognition::~FaceRecognition()
+{
+ _label_manager.Clear();
+}
+
+unique_ptr<DataSetManager> FaceRecognition::CreateDSM(const training_engine_backend_type_e backend_type)
+{
+ switch(backend_type) {
+ case TRAINING_ENGINE_BACKEND_NNTRAINER:
+ return make_unique<NNTrainerDSM>();
+ default:
+ throw string("Invalid training engine backend type.");
+ }
+
+ throw string("Invalid training engine backend type.");
+}
+
+unique_ptr<FeatureVectorManager> FaceRecognition::CreateFVM(const training_engine_backend_type_e backend_type)
+{
+ switch(backend_type) {
+ case TRAINING_ENGINE_BACKEND_NNTRAINER:
+ return make_unique<NNTrainerFVM>();
+ default:
+ throw string("Invalid training engine backend type.");
+ }
+
+ throw string("Invalid training engine backend type.");
+}
+
+void FaceRecognition::UpdateDataSet(unique_ptr<DataSetManager>& data_set, std::vector<float>& feature_vec, const int label_idx, const int label_cnt)
+{
+ try {
+ size_t data_set_cnt = 0;
+ auto fvm = CreateFVM(_backend_type);
+
+ data_set = CreateDSM(_backend_type);
+
+ // 1. If data set file exists then load the file to DataSetManager object first
+ // and them write them to the data set file with updated label value, and then
+ // write a new dataset to the data set file.
+ // Otherwise, it writes only new data set to the data set file.
+ if (FaceRecogUtil::IsFileExist(fvm->GetFileName())) {
+ data_set->LoadDataSet(fvm->GetFileName());
+
+ vector<vector<float>> feature_vectors = data_set->GetData();
+ vector<unsigned int> label_idx_vectors = data_set->GetLabelIdx();
+
+ // 1) Remove existing data file.
+ remove(fvm->GetFileName().c_str());
+
+ // 2) Write existing feature vectors and its one-hot encoding table considered
+ // for new label count to the data set file.
+ for (unsigned int idx = 0; idx < feature_vectors.size(); ++idx)
+ fvm->WriteFeatureVec(feature_vectors[idx], label_cnt, label_idx_vectors[idx]);
+
+ data_set_cnt += feature_vectors.size();
+
+ // 3) If same feature vector isn't duplcated then write the feature vector to data set file.
+ if (!data_set->IsFeatureVectorDuplicated(feature_vec)) {
+ fvm->WriteFeatureVec(feature_vec, label_cnt, label_idx);
+ LOGD("Added a new feature vector to data set file.");
+ data_set_cnt++;
+ }
+ } else {
+ // 1) Write only a new data set to the data st file.
+ fvm->WriteFeatureVec(feature_vec, label_cnt, label_idx);
+ LOGD("Added a new feature vector to data set file.");
+ data_set_cnt++;
+ }
+
+ // 2. Write feature vector header.
+ fvm->WriteHeader(feature_vec.size(), label_cnt, data_set_cnt);
+ data_set->Clear();
+
+ data_set->LoadDataSet(fvm->GetFileName());
+ } catch (const string& exception) {
+ throw exception;
+ } catch (const exception& e) {
+ throw e;
+ }
+}
+
+void FaceRecognition::UpdateDataSet(unique_ptr<DataSetManager>& data_set)
+{
+ data_set = CreateDSM(_backend_type);
+
+ try {
+ auto fvm = CreateFVM(_backend_type);
+
+ if (FaceRecogUtil::IsFileExist(fvm->GetFileName()) == false)
+ throw string("Feature vector file not found.");
+
+ data_set->LoadDataSet(fvm->GetFileName());
+ } catch (const string& exception) {
+ throw exception;
+ } catch (const exception& e) {
+ throw e;
+ }
+}
+
+int FaceRecognition::Init(const string backend_name, unsigned int device_type)
+{
+ if (_initialized) {
+ LOGW("Already initialized.");
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ try {
+ // Initialize inference engine object for backbone model.
+ _backbone = make_unique<InferenceEngineHelper>(backend_name, device_type);
+
+ vector<string> input_layer_names, output_layer_names;
+ vector<inference_engine_tensor_info> input_tensor_info, output_tensor_info;
+
+ for (auto& input : _face_net_info->GetInputLayerInfo()) {
+ input_layer_names.push_back(input.layer_name);
+ input_tensor_info.push_back(input.tensor_info);
+ }
+
+ for (auto& output : _face_net_info->GetOutputLayerInfo()) {
+ output_layer_names.push_back(output.layer_name);
+ output_tensor_info.push_back(output.tensor_info);
+ }
+
+ _backbone->UpdateLayerInfo(input_layer_names, output_layer_names,
+ input_tensor_info, output_tensor_info);
+
+ _backbone->Load(_face_net_info->GetModelFilePath());
+
+ TrainingEngineBackendInfo engine_info = _training_model->GetTrainingEngineInfo();
+
+ _internal = make_unique<InferenceEngineHelper>(engine_info.backend_name, engine_info.target_device);
+ } catch (const string& exception) {
+ LOGE("%s", exception.c_str());
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ } catch (const std::exception& e) {
+ LOGE("%s", e.what());
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ _initialized = true;
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int FaceRecognition::RegisterNewFace(vector<float>& vec, string label_name)
+{
+ if (!_initialized) {
+ LOGE("Initialization not ready yet.");
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ try {
+ // 1. Store only label names to label file, which aren't duplicated.
+ bool duplicated = _label_manager.AddLabelToMap(label_name, label_name);
+ if (!duplicated) {
+ int ret = _label_manager.AddLabelToFile(label_name);
+ if (ret == 0)
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ if (_face_net_info->GetInputLayerInfo().empty() || _face_net_info->GetInputLayerInfo().size() > 1) {
+ LOGE("Invalid input layer size - input layer size should be 1.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ if (_face_net_info->GetOutputLayerInfo().empty() || _face_net_info->GetOutputLayerInfo().size() > 1) {
+ LOGE("Invalid output layer size - output layer size should be 1.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ // Set input tensor for inference.
+ vector<model_layer_info>& input_layer_info = _face_net_info->GetInputLayerInfo();
+
+ // Ps. input layer size should be 1.
+ _backbone->UpdateInputData(input_layer_info[0].layer_name, vec, vec.size() * 4);
+
+ int ret = _backbone->Run();
+ if (ret != INFERENCE_ENGINE_ERROR_NONE) {
+ LOGE("fail to inference backbone model.");
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ vector<float> feature_vec;
+ // Set input tensor for inference.
+ vector<model_layer_info>& output_layer_info = _face_net_info->GetOutputLayerInfo();
+
+ // 2. Get feature vector from a given vec through inference engine.
+ // Ps. output layer size should be 1.
+ ret = _backbone->GetVectorFromOutput(output_layer_info[0].layer_name, feature_vec);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE) {
+ LOGE("fail to get output vector.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ // Get label index and count.
+ int label_idx = _label_manager.GetLabelIndex(label_name);
+ int label_cnt = _label_manager.GetMaxLabel();
+
+ _training_model->ConfigureModel(label_cnt);
+
+ unique_ptr<DataSetManager> data_set;
+
+ UpdateDataSet(data_set, feature_vec, label_idx, label_cnt);
+ _training_model->ApplyDataSet(data_set);
+ _training_model->Compile();
+ _training_model->Training();
+ } catch (string& exception) {
+ LOGE("%s", exception.c_str());
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ } catch (const std::exception& e) {
+ LOGE("%s", e.what());
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int FaceRecognition::GetAnswer(vector<float>& result_tensor, unsigned int *out_idx)
+{
+ int answer_idx;
+
+ string result_str;
+
+ for (auto& r : result_tensor)
+ result_str += to_string(r) + " ";
+
+ LOGD("raw data = %s", result_str.c_str());
+
+ answer_idx = max_element(result_tensor.begin(), result_tensor.end()) - result_tensor.begin();
+
+ // Check decision threshold.
+ if (result_tensor[answer_idx] < _label_manager.GetDecisionThreshold()) {
+ return MEDIA_VISION_ERROR_NO_DATA;
+ }
+
+#if 0
+ float weighted = result_tensor[answer_idx] * _label_manager.GetDecisionWeight();
+
+ // Check weighted value.
+ for (auto& r : result_tensor) {
+ if (result_tensor[answer_idx] == r)
+ continue;
+
+ if (weighted < r)
+ return MEDIA_VISION_ERROR_NO_DATA;
+ }
+#endif
+
+ *out_idx = answer_idx;
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int FaceRecognition::RecognizeFace(vector<float>& vec, unsigned int *out_idx)
+{
+ if (!_initialized) {
+ LOGE("Initialization not ready yet.");
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ TrainingEngineBackendInfo engine_info = _training_model->GetTrainingEngineInfo();
+ vector<string>& input_layers = engine_info.input_layer_names;
+ vector<inference_engine_tensor_info>& input_tensor_info = engine_info.input_tensor_info;
+ vector<string>& output_layers = engine_info.output_layer_names;
+ vector<inference_engine_tensor_info>& output_tensor_info = engine_info.output_tensor_info;
+ vector<float> result_tensor;
+
+ try {
+ if (_face_net_info->GetInputLayerInfo().empty() || _face_net_info->GetInputLayerInfo().size() > 1) {
+ LOGE("Invalid input layer size - input layer size should be 1.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ if (_face_net_info->GetOutputLayerInfo().empty() || _face_net_info->GetOutputLayerInfo().size() > 1) {
+ LOGE("Invalid output layer size - output layer size should be 1.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ // Set input tensor for inference.
+ vector<model_layer_info>& input_layer_info = _face_net_info->GetInputLayerInfo();
+
+ // Ps. input layer size should be 1.
+ _backbone->UpdateInputData(input_layer_info[0].layer_name, vec, vec.size() * 4);
+
+ int ret = _backbone->Run();
+ if (ret != INFERENCE_ENGINE_ERROR_NONE) {
+ LOGE("Fail to Run.");
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ vector<float> feature_vec;
+ // Set input tensor for inference.
+ vector<model_layer_info>& output_layer_info = _face_net_info->GetOutputLayerInfo();
+
+ // 2. Get feature vector from a given vec through inference engine.
+ // Ps. output layer size should be 1.
+ ret = _backbone->GetVectorFromOutput(output_layer_info[0].layer_name, feature_vec);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE) {
+ LOGE("Fail to GetVectorFromOutput.");
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ output_tensor_info[0].shape[0] = _label_manager.GetMaxLabel();
+ _internal->UpdateLayerInfo(input_layers, output_layers, input_tensor_info, output_tensor_info);
+
+ // model file could be created in runtime so just return -1 if the model file doesn't exist.
+ ret = _internal->Load(_internal_model_file);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE) {
+ LOGE("Fail to Load.");
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ _internal->UpdateInputData(input_layers[0], feature_vec, feature_vec.size() * 4);
+
+ ret = _internal->Run();
+ if (ret != INFERENCE_ENGINE_ERROR_NONE) {
+ LOGE("Fail to Run.");
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ ret = _internal->GetVectorFromOutput(output_layers[0], result_tensor);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE) {
+ LOGE("Fail to GetVectorFromOutput.");
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ return GetAnswer(result_tensor, out_idx);
+ } catch (const string& exception) {
+ LOGE("%s", exception.c_str());
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ } catch (const exception& e) {
+ LOGE("%s", e.what());
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+}
+
+int FaceRecognition::DeleteLabel(std::string label_name)
+{
+ // Deleting a given label is to remove existing registered person from label and feature vector files.
+
+ try {
+ if (_label_manager.IsExist(label_name) == false) {
+ LOGE("%s doesn't exsit in label file.", label_name.c_str());
+ return MEDIA_VISION_ERROR_NO_DATA;
+ }
+
+ unsigned int target_label_idx = _label_manager.GetLabelIndex(label_name);
+
+ // Get label count after removing a given label from the label file.
+ _label_manager.RemoveLabel(label_name);
+
+ int label_cnt = _label_manager.GetMaxLabel();
+ auto fvm = CreateFVM(_backend_type);
+ auto data_set = CreateDSM(_backend_type);
+
+ data_set->LoadDataSet(fvm->GetFileName());
+
+ // Remove existing data file.
+ remove(fvm->GetFileName().c_str());
+
+ vector<vector<float>> feature_vectors = data_set->GetData();
+ vector<unsigned int> label_idx_vectors = data_set->GetLabelIdx();
+
+ size_t data_set_cnt = 0;
+
+ // Write existing feature vectors and its one-hot encoding table with updated label.
+ for (unsigned int idx = 0; idx < feature_vectors.size(); ++idx) {
+ // Except the data sets with a given target_label_idx.
+ if (label_idx_vectors[idx] == target_label_idx)
+ continue;
+
+ // One-hot encoding table should be updated.
+ // Assume that below label file exists for example,
+ // In label file
+ // -------------
+ // offset 0 : label 1
+ // offset 1 : label 2
+ // offset 2 : label 3
+ //
+ // One hot encoding table should be updated like below after removing label 1,
+ // In label file
+ // -------------
+ // offset 0 : label 2
+ // offset 1 : label 3
+ //
+ // So if the index of removed label less than remaining index then decrease each index.
+ if (label_idx_vectors[idx] > target_label_idx)
+ label_idx_vectors[idx]--;
+
+ fvm->WriteFeatureVec(feature_vectors[idx], label_cnt, label_idx_vectors[idx]);
+ data_set_cnt++;
+ }
+
+ fvm->WriteHeader(feature_vectors[0].size(), label_cnt, data_set_cnt);
+
+ _training_model->ConfigureModel(label_cnt);
+
+ std::unique_ptr<DataSetManager> new_data_set;
+
+ UpdateDataSet(new_data_set);
+ _training_model->ApplyDataSet(new_data_set);
+ _training_model->Compile();
+ _training_model->Training();
+ } catch (const string& exception) {
+ LOGE("%s", exception.c_str());
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ } catch (const exception& e) {
+ LOGE("%s", e.what());
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int FaceRecognition::GetLabelWithIndex(string& out_label, unsigned int label_idx)
+{
+ try {
+ _label_manager.GetLabelString(out_label, label_idx);
+ } catch (const string& exception) {
+ LOGE("%s", exception.c_str());
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ } catch (const exception& e) {
+ LOGE("%s", e.what());
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
+ return MEDIA_VISION_ERROR_NONE;
+}
\ No newline at end of file
--- /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 "mv_private.h"
+#include "mv_face_recognition.h"
+#include "mv_face_recognition_open.h"
+
+int mv_face_recognition_create(mv_face_recognition_h *out_handle)
+{
+ MEDIA_VISION_SUPPORT_CHECK(
+ __mv_inference_face_check_system_info_feature_supported());
+
+ MEDIA_VISION_NULL_ARG_CHECK(out_handle);
+
+ MEDIA_VISION_FUNCTION_ENTER();
+
+ int ret = MEDIA_VISION_ERROR_NONE;
+
+ ret = mv_face_recognition_create_open(out_handle);
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+
+ return ret;
+}
+
+int mv_face_recognition_destroy(mv_face_recognition_h handle)
+{
+ MEDIA_VISION_SUPPORT_CHECK(
+ __mv_inference_face_check_system_info_feature_supported());
+
+ MEDIA_VISION_INSTANCE_CHECK(handle);
+
+ MEDIA_VISION_FUNCTION_ENTER();
+
+ int ret = MEDIA_VISION_ERROR_NONE;
+
+ ret = mv_face_recognition_destroy_open(handle);
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+
+ return ret;
+}
+
+int mv_face_recognition_prepare(mv_face_recognition_h handle)
+{
+ MEDIA_VISION_SUPPORT_CHECK(
+ __mv_inference_face_check_system_info_feature_supported());
+
+ MEDIA_VISION_INSTANCE_CHECK(handle);
+
+ MEDIA_VISION_FUNCTION_ENTER();
+
+ int ret = MEDIA_VISION_ERROR_NONE;
+
+ ret = mv_face_recognition_prepare_open(handle);
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+
+ return ret;
+}
+
+int mv_face_recognition_register(mv_face_recognition_h handle, mv_source_h source, const char *label)
+{
+ MEDIA_VISION_SUPPORT_CHECK(
+ __mv_inference_face_check_system_info_feature_supported());
+
+ MEDIA_VISION_INSTANCE_CHECK(handle);
+ MEDIA_VISION_INSTANCE_CHECK(source);
+ MEDIA_VISION_INSTANCE_CHECK(label);
+
+ MEDIA_VISION_FUNCTION_ENTER();
+
+ int ret = MEDIA_VISION_ERROR_NONE;
+
+ ret = mv_face_recognition_register_open(handle, source, label);
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+
+ return ret;
+}
+
+int mv_face_recognition_unregister(mv_face_recognition_h handle, const char *label)
+{
+ MEDIA_VISION_SUPPORT_CHECK(
+ __mv_inference_face_check_system_info_feature_supported());
+
+ MEDIA_VISION_INSTANCE_CHECK(handle);
+ MEDIA_VISION_INSTANCE_CHECK(label);
+
+ MEDIA_VISION_FUNCTION_ENTER();
+
+ int ret = MEDIA_VISION_ERROR_NONE;
+
+ ret = mv_face_recognition_unregister_open(handle, label);
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+
+ return ret;
+}
+
+int mv_face_recognition_inference(mv_face_recognition_h handle, mv_source_h source, char *out_label)
+{
+ MEDIA_VISION_SUPPORT_CHECK(
+ __mv_inference_face_check_system_info_feature_supported());
+
+ MEDIA_VISION_INSTANCE_CHECK(handle);
+ MEDIA_VISION_INSTANCE_CHECK(source);
+ MEDIA_VISION_INSTANCE_CHECK(out_label);
+
+ MEDIA_VISION_FUNCTION_ENTER();
+
+ int ret = MEDIA_VISION_ERROR_NONE;
+
+ ret = mv_face_recognition_inference_open(handle, source, out_label);
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+
+ return ret;
+}
\ No newline at end of file
--- /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 <dlog.h>
+
+#include "face_recognition.h"
+#include "feature_vector_manager.h"
+#include "mv_face_recognition_open.h"
+
+using namespace std;
+
+int mv_face_recognition_create_open(mv_face_recognition_h *handle)
+{
+ if (handle == NULL) {
+ LOGE("Handle can't be created because handle pointer is NULL");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ (*handle) = static_cast<mv_face_recognition_h>(new (std::nothrow)FaceRecognition());
+
+ if (*handle == NULL) {
+ LOGE("Failed to create face recognition handle");
+ return MEDIA_VISION_ERROR_OUT_OF_MEMORY;
+ }
+
+ LOGD("face recognition handle [%p] has been created", *handle);
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_face_recognition_destroy_open(mv_face_recognition_h handle)
+{
+ if (!handle) {
+ LOGE("Handle is NULL.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ LOGD("Destroying face recognition handle [%p]", handle);
+ delete static_cast<FaceRecognition *>(handle);
+ LOGD("Face recognition handle has been destroyed");
+
+ return MEDIA_VISION_ERROR_NONE;
+}
+
+int mv_face_recognition_prepare_open(mv_face_recognition_h handle)
+{
+ LOGD("ENTER");
+
+ if (!handle) {
+ LOGE("Handle is NULL.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ FaceRecognition *pFace = static_cast<FaceRecognition *>(handle);
+
+ int ret = pFace->Init();
+ if (ret != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Fail to initialize face recognition.");
+ return ret;
+ }
+
+ LOGD("LEAVE");
+
+ return ret;
+}
+
+int mv_face_recognition_register_open(mv_face_recognition_h handle, mv_source_h source, const char *label)
+{
+ LOGD("ENTER");
+
+ if (!handle) {
+ LOGE("Handle is NULL.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ FaceRecognition *pFace = static_cast<FaceRecognition *>(handle);
+ mv_colorspace_e colorspace = MEDIA_VISION_COLORSPACE_INVALID;
+ unsigned int width = 0, height = 0, bufferSize = 0;
+ unsigned char *buffer = NULL;
+
+ if (mv_source_get_width(source, &width) != MEDIA_VISION_ERROR_NONE ||
+ mv_source_get_height(source, &height) != MEDIA_VISION_ERROR_NONE ||
+ mv_source_get_colorspace(source, &colorspace) != MEDIA_VISION_ERROR_NONE ||
+ mv_source_get_buffer(source, &buffer, &bufferSize))
+ return MEDIA_VISION_ERROR_INTERNAL;
+
+ // TODO. Let's support various color spaces.
+
+ if (colorspace != MEDIA_VISION_COLORSPACE_RGB888) {
+ LOGE("Not Supported format!\n");
+ return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT;
+ }
+
+ vector<float> src_vec;
+
+ FeatureVectorManager::GetVecFromRGB(buffer, src_vec, width, height, 112, 112);
+
+ int ret = pFace->RegisterNewFace(src_vec, string(label));
+ if (ret != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Fail to register new face.");
+ return ret;
+ }
+
+ LOGD("LEAVE");
+
+ return ret;
+}
+
+int mv_face_recognition_unregister_open(mv_face_recognition_h handle, const char *label)
+{
+ LOGD("ENTER");
+
+ if (!handle) {
+ LOGE("Handle is NULL.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ FaceRecognition *pFace = static_cast<FaceRecognition *>(handle);
+
+ int ret = pFace->DeleteLabel(string(label));
+ if (ret != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Fail to register new face.");
+ return ret;
+ }
+
+ LOGD("LEAVE");
+ return 0;
+}
+
+int mv_face_recognition_inference_open(mv_face_recognition_h handle, mv_source_h source, char *out_label)
+{
+ LOGD("ENTER");
+
+ if (!handle) {
+ LOGE("Handle is NULL.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
+ }
+
+ FaceRecognition *pFace = static_cast<FaceRecognition *>(handle);
+ mv_colorspace_e colorspace = MEDIA_VISION_COLORSPACE_INVALID;
+ unsigned int width = 0, height = 0, bufferSize = 0;
+ unsigned char *buffer = NULL;
+
+ if (mv_source_get_width(source, &width) != MEDIA_VISION_ERROR_NONE ||
+ mv_source_get_height(source, &height) != MEDIA_VISION_ERROR_NONE ||
+ mv_source_get_colorspace(source, &colorspace) != MEDIA_VISION_ERROR_NONE ||
+ mv_source_get_buffer(source, &buffer, &bufferSize))
+ return MEDIA_VISION_ERROR_INTERNAL;
+
+ // TODO. Let's support various color spaces.
+
+ if (colorspace != MEDIA_VISION_COLORSPACE_RGB888) {
+ LOGE("Not Supported format!\n");
+ return MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT;
+ }
+
+ vector<float> src_vec;
+ unsigned int out_idx;
+
+ FeatureVectorManager::GetVecFromRGB(buffer, src_vec, width, height, 112, 112);
+
+ int ret = pFace->RecognizeFace(src_vec, &out_idx);
+ if (ret == MEDIA_VISION_ERROR_NO_DATA) {
+ LOGW("Label not found.");
+ out_label = NULL;
+ return ret;
+ }
+
+ if (ret != MEDIA_VISION_ERROR_NONE) {
+ LOGE("Fail to recognize face.");
+ return ret;
+ }
+
+ string result_label;
+
+ ret = pFace->GetLabelWithIndex(result_label, out_idx);
+ if (ret != MEDIA_VISION_ERROR_NONE) {
+ LOGI("Fail to find label.");
+ return ret;
+ }
+
+ int length = result_label.copy(out_label, result_label.length(), 0);
+ out_label[length] = '\0';
+
+ LOGD("LEAVE");
+
+ return MEDIA_VISION_ERROR_NONE;
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 <dlog.h>
+#include <mv_private.h>
+
+#include "nntrainer_dsm.h"
+
+using namespace std;
+
+void NNTrainerDSM::PrintHeader(FeaVecHeader& fvh)
+{
+ LOGD("signature = %u", fvh.signature);
+ LOGD("feature vector size = %zu", fvh.feature_size);
+ LOGD("one hot encoding table size = %zu", fvh.one_hot_table_size);
+ LOGD("data set count = %u", fvh.data_set_cnt);
+}
+
+NNTrainerDSM::NNTrainerDSM() : DataSetManager()
+{
+
+}
+
+NNTrainerDSM::~NNTrainerDSM()
+{
+
+}
+
+void NNTrainerDSM::LoadDataSet(const std::string file_name)
+{
+ std::ifstream openFile(file_name);
+
+ if (!openFile.is_open())
+ throw std::string("fail to open a file.");
+
+ // Feature vector file header is written at the end of the data file
+ // So read feature vector header from the end of the file.
+ openFile.seekg(static_cast<int>(sizeof(FeaVecHeader) * -1), std::ios::end);
+
+ FeaVecHeader fvh;
+
+ openFile.read((char *)&fvh, sizeof(FeaVecHeader));
+ openFile.seekg(0, std::ios::beg);
+
+ PrintHeader(fvh);
+
+ size_t line_size_in_bytes = fvh.feature_size * 4 + fvh.one_hot_table_size * 4;
+
+ _feature_vector_size = fvh.feature_size;
+ _label_size = fvh.one_hot_table_size;
+ _data_set_length = line_size_in_bytes;
+
+ float *line_data = new(std::nothrow) float[line_size_in_bytes];
+ if (!line_data)
+ throw std::string("fail to allocate line_data.");
+
+ for (size_t data_set_idx = 0; data_set_idx < fvh.data_set_cnt; ++data_set_idx) {
+ openFile.read((char *)line_data, line_size_in_bytes);
+
+ std::vector<float> data, label;
+
+ for (size_t num = 0; num < fvh.feature_size; ++num)
+ data.push_back((float)line_data[num]);
+
+ int label_idx = 0;
+
+ for (size_t num = 0; num < fvh.one_hot_table_size; ++num) {
+ if (line_data[fvh.feature_size + num] == 1.0f)
+ label_idx = num;
+
+ label.push_back((float)line_data[fvh.feature_size + num]);
+ }
+
+ _data.push_back(data);
+ _labels.push_back(label);
+ _label_index.push_back(label_idx);
+ }
+
+ delete line_data;
+ openFile.close();
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 "nntrainer_fvm.h"
+
+using namespace std;
+
+NNTrainerFVM::NNTrainerFVM(const std::string feature_vector_file) : FeatureVectorManager(feature_vector_file)
+{
+
+}
+
+NNTrainerFVM::~NNTrainerFVM()
+{
+
+}
+
+void NNTrainerFVM::WriteHeader(size_t feature_size, size_t one_hot_table_size, unsigned int data_set_cnt)
+{
+ std::ofstream writeFile;
+
+ writeFile.open(_feature_vector_file.c_str(), std::ios::out | std::ios::binary | std::ios::app);
+ if (!writeFile.is_open())
+ throw std::string("fail to open a file");
+
+ FeaVecHeader header = { feature_vector_signagure, feature_size, one_hot_table_size, data_set_cnt };
+
+ writeFile.write((char *)&header, sizeof(FeaVecHeader));
+
+ writeFile.close();
+}
+
+void NNTrainerFVM::ReadHeader(FeaVecHeader& header)
+{
+ std::ifstream openFile(_feature_vector_file.c_str(), std::ios::in | std::ios::binary);
+
+ if (!openFile.is_open())
+ throw std::string("fail to open a file.");
+
+ openFile.seekg(static_cast<int>(sizeof(FeaVecHeader) * -1), std::ios::end);
+
+ openFile.read((char *)&header, sizeof(FeaVecHeader));
+ if (!openFile)
+ throw std::string("fail to read feature vector file.");
+
+ openFile.close();
+
+ if (header.signature != feature_vector_signagure)
+ throw std::string("wrong feature vector file header.");
+}
+
+void NNTrainerFVM::WriteFeatureVec(std::vector<float>& feature_vec, const int max_label, const int label_index)
+{
+ std::ofstream writeFile;
+
+ writeFile.open(_feature_vector_file.c_str(), std::ios::out | std::ios::binary | std::ios::app);
+
+ if (!writeFile.is_open())
+ throw std::string("fail to open a file.");
+
+ size_t img_size = feature_vec.size() * 4;
+ std::unique_ptr<char[]> pBuffer = std::make_unique<char[]>(img_size);
+ if (!pBuffer)
+ throw std::string("fail to allocate buffer.");
+
+ memcpy(pBuffer.get(), feature_vec.data(), img_size);
+ writeFile.write(pBuffer.get(), img_size);
+
+ for (int idx = 0; idx < max_label; ++idx) {
+ float one_hot_table = 0.0f;
+
+ if (label_index == idx)
+ one_hot_table = 1.0f;
+
+ writeFile.write((char *)&one_hot_table, sizeof(float));
+ }
+
+ writeFile.close();
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 <string.h>
+#include <fstream>
+#include <istream>
+#include <tuple>
+#include <map>
+#include <algorithm>
+
+#include <sys/stat.h>
+
+#include "simple_shot.h"
+#include "data_set_manager.h"
+#include "feature_vector_manager.h"
+
+using namespace std;
+using namespace TrainingEngineInterface::Common;
+
+SimpleShot::SimpleShot(const training_engine_backend_type_e backend_type, const std::string internal_model_file) :
+ TrainingModel(backend_type, internal_model_file)
+{
+ map<int, string>::iterator item = _backend_lookup.find(backend_type);
+ if (item == _backend_lookup.end())
+ throw string("Invalid training engine backend type.");
+
+ _engine_info.backend_name = item->second;
+ _engine_info.target_device = INFERENCE_TARGET_CPU;
+
+ const inference_engine_tensor_info nntrainer_input_tensor_info = {
+ { 192, 1, 1, 1 },
+ INFERENCE_TENSOR_SHAPE_NCHW,
+ INFERENCE_TENSOR_DATA_TYPE_FLOAT32,
+ (size_t)(192 * 1 * 1 * 1)
+ };
+
+ _engine_info.input_layer_names.push_back("preprocess_l2norm0");
+ _engine_info.input_tensor_info.push_back(nntrainer_input_tensor_info);
+
+ // size of output tensor will be updated by RecognizeFace function
+ // because the size should be changed according to maximum label count
+ // so it has 1 in default.
+ inference_engine_tensor_info nntrainer_output_tensor_info = {
+ std::vector<size_t>{ 1, 1, 1, 1 },
+ INFERENCE_TENSOR_SHAPE_NCHW,
+ INFERENCE_TENSOR_DATA_TYPE_FLOAT32,
+ 1
+ };
+
+ _engine_info.output_layer_names.push_back("centroid_knn1");
+ _engine_info.output_tensor_info.push_back(nntrainer_output_tensor_info);
+
+ _engine_info.optimizer_property = {. options = { "learning_rate=0.1" } };
+ _engine_info.compile_property = { .options = { "batch_size=1" } };
+}
+
+SimpleShot::~SimpleShot()
+{
+ // If a model exists then destroy the model.
+ if (_model)
+ _training->DestroyModel(_model.get());
+}
+
+void SimpleShot::ConfigureModel(int num_of_class)
+{
+ training_engine_config config = { _engine_info.backend_name };
+ int ret = _training->BindBackend(config);
+ if (ret != TRAINING_ENGINE_ERROR_NONE)
+ throw std::string("Fail to bind backend engine.");
+
+ training_engine_capacity capacity = { TRAINING_TENSOR_SHAPE_MIN };
+ ret = _training->GetBackendCapacity(capacity);
+ if (ret != TRAINING_ENGINE_ERROR_NONE)
+ throw std::string("Fail to get backend capacity.");
+
+ _model = _training->CreateModel();
+ if (!_model)
+ throw std::string("Fail to create a model.");
+
+ auto l2norm = _training->CreateLayer(TRAINING_LAYER_TYPE_L2NORM);
+ if (!l2norm)
+ throw std::string("Fail to create l2norm layer.");
+
+ auto knn = _training->CreateLayer(TRAINING_LAYER_TYPE_CENTROID_KNN);
+ if (!knn)
+ throw std::string("Fail to create knn layer.");
+
+ // Ps. In case of the first layer, input_shape property is mandatorily required.
+ // 1:192 is a shape of backbone model output tensor.
+ training_engine_layer_property l2norm_property = { .options = { "input_shape=1:192", "trainable=false" } };
+ ret = _training->SetLayerProperty(l2norm.get(), l2norm_property);
+ if (ret != TRAINING_ENGINE_ERROR_NONE)
+ throw std::string("Fail to set layer propery.");
+
+ const std::string num_class_prop = "num_class=" + std::to_string(num_of_class);
+ training_engine_layer_property knn_property = { .options = { num_class_prop, "trainable=false" } };
+
+ ret = _training->SetLayerProperty(knn.get(), knn_property);
+ if (ret != TRAINING_ENGINE_ERROR_NONE)
+ throw std::string("Fail to set layer property.");
+
+ ret = _training->AddLayer(_model.get(), l2norm.get());
+ if (ret != TRAINING_ENGINE_ERROR_NONE)
+ throw std::string("Fail to add l2norm layer.");
+
+ ret = _training->AddLayer(_model.get(), knn.get());
+ if (ret != TRAINING_ENGINE_ERROR_NONE)
+ throw std::string("Fail to add knn layer.");
+}
+
+void SimpleShot::SaveModel(const std::string file_path)
+{
+ int ret = TRAINING_ENGINE_ERROR_NONE;
+
+ std::string bin_file_path = file_path.substr(0, file_path.find('.'));
+ bin_file_path += std::string(".bin");
+
+ // NNStreamer returns an error if internal model file(ini and bin files) exists before generating it.
+ // So remove existing files.
+ std::remove(bin_file_path.c_str());
+ std::remove(file_path.c_str());
+
+ ret = _training->SaveModel(_model.get(), file_path);
+ if (ret != TRAINING_ENGINE_ERROR_NONE)
+ throw std::string("Fail to save a model.");
+}
--- /dev/null
+/**
+ * Copyright (c) 2021 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 INFERENCE_ENGINE_HELPER_H
+#define INFERENCE_ENGINE_HELPER_H
+
+#include <iostream>
+#include <memory>
+
+#include "inference_engine_error.h"
+#include "inference_engine_common_impl.h"
+
+class InferenceEngineHelper {
+private:
+ std::unique_ptr<InferenceEngineInterface::Common::InferenceEngineCommon> _engine;
+ IETensorBuffer _inputs, _outputs;
+ inference_engine_layer_property _input_property, _output_property;
+
+ int GetModelInfo(std::vector<std::string> &model_paths,
+ std::vector<std::string> &models);
+ int PrepareTensorBuffers(InferenceEngineInterface::Common::InferenceEngineCommon *engine,
+ IETensorBuffer &inputs,
+ IETensorBuffer &outputs);
+
+ void CleanupTensorBuffers(IETensorBuffer &inputs, IETensorBuffer &outputs);
+
+public:
+ InferenceEngineHelper(std::string backend_name, int target_device);
+ ~InferenceEngineHelper();
+ int Load(std::string backbone_path);
+ int UpdateLayerInfo(const std::vector<std::string>& input_layers,
+ const std::vector<std::string>& output_layers,
+ const std::vector<inference_engine_tensor_info>& input_tensor_info,
+ const std::vector<inference_engine_tensor_info>& output_tensor_info);
+ void UpdateInputData(std::string layer_name, std::vector<float>& data, size_t size);
+ int Run(void);
+ void Finish();
+ int GetVectorFromOutput(std::string layer_name, std::vector<float>& feature_vec);
+ int GetOutputBuffer(std::string layer_name, inference_engine_tensor_buffer& output);
+};
+
+#endif
--- /dev/null
+/**
+ * Copyright (c) 2021 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 "inference_engine_helper.h"
+
+using namespace std;
+using namespace InferenceEngineInterface::Common;
+
+static std::map<std::string, int> Model_Formats = {
+ { "caffemodel", INFERENCE_MODEL_CAFFE }, { "pb", INFERENCE_MODEL_TF },
+ { "tflite", INFERENCE_MODEL_TFLITE }, { "t7", INFERENCE_MODEL_TORCH },
+ { "weights", INFERENCE_MODEL_DARKNET }, { "xml", INFERENCE_MODEL_DLDT },
+ { "onnx", INFERENCE_MODEL_ONNX }, {"ini", INFERENCE_MODEL_NNTRAINER }
+};
+
+InferenceEngineHelper::InferenceEngineHelper(std::string backend_name, int target_device)
+{
+ _engine = std::make_unique<InferenceEngineCommon>();
+
+ inference_engine_config config = { backend_name, -1, target_device };
+
+ int ret = _engine->BindBackend(&config);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE)
+ throw std::string("fail to bind backend engine");
+
+ inference_engine_capacity capacity;
+
+ ret = _engine->GetBackendCapacity(&capacity);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE)
+ throw std::string("fail to get backend engine capacity.");
+
+ ret = _engine->SetTargetDevices(config.target_devices);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE)
+ throw std::string("fail to set target device.");
+}
+
+InferenceEngineHelper::~InferenceEngineHelper()
+{
+ _engine->UnbindBackend();
+}
+
+int InferenceEngineHelper::GetModelInfo(std::vector<std::string> &model_paths,
+ std::vector<std::string> &models)
+{
+ std::string model_path = model_paths[0];
+ std::string ext_str = model_path.substr(model_path.find_last_of(".") + 1);
+ std::map<std::string, int>::iterator key = Model_Formats.find(ext_str);
+ int ret = key != Model_Formats.end() ? key->second : -1;
+
+ if (ret == -1) {
+ return ret;
+ }
+
+ switch (ret) {
+ case INFERENCE_MODEL_CAFFE:
+ case INFERENCE_MODEL_TF:
+ case INFERENCE_MODEL_DARKNET:
+ case INFERENCE_MODEL_DLDT:
+ case INFERENCE_MODEL_ONNX:
+ models.push_back(model_paths[0]);
+ models.push_back(model_paths[1]);
+ break;
+ case INFERENCE_MODEL_TFLITE:
+ case INFERENCE_MODEL_TORCH:
+ case INFERENCE_MODEL_NNTRAINER:
+ models.push_back(model_paths[0]);
+ break;
+ default:
+ break;
+ }
+
+ return ret;
+}
+
+int InferenceEngineHelper::PrepareTensorBuffers(InferenceEngineCommon *engine,
+ IETensorBuffer &inputs,
+ IETensorBuffer &outputs)
+{
+ int ret = engine->GetInputTensorBuffers(inputs);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE)
+ return ret;
+
+ if (inputs.empty()) {
+ inference_engine_layer_property input_property;
+ ret = engine->GetInputLayerProperty(input_property);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE)
+ return ret;
+
+ // If backend is OpenCV then the buffers will be allocated out of this function.
+ if (input_property.layers.empty()) {
+ return INFERENCE_ENGINE_ERROR_NONE;
+ }
+
+ for (auto& layer : input_property.layers) {
+ inference_engine_tensor_buffer tensor_buffer;
+ inference_engine_tensor_info tensor_info = layer.second;
+
+ if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) {
+ tensor_buffer.buffer = (void *) (new float[tensor_info.size]);
+ tensor_buffer.size = tensor_info.size * 4;
+ } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) {
+ tensor_buffer.buffer = (void *) (new unsigned char[tensor_info.size]);
+ tensor_buffer.size = tensor_info.size;
+ }
+
+ tensor_buffer.owner_is_backend = 0;
+ tensor_buffer.data_type = tensor_info.data_type;
+ inputs.insert(std::make_pair(layer.first, tensor_buffer));
+ }
+ }
+
+ ret = engine->GetOutputTensorBuffers(outputs);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE)
+ return ret;
+
+ if (outputs.empty()) {
+ inference_engine_layer_property output_property;
+ ret = engine->GetOutputLayerProperty(output_property);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE)
+ return ret;
+
+ // If backend is OpenCV then the buffers will be allocated out of this function.
+ if (output_property.layers.empty()) {
+ return INFERENCE_ENGINE_ERROR_NONE;
+ }
+
+ for (auto& layer : output_property.layers) {
+ inference_engine_tensor_info tensor_info = layer.second;
+ inference_engine_tensor_buffer tensor_buffer;
+
+ if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32) {
+ tensor_buffer.buffer = (void *) (new float[tensor_info.size]);
+ tensor_buffer.size = tensor_info.size * 4;
+ } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT8) {
+ tensor_buffer.buffer = (void *) (new unsigned char[tensor_info.size]);
+ tensor_buffer.size = tensor_info.size;
+ } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_INT64) {
+ tensor_buffer.buffer = (void *)(new long long[tensor_info.size]);
+ tensor_buffer.size = tensor_info.size * 8;
+ } else if (tensor_info.data_type == INFERENCE_TENSOR_DATA_TYPE_UINT16) {
+ tensor_buffer.buffer = (void *)(new unsigned short[tensor_info.size]);
+ tensor_buffer.size = tensor_info.size * 2;
+ }
+
+ tensor_buffer.owner_is_backend = 0;
+ tensor_buffer.data_type = tensor_info.data_type;
+ outputs.insert(std::make_pair(layer.first, tensor_buffer));
+ }
+ }
+
+ return INFERENCE_ENGINE_ERROR_NONE;
+}
+
+void InferenceEngineHelper::CleanupTensorBuffers(IETensorBuffer &inputs,
+ IETensorBuffer &outputs)
+{
+ if (!inputs.empty()) {
+ for (auto& layer : inputs) {
+ inference_engine_tensor_buffer tensor_buffer = layer.second;
+
+ // If tensor buffer owner is a backend then skip to release the tensor buffer.
+ // This tensor buffer will be released by the backend.
+ if (tensor_buffer.owner_is_backend) {
+ continue;
+ }
+
+ if (tensor_buffer.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32)
+ delete[](float *) tensor_buffer.buffer;
+ else
+ delete[](unsigned char *) tensor_buffer.buffer;
+ }
+ }
+
+ if (!outputs.empty()) {
+ for (auto& layer : outputs) {
+ inference_engine_tensor_buffer tensor_buffer = layer.second;
+
+ // If tensor buffer owner is a backend then skip to release the tensor buffer.
+ // This tensor buffer will be released by the backend.
+ if (tensor_buffer.owner_is_backend) {
+ continue;
+ }
+
+ if (tensor_buffer.data_type == INFERENCE_TENSOR_DATA_TYPE_FLOAT32)
+ delete[](float *) tensor_buffer.buffer;
+ else
+ delete[](unsigned char *) tensor_buffer.buffer;
+ }
+ }
+}
+
+int InferenceEngineHelper::Load(std::string backbone_path)
+{
+ int ret = 0;
+
+ std::vector<std::string> models, model_paths;
+ model_paths.push_back(backbone_path);
+
+ int model_type = GetModelInfo(model_paths, models);
+
+ ret = _engine->Load(models, (inference_model_format_e) model_type);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE) {
+ if (model_type != INFERENCE_MODEL_NNTRAINER)
+ throw std::string("fail to load model file.");
+ }
+
+ ret = PrepareTensorBuffers(_engine.get(), _inputs, _outputs);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE) {
+ if (model_type != INFERENCE_MODEL_NNTRAINER)
+ throw std::string("fail to prepare tensor buffers.");
+ }
+
+ return ret;
+}
+
+int InferenceEngineHelper::UpdateLayerInfo(const std::vector<std::string>& input_layers,
+ const std::vector<std::string>& output_layers,
+ const std::vector<inference_engine_tensor_info>& input_tensor_info,
+ const std::vector<inference_engine_tensor_info>& output_tensor_info)
+{
+ int ret = 0;
+
+ _input_property.layers.clear();
+
+ if (input_layers.size() != input_tensor_info.size() ||
+ output_layers.size() != output_tensor_info.size())
+ throw std::string("layer name and tensor info size are different.");
+
+ for (size_t idx = 0; idx < input_layers.size(); ++idx)
+ _input_property.layers.insert(std::make_pair(input_layers[idx], input_tensor_info[idx]));
+
+ ret = _engine->SetInputLayerProperty(_input_property);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE)
+ throw std::string("fail to set input layer property.");
+
+ _output_property.layers.clear();
+
+ for (size_t idx = 0; idx < output_layers.size(); ++idx)
+ _output_property.layers.insert(std::make_pair(output_layers[idx], output_tensor_info[idx]));
+
+ ret = _engine->SetOutputLayerProperty(_output_property);
+ if (ret != INFERENCE_ENGINE_ERROR_NONE)
+ throw std::string("fail to set output layer property.");
+
+ return ret;
+}
+
+void InferenceEngineHelper::UpdateInputData(std::string layer_name, std::vector<float>& data, size_t size)
+{
+ if (data.size() * 4 != size)
+ throw std::string("number of bytes of data should be same as size");
+
+ auto it = _inputs.find(layer_name);
+
+ if (it == _inputs.end())
+ throw std::string("Invalid layer name.");
+
+ memcpy(it->second.buffer, data.data(), size);
+}
+
+int InferenceEngineHelper::Run(void)
+{
+ return _engine->Run(_inputs, _outputs);
+}
+
+void InferenceEngineHelper::Finish()
+{
+ _engine->UnbindBackend();
+}
+
+int InferenceEngineHelper::GetVectorFromOutput(std::string layer_name, std::vector<float>& feature_vec)
+{
+ auto it = _outputs.find(layer_name);
+ if (it != _outputs.end()) {
+ inference_engine_tensor_buffer& buffer = it->second;
+ float *data = static_cast<float *>(buffer.buffer);
+
+ for (size_t idx = 0; idx < buffer.size / 4; ++idx)
+ feature_vec.push_back(data[idx]);
+
+ return INFERENCE_ENGINE_ERROR_NONE;
+ }
+
+ return INFERENCE_ENGINE_ERROR_INTERNAL;
+}
+
+int InferenceEngineHelper::GetOutputBuffer(std::string layer_name, inference_engine_tensor_buffer& output)
+{
+ auto it = _outputs.find(layer_name);
+ if (it != _outputs.end()) {
+ output = it->second;
+ return INFERENCE_ENGINE_ERROR_NONE;
+ }
+
+ return INFERENCE_ENGINE_ERROR_INTERNAL;
+}
\ No newline at end of file
--- /dev/null
+project(${MV_TRAINING_LIB_NAME})
+cmake_minimum_required(VERSION 2.6)
+
+pkg_check_modules(${PROJECT_NAME}_DEP REQUIRED training-engine-interface-common)
+file(GLOB MV_TRAINING_SOURCE_LIST "${PROJECT_SOURCE_DIR}/src/*.c" "${PROJECT_SOURCE_DIR}/src/*.cpp")
+
+find_package(OpenCV REQUIRED dnn imgproc)
+if(NOT OpenCV_FOUND)
+ message(SEND_ERROR "OpenCV NOT FOUND")
+ return()
+endif()
+
+if(FORCED_STATIC_BUILD)
+ add_library(${PROJECT_NAME} STATIC ${MV_TRAINING_SOURCE_LIST})
+else()
+ add_library(${PROJECT_NAME} SHARED ${MV_TRAINING_SOURCE_LIST})
+endif()
+
+target_link_libraries(${PROJECT_NAME} ${MV_COMMON_LIB_NAME} ${OpenCV_LIBS} ${${PROJECT_NAME}_DEP_LIBRARIES})
+target_include_directories(${PROJECT_NAME} PRIVATE include)
+install(TARGETS ${PROJECT_NAME} DESTINATION ${LIB_INSTALL_DIR})
--- /dev/null
+/**
+ * Copyright (c) 2021 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 DATA_SET_MANAGER_H
+#define DATA_SET_MANAGER_H
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+
+#include "feature_vector_manager.h"
+
+class DataSetManager {
+protected:
+ std::vector<std::vector<float>> _data;
+ std::vector<std::vector<float>> _labels;
+ std::vector<unsigned int> _label_index;
+ size_t _feature_vector_size;
+ size_t _label_size;
+ size_t _data_set_length;
+
+public:
+ DataSetManager();
+ ~DataSetManager();
+
+ virtual void LoadDataSet(const std::string file_name);
+ void Clear();
+ bool IsFeatureVectorDuplicated(const std::vector<float>& vec);
+ std::vector<std::vector<float>>& GetData(void);
+ std::vector<std::vector<float>>& GetLabel(void);
+ size_t GetFeaVecSize(void);
+ size_t GetLabelSize(void);
+ size_t GetDataSetLen(void);
+ std::vector<unsigned int>& GetLabelIdx(void);
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 FEATURE_VECTOR_MANAGER_H
+#define FEATURE_VECTOR_MANAGER_H
+
+#include <string.h>
+#include <iostream>
+#include <fstream>
+#include <istream>
+#include <algorithm>
+#include <vector>
+#include <map>
+
+#include <opencv2/opencv.hpp>
+#include <opencv2/imgproc/imgproc.hpp>
+
+#include "file_util.h"
+
+static const unsigned int feature_vector_signagure = 0xFEA09841;
+
+typedef struct {
+ unsigned int signature;
+ size_t feature_size;
+ size_t one_hot_table_size;
+ unsigned int data_set_cnt;
+} FeaVecHeader;
+
+class FeatureVectorManager {
+protected:
+ std::string _feature_vector_file;
+
+public:
+ FeatureVectorManager(const std::string feature_vector_file = "feature_vector_file.dat");
+ ~FeatureVectorManager();
+
+ const std::string& GetFileName();
+ static void GetVecFromImg(const std::string image_file, std::vector<float>& vec, int width, int height);
+ static void GetVecFromRGB(unsigned char *in_data, std::vector<float>& vec, int width, int height,
+ int re_width, int re_height);
+ static void GetVecFromXRGB(unsigned char *in_data, std::vector<float>& vec,
+ int in_width, int in_height, int re_width, int re_height);
+
+ virtual void WriteHeader(size_t feature_size, size_t one_hot_table_size, unsigned int data_set_cnt);
+ virtual void ReadHeader(FeaVecHeader& header);
+ virtual void WriteFeatureVec(std::vector<float>& feature_vec, const int max_label, const int label_index);
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 FILE_UTIL_H
+#define FILE_UTIL_H
+
+#include <iostream>
+#include <sys/stat.h>
+
+namespace FaceRecogUtil
+{
+ bool IsFileExist(const std::string file_path);
+ bool IsImageFile(const std::string image_file);
+}
+
+#endif
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 LABEL_MANAGER_H
+#define LABEL_MANAGER_H
+
+#include <string.h>
+#include <iostream>
+#include <fstream>
+#include <istream>
+#include <algorithm>
+#include <vector>
+#include <map>
+
+#include "file_util.h"
+
+class LabelManager {
+private:
+ std::map<std::string, std::string> _labels_and_files;
+ std::string _label_file;
+ // Correct answer should be bigger than this value. In defualt it has -0.67.
+ static constexpr float _default_decision_threshold = -0.97;
+ float _decision_threshold;
+ static constexpr float _decision_weight = 1.2;
+
+public:
+ LabelManager(std::string label_file = "labels.dat");
+ ~LabelManager();
+ void Clear();
+ float GetDecisionThreshold();
+ float GetDecisionWeight();
+ unsigned int GetLabelIndex(const std::string given_label);
+ bool IsExist(const std::string given_label);
+ unsigned int RemoveLabel(const std::string given_label);
+ int GetLabelString(std::string& label, const int idx);
+ unsigned int AddLabelToFile(std::string given_label);
+ int ImportLabel(void);
+ bool AddLabelToMap(const std::string given_label, const std::string image_file);
+ int GetMaxLabel(const std::string label_file);
+ int GetMaxLabel();
+ std::string GetLabelFromAnswer(const std::vector<float>& result);
+};
+
+#endif
--- /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.
+ */
+
+#ifndef TRAINING_MODEL_H
+#define TRAINING_MODEL_H
+
+#include <iostream>
+#include <map>
+
+#include "training_engine_error.h"
+#include "training_engine_common_impl.h"
+#include "inference_engine_common_impl.h"
+#include "data_set_manager.h"
+#include "feature_vector_manager.h"
+
+typedef struct {
+ std::string backend_name;
+ unsigned int target_device;
+ std::vector<std::string> input_layer_names;
+ std::vector<std::string> output_layer_names;
+ std::vector<inference_engine_tensor_info> input_tensor_info;
+ std::vector<inference_engine_tensor_info> output_tensor_info;
+ training_engine_optimizer_property optimizer_property;
+ training_engine_compile_property compile_property;
+} TrainingEngineBackendInfo;
+
+class TrainingModel {
+protected:
+ std::unique_ptr<TrainingEngineInterface::Common::TrainingEngineCommon> _training;
+ std::unique_ptr<training_engine_model> _model;
+ std::unique_ptr<training_engine_dataset> _data_set;
+ std::map<int, std::string> _backend_lookup;
+ std::string _internal_model_file;
+
+public:
+ TrainingModel(const training_engine_backend_type_e backend_type = TRAINING_ENGINE_BACKEND_NNTRAINER,
+ const std::string internal_model_file = "model_and_weights.ini");
+ ~ TrainingModel();
+
+ void ApplyDataSet(std::unique_ptr<DataSetManager>& data_set);
+ void Compile();
+ void Training();
+
+ virtual void ConfigureModel(int num_of_class);
+ virtual TrainingEngineBackendInfo& GetTrainingEngineInfo();
+ virtual void SaveModel(const std::string file_path);
+};
+
+#endif
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 "data_set_manager.h"
+
+using namespace std;
+
+DataSetManager::DataSetManager() : _data(), _labels(), _label_index(), _feature_vector_size(), _label_size(), _data_set_length()
+{
+
+}
+
+DataSetManager::~DataSetManager()
+{
+ Clear();
+}
+
+void DataSetManager::LoadDataSet(const std::string file_name)
+{
+ LoadDataSet(file_name);
+}
+
+void DataSetManager::Clear()
+{
+ for (auto& data : _data)
+ data.clear();
+
+ _data.clear();
+
+ for (auto& label : _labels)
+ label.clear();
+
+ _labels.clear();
+ _label_index.clear();
+}
+
+bool DataSetManager::IsFeatureVectorDuplicated(const std::vector<float>& vec)
+{
+ if (_data.empty())
+ return false;
+
+ bool duplicated = false;
+
+ for (size_t item_idx = 0; item_idx < _data.size(); ++item_idx) {
+ if (vec.size() != _data[item_idx].size())
+ continue;
+
+ duplicated = true;
+
+ for (size_t val_idx = 0; val_idx < _data[item_idx].size(); ++val_idx) {
+ if (vec[val_idx] != _data[item_idx][val_idx]) {
+ duplicated = false;
+ break;
+ }
+ }
+
+ if (duplicated)
+ return true;
+ }
+
+ return duplicated;
+}
+
+std::vector<std::vector<float>>& DataSetManager::GetData(void)
+{
+ return _data;
+}
+
+std::vector<std::vector<float>>& DataSetManager::GetLabel(void)
+{
+ return _labels;
+}
+
+size_t DataSetManager::GetFeaVecSize(void)
+{
+ return _feature_vector_size;
+}
+
+size_t DataSetManager::GetLabelSize(void)
+{
+ return _label_size;
+}
+
+size_t DataSetManager::GetDataSetLen(void)
+{
+ return _data_set_length;
+}
+
+std::vector<unsigned int>& DataSetManager::GetLabelIdx(void)
+{
+ return _label_index;
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 <opencv2/opencv.hpp>
+#include <opencv2/imgproc/imgproc.hpp>
+
+#include "feature_vector_manager.h"
+
+using namespace std;
+
+FeatureVectorManager::FeatureVectorManager(const std::string feature_vector_file) : _feature_vector_file(feature_vector_file)
+{
+
+}
+
+FeatureVectorManager::~FeatureVectorManager()
+{
+
+}
+
+const std::string& FeatureVectorManager::GetFileName() {
+ return _feature_vector_file;
+}
+
+void FeatureVectorManager::GetVecFromImg(const std::string image_file, std::vector<float>& vec, int width, int height)
+{
+ cv::Mat src, dst;
+
+ if (!FaceRecogUtil::IsImageFile(image_file))
+ throw std::string("Invalid image file.");
+
+ src = cv::imread(image_file);
+
+ if (!src.data)
+ throw std::string("Invalid src.data.");
+
+ cv::cvtColor(src, src, cv::COLOR_BGR2RGB);
+
+ cv::Mat resized;
+
+ resize(src, resized, cv::Size(width, height), 0, 0, cv::INTER_CUBIC);
+
+ cv::Mat floatSrc;
+
+ resized.convertTo(floatSrc, CV_32FC3);
+
+ cv::Mat meaned = cv::Mat(floatSrc.size(), CV_32FC3, cv::Scalar(127.5f, 127.5f, 127.5f));
+
+ cv::subtract(floatSrc, meaned, dst);
+ dst /= 127.5f;
+
+ vec.assign((float *)dst.data, (float *)dst.data + dst.total() * dst.channels());
+}
+
+void FeatureVectorManager::GetVecFromRGB(unsigned char *in_data, std::vector<float>& vec,
+ int width, int height, int re_width, int re_height)
+{
+ cv::Mat cvSrc = cv::Mat(cv::Size(width, height), CV_MAKETYPE(CV_8U, 3), in_data).clone();
+
+ cv::Mat resized;
+
+ resize(cvSrc, resized, cv::Size(re_width, re_height), 0, 0, cv::INTER_CUBIC);
+
+ cv::Mat floatSrc;
+
+ resized.convertTo(floatSrc, CV_32FC3);
+
+ cv::Mat meaned = cv::Mat(floatSrc.size(), CV_32FC3, cv::Scalar(127.5f, 127.5f, 127.5f));
+ cv::Mat dst;
+
+ cv::subtract(floatSrc, meaned, dst);
+ dst /= 127.5f;
+
+ vec.assign((float *)dst.data, (float *)dst.data + dst.total() * dst.channels());
+}
+
+void FeatureVectorManager::GetVecFromXRGB(unsigned char *in_data, std::vector<float>& vec,
+ int in_width, int in_height, int re_width, int re_height)
+{
+ cv::Mat argb(cv::Size(in_width, in_height), CV_8UC4, in_data);
+
+ cv::Mat split_rgbx[4];
+ cv::split (argb, split_rgbx);
+ cv::Mat splitted[] = {split_rgbx[0], split_rgbx[1], split_rgbx[2]};
+ cv::Mat rgb;
+ cv::merge(splitted, 3, rgb);
+
+ cv::Mat resized;
+
+ resize(rgb, resized, cv::Size(re_width, re_height), 0, 0, cv::INTER_CUBIC);
+
+ cv::Mat floatSrc;
+
+ resized.convertTo(floatSrc, CV_32FC3);
+
+ cv::Mat meaned = cv::Mat(floatSrc.size(), CV_32FC3, cv::Scalar(127.5f, 127.5f, 127.5f));
+
+ cv::Mat dst;
+
+ cv::subtract(floatSrc, meaned, dst);
+ dst /= 127.5f;
+
+ vec.assign((float *)dst.data, (float *)dst.data + dst.total() * dst.channels());
+}
+
+void FeatureVectorManager::WriteHeader(size_t feature_size, size_t one_hot_table_size, unsigned int data_set_cnt)
+{
+ WriteHeader(feature_size, one_hot_table_size, data_set_cnt);
+}
+
+void FeatureVectorManager::ReadHeader(FeaVecHeader& header)
+{
+ ReadHeader(header);
+}
+
+void FeatureVectorManager::WriteFeatureVec(std::vector<float>& feature_vec, const int max_label, const int label_index)
+{
+ WriteFeatureVec(feature_vec, max_label, label_index);
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 <file_util.h>
+
+namespace FaceRecogUtil
+{
+ bool IsFileExist(const std::string file_path)
+ {
+ struct stat fileStat;
+
+ if (stat(file_path.c_str(), &fileStat))
+ return false;
+
+ if (!S_ISREG(fileStat.st_mode))
+ return false;
+
+ return true;
+ }
+
+ bool IsImageFile(const std::string image_file)
+ {
+
+ size_t size = image_file.size();
+
+ // At least, the length of a image file name should be more then 5. i.e., a.bmp, a.jpg, a.png, ...
+ if (size < 5)
+ return false;
+
+ std::string ext = image_file.substr(size - 3);
+ if (ext.compare("bmp") != 0 && ext.compare("jpg") != 0 && ext.compare("png") != 0)
+ return false;
+
+ return true;
+ }
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 <dlog.h>
+#include <mv_private.h>
+
+#include "label_manager.h"
+
+#define DECISION_THRESHOLD_FILE "decision.txt"
+
+using namespace std;
+
+LabelManager::LabelManager(std::string label_file) : _labels_and_files(), _label_file(label_file)
+{
+ std::ifstream readFile;
+
+ readFile.open(DECISION_THRESHOLD_FILE);
+
+ if (readFile.fail())
+ _decision_threshold = _default_decision_threshold;
+ else
+ readFile >> _decision_threshold;
+
+ LOGD("decision_threshold value is %f", _decision_threshold);
+}
+
+LabelManager::~LabelManager() { }
+
+void LabelManager::Clear() {
+ _labels_and_files.clear();
+}
+
+float LabelManager::GetDecisionThreshold() {
+ return _decision_threshold;
+}
+
+float LabelManager::GetDecisionWeight() {
+ return _decision_weight;
+}
+
+unsigned int LabelManager::GetLabelIndex(const std::string given_label)
+{
+ std::ifstream readFile;
+
+ readFile.open(_label_file.c_str());
+
+ int label_index = -1;
+
+ if (readFile.fail())
+ throw std::string("Fail to open " + _label_file + " file.");
+
+ std::string line;
+
+ while (getline(readFile, line)) {
+ label_index++;
+
+ if (line.compare(given_label) == 0) {
+ readFile.close();
+
+ return label_index;
+ }
+ }
+
+ readFile.close();
+ throw std::string("Label index not found.");
+}
+
+bool LabelManager::IsExist(const std::string given_label)
+{
+ std::ifstream readFile;
+
+ readFile.open(_label_file.c_str());
+
+ int label_index = -1;
+
+ if (readFile.fail())
+ throw std::string("Fail to open " + _label_file + " file.");
+
+ std::string line;
+
+ while (getline(readFile, line)) {
+ label_index++;
+
+ if (line.compare(given_label) == 0) {
+ readFile.close();
+ return true;
+ }
+ }
+
+ readFile.close();
+ return false;
+}
+
+unsigned int LabelManager::RemoveLabel(const std::string given_label)
+{
+ std::ifstream readFile;
+
+ readFile.open(_label_file.c_str());
+
+ std::ofstream writeFile;
+
+ std::string new_label_file(_label_file);
+
+ new_label_file += ".new";
+
+ writeFile.open(new_label_file.c_str(), std::ios::out | std::ios::binary);
+
+ int label_index = 0;
+
+ if (readFile.fail() || !writeFile.is_open())
+ throw std::string("Fail to open " + _label_file + "or " + new_label_file + " file.");
+
+ std::string line;
+
+ while (getline(readFile, line)) {
+ if (line.compare(given_label) != 0) {
+ line += "\n";
+ writeFile.write(line.c_str(), line.size());
+ label_index++;
+ }
+ }
+
+ readFile.close();
+ writeFile.close();
+
+ if (label_index == 0) {
+ // Just keep original version in case of no copy so drop the new label file.
+ remove(new_label_file.c_str());
+ } else {
+ remove(_label_file.c_str());
+ rename(new_label_file.c_str(), _label_file.c_str());
+ }
+
+ return label_index;
+}
+
+int LabelManager::GetLabelString(std::string& label, const int idx)
+{
+ std::ifstream readFile;
+
+ readFile.open(_label_file.c_str());
+
+ int label_index = -1;
+ int ret = 0;
+
+ if (readFile.fail())
+ throw std::string("Fail to open " + _label_file + " file.");
+
+ std::string line;
+
+ while (getline(readFile, line)) {
+ label_index++;
+ line += "\n";
+
+ if (idx == label_index) {
+ label = line;
+ label.erase(std::remove(label.begin(), label.end(), '\n'), label.end());
+ break;
+ }
+ }
+
+ readFile.close();
+ return ret;
+}
+
+unsigned int LabelManager::AddLabelToFile(std::string given_label)
+{
+ std::ofstream writeFile;
+
+ writeFile.open(_label_file.c_str(), std::ios::out | std::ios::app);
+
+ if (!writeFile.is_open())
+ throw std::string("Fail to open " + _label_file + " file.");
+
+ given_label += "\n";
+ writeFile.write(given_label.c_str(), given_label.size());
+ writeFile.close();
+
+ return GetMaxLabel(_label_file);
+}
+
+int LabelManager::ImportLabel(void)
+{
+ // label count is 0 if lael file doesn't exist.
+ if (!FaceRecogUtil::IsFileExist(_label_file))
+ return 0;
+
+ std::ifstream readFile;
+
+ readFile.open(_label_file);
+
+ int label_cnt = 0;
+
+ if (readFile.fail())
+ throw std::string("Fail to open " + _label_file + " file.");
+
+ std::string line;
+
+ while (getline(readFile, line)) {
+ bool duplicated = AddLabelToMap(line, line);
+ if (duplicated)
+ continue;
+
+ label_cnt++;
+ }
+
+ readFile.close();
+
+ return label_cnt;
+}
+
+
+bool LabelManager::AddLabelToMap(const std::string given_label, const std::string image_file)
+{
+ // Find same one if not empty. If same one exists in the map then skip.
+ if (!_labels_and_files.empty()) {
+ auto item = _labels_and_files.find(given_label);
+ if (item != _labels_and_files.end())
+ return true;
+ }
+
+ _labels_and_files.insert(std::pair<std::string, std::string>(given_label, image_file));
+
+ return false;
+}
+
+int LabelManager::GetMaxLabel(const std::string label_file)
+{
+
+ // label count is 0 if lael file doesn't exist.
+ if (!FaceRecogUtil::IsFileExist(label_file))
+ return 0;
+
+ std::ifstream readFile;
+
+ readFile.open(label_file.c_str());
+
+ int label_cnt = 0;
+
+ if (readFile.fail())
+ throw std::string("Fail to open " + label_file + " file.");
+
+ std::string line;
+
+ while (getline(readFile, line))
+ label_cnt++;
+
+ readFile.close();
+
+ return label_cnt;
+}
+
+int LabelManager::GetMaxLabel()
+{
+ return GetMaxLabel(_label_file);
+}
+
+std::string LabelManager::GetLabelFromAnswer(const std::vector<float>& result)
+{
+ if (result.empty())
+ throw std::string("result vector is empty.");
+
+ int answer_idx = max_element(result.begin(), result.end()) - result.begin();
+ if (result[answer_idx] < _decision_threshold)
+ return std::string("Not recognized.");
+
+ std::string answer_label;
+
+ int ret = GetLabelString(answer_label, answer_idx);
+ if (ret)
+ throw std::string("answer label not found.");
+
+ return answer_label;
+}
\ No newline at end of file
--- /dev/null
+/**
+ * Copyright (c) 2021 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 <string.h>
+#include <fstream>
+#include <istream>
+#include <tuple>
+#include <map>
+#include <algorithm>
+
+#include <sys/stat.h>
+
+#include <dlog.h>
+#include <mv_private.h>
+
+#include "training_model.h"
+
+using namespace std;
+using namespace TrainingEngineInterface::Common;
+
+TrainingModel::TrainingModel(const training_engine_backend_type_e backend_type, const std::string internal_model_file)
+{
+ _internal_model_file = internal_model_file;
+
+ _backend_lookup.insert(make_pair<int, string>(TRAINING_ENGINE_BACKEND_NNTRAINER, "nntrainer"));
+
+ try {
+ _training = std::make_unique<TrainingEngineInterface::Common::TrainingEngineCommon>();
+ } catch (std::string& exception) {
+ std::cerr << exception << std::endl;
+ return;
+ } catch (const std::exception& e) {
+ std::cerr << e.what() << std::endl;
+ return;
+ }
+}
+TrainingModel::~ TrainingModel()
+{
+ if (_training)
+ _training->UnbindBackend();
+}
+
+void TrainingModel::ApplyDataSet(unique_ptr<DataSetManager>& data_set)
+{
+ vector<vector<float>> values = data_set->GetData();
+ vector<vector<float>> labels = data_set->GetLabel();
+
+ LOGD("Generating feature vectors for training");
+
+ _data_set = _training->CreateDataset();
+ if (!_data_set)
+ throw std::string("Fail to create a dataset.");
+
+ int ret;
+
+ for (size_t idx = 0; idx < values.size(); ++idx) {
+ ret = _training->AddDataToDataset(_data_set.get(), values[idx], labels[idx], TRAINING_DATASET_TYPE_TRAIN);
+ if (ret != TRAINING_ENGINE_ERROR_NONE)
+ throw string("Fail to add data to dataset.");
+ }
+
+ data_set->Clear();
+
+ ret = _training->SetDataset(_model.get(), _data_set.get());
+ if (ret != TRAINING_ENGINE_ERROR_NONE)
+ throw string("Fail to set dataset to model.");
+}
+
+void TrainingModel::Compile()
+{
+ auto optimizer = _training->CreateOptimizer(TRAINING_OPTIMIZER_TYPE_SGD);
+ if (!optimizer)
+ throw string("Fail to create a optimizer.");
+
+ int ret = _training->SetOptimizerProperty(optimizer.get(), GetTrainingEngineInfo().optimizer_property);
+ if (ret != TRAINING_ENGINE_ERROR_NONE)
+ throw string("Fail to set optimizer property.");
+
+ ret = _training->AddOptimizer(_model.get(), optimizer.get());
+ if (ret != TRAINING_ENGINE_ERROR_NONE)
+ throw string("Fail to add optimizer to model.");
+
+ ret = _training->CompileModel(_model.get(), GetTrainingEngineInfo().compile_property);
+ if (ret != TRAINING_ENGINE_ERROR_NONE)
+ throw string("Fail to compile model.");
+}
+
+void TrainingModel::Training()
+{
+ training_engine_model_property model_property;
+ int ret = _training->TrainModel(_model.get(), model_property);
+ if (ret != TRAINING_ENGINE_ERROR_NONE)
+ throw string("Fail to train model.");
+
+ try {
+ // Save model file.
+ SaveModel(_internal_model_file);
+ } catch (const string& exception) {
+ throw exception;
+ } catch (const exception& e) {
+ throw e;
+ }
+}
+
+void TrainingModel::ConfigureModel(int num_of_class)
+{
+ // Child class implements model and layer configuration for training approach
+ // because there are various apparches so call child class's function.
+ ConfigureModel(num_of_class);
+}
+
+TrainingEngineBackendInfo& TrainingModel::GetTrainingEngineInfo()
+{
+ return GetTrainingEngineInfo();
+}
+
+void TrainingModel::SaveModel(const std::string file_path)
+{
+ SaveModel(file_path);
+}
\ No newline at end of file
Name: capi-media-vision
Summary: Media Vision library for Tizen Native API
-Version: 0.16.0
+Version: 0.17.0
Release: 0
Group: Multimedia/Framework
License: Apache-2.0 and BSD-3-Clause
BuildRequires: pkgconfig(json-glib-1.0)
BuildRequires: pkgconfig(iniparser)
BuildRequires: pkgconfig(inference-engine-interface-common)
+BuildRequires: pkgconfig(training-engine-interface-common)
%if !0%{?ml_only:1}
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(zbar)
%manifest %{name}.manifest
%license LICENSE.APLv2
%{_libdir}/libmv_inference*.so
+%{_libdir}/libmv_training.so
+%{_libdir}/libmv_face_recognition.so
%files machine_learning-devel
%{_includedir}/media/mv_infer*.h
cmake_minimum_required(VERSION 2.6)
add_subdirectory(${PROJECT_SOURCE_DIR}/inference)
+add_subdirectory(${PROJECT_SOURCE_DIR}/face_recognition)
\ No newline at end of file
--- /dev/null
+project(mv_face_recognition_test_suite)
+cmake_minimum_required(VERSION 2.6)
+
+add_executable(${PROJECT_NAME} test_face_recognition.cpp)
+
+target_link_libraries(${PROJECT_NAME} gtest gtest_main
+ mv_face_recognition
+ mv_image_helper
+)
+
+install(TARGETS ${PROJECT_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR})
--- /dev/null
+/**
+ * Copyright (c) 2021 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 <iostream>
+#include <string.h>
+#include <map>
+
+#include "gtest/gtest.h"
+
+#include "ImageHelper.h"
+#include "mv_face_recognition.h"
+
+using namespace testing;
+using namespace std;
+
+static const map<string, string> training_images = {
+ { "037830.png", "2929" },
+ { "038965.png", "2929" },
+ { "045978.png", "2929" },
+ { "050501.png", "2929" },
+ { "065899.png", "2929" },
+ { "010348.png", "7779" },
+ { "029342.png", "7779" },
+ { "035939.png", "7779" },
+ { "061310.png", "7779" },
+ { "062261.png", "7779" },
+ { "000928.png", "3448" },
+ { "008922.png", "3448" },
+ { "029633.png", "3448" },
+ { "032962.png", "3448" },
+ { "054616.png", "3448" }
+};
+
+static const map<string, string> test_images = {
+ { "068468.png", "2929" },
+ { "068883.png", "2929" },
+ { "075004.png", "2929" },
+ { "078125.png", "2929" },
+ { "080649.png", "2929" },
+ { "074645.png", "7779" },
+ { "086536.png", "7779" },
+ { "089334.png", "7779" },
+ { "096514.png", "7779" },
+ { "100336.png", "7779" },
+ { "054757.png", "3448" },
+ { "064838.png", "3448" },
+ { "072749.png", "3448" },
+ { "073526.png", "3448" },
+ { "080451.png", "3448" }
+};
+
+using namespace MediaVision::Common;
+
+TEST(FaceRecognitionTest, FaceRecognitionClassShouldBeOk)
+{
+ mv_face_recognition_h handle;
+ vector<string> answers = {
+ "3448", "3448", "2929", "2929", "3448",
+ "3448", "7779", "2929", "2929", "3448",
+ "2929", "7779", "7779", "7779", "7779"
+ };
+
+ int ret = mv_face_recognition_create(&handle);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ ret = mv_face_recognition_prepare(handle);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ for (auto& image : training_images) {
+ const string image_path = string("/opt/usr/images/training/") + image.first;
+ mv_source_h mv_source = NULL;
+
+ int ret = mv_create_source(&mv_source);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ ret = ImageHelper::loadImageToSource(image_path.c_str(), mv_source);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ ret = mv_face_recognition_register(handle, mv_source, image.second.c_str());
+ ASSERT_EQ(ret, 0);
+
+ ret = mv_destroy_source(mv_source);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+ }
+
+ unsigned int image_idx = 0;
+
+ for (auto& image : test_images) {
+ const string image_path = string("/opt/usr/images/test/") + image.first;
+ mv_source_h mv_source = NULL;
+
+ int ret = mv_create_source(&mv_source);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ ret = ImageHelper::loadImageToSource(image_path.c_str(), mv_source);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ char out_label[MAX_LABEL_SIZE];
+
+ ret = mv_face_recognition_inference(handle, mv_source, out_label);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ ret = mv_destroy_source(mv_source);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ ASSERT_TRUE(answers[image_idx++] == string(out_label));
+ }
+
+ ret = mv_face_recognition_destroy(handle);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+}
+
+TEST(FaceRecognitionTest, FaceRecognitionClassWithEachLabelRemovalShouldBeOk)
+{
+ vector<string> labels = { "", "3448", "2929", "7779" };
+ vector<vector<string>> answers = {
+ { "3448", "3448", "2929", "2929", "3448",
+ "3448", "7779", "2929", "2929", "3448",
+ "2929", "7779", "7779", "7779", "7779" },
+ { "7779", "7779", "2929", "2929", "7779",
+ "2929", "7779", "2929", "2929", "7779",
+ "2929", "7779", "7779", "7779", "7779" },
+ { "7779", "3448", "none", "none", "3448",
+ "3448", "7779", "none", "none", "3448",
+ "none", "7779", "7779", "7779", "7779" },
+ { "3448", "3448", "2929", "2929", "3448",
+ "3448", "none", "2929", "2929", "3448",
+ "2929", "none", "none", "none", "none" }
+ };
+
+ unsigned int label_idx = 0;
+
+ for (auto& label : labels) {
+ mv_face_recognition_h handle;
+
+ int ret = mv_face_recognition_create(&handle);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ ret = mv_face_recognition_prepare(handle);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ auto& answer = answers[label_idx++];
+ unsigned int image_idx = 0;
+
+ for (auto& image : training_images) {
+ const string image_path = string("/opt/usr/images/training/") + image.first;
+ mv_source_h mv_source = NULL;
+
+ ret = mv_create_source(&mv_source);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ ret = ImageHelper::loadImageToSource(image_path.c_str(), mv_source);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ ret = mv_face_recognition_register(handle, mv_source, image.second.c_str());
+ ASSERT_EQ(ret, 0);
+
+ ret = mv_destroy_source(mv_source);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+ }
+
+
+ if (!label.empty()) {
+ ret = mv_face_recognition_unregister(handle, label.c_str());
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+ }
+
+ for (auto& image : test_images) {
+ const string image_path = string("/opt/usr/images/test/") + image.first;
+ mv_source_h mv_source = NULL;
+
+ int ret = mv_create_source(&mv_source);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ ret = ImageHelper::loadImageToSource(image_path.c_str(), mv_source);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ char out_label[MAX_LABEL_SIZE];
+
+ ret = mv_face_recognition_inference(handle, mv_source, out_label);
+ if (ret == MEDIA_VISION_ERROR_NO_DATA) {
+ strcpy(out_label, "none");
+ ret = MEDIA_VISION_ERROR_NONE;
+ }
+
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ ret = mv_destroy_source(mv_source);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ ASSERT_TRUE(answer[image_idx++] == string(out_label));
+ }
+
+ ret = mv_face_recognition_destroy(handle);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+ }
+}
+
+int main(int argc, char **argv)
+{
+ InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}