*
* @param[in] handle The handle to the face recognition object.
* @param[in] source The handle to the source of the media.
- * @param[out] out_result The structure which is filled with inference result,
*
* @return @c 0 on success, otherwise a negative error value
* @retval #MEDIA_VISION_ERROR_NONE Successful
* @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,
- mv_face_recognition_result_s *out_result);
+int mv_face_recognition_inference(mv_face_recognition_h handle, mv_source_h source);
+
+/**
+ * @brief Get a label name.
+ * @details Use this function to get a label name after calling mv_face_recognition_inference function.
+ *
+ * @since_tizen 7.0
+ *
+ * @param[in] handle The handle to the face recognition object.
+ * @param[out] out_label The array pointer for the label name to be stored.
+ * This API returns memory pointer containing actual label string to @a out_label.
+ * So do not free @a out_label. And please note that @a out_label is valid only while handle is alive.
+ *
+ * @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_INVALID_OPERATION Invalid operation
+ *
+ * @pre Request a inference by calling @ref mv_face_recognition_inference()
+ */
+int mv_face_recognition_get_label(mv_face_recognition_h handle, const char **out_label);
#ifdef __cplusplus
}
#include <mv_common.h>
-/**
- * @brief Define MV_FACE_RECOGNITION_MAX_LABEL_LEN to indicate maximum label string length.
- *
- * @since_tizen 7.0
- */
-#define MV_FACE_RECOGNITION_MAX_LABEL_LEN 128
-/**
- * @brief Define MV_FACE_RECOGNITION_MAX_LABEL_CNT to indicate Maximum label count.
- *
- * @since_tizen 7.0
- */
-#define MV_FACE_RECOGNITION_MAX_LABEL_CNT 100
-
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
-/**
- * @brief The face recognition result structure.
- * @details Contains face recognition result such as label, label index, raw data,
- * and raw data count.
- * @since_tizen 7.0
- */
-typedef struct {
- unsigned int label_idx; /**< label index of label file. */
- char label[MV_FACE_RECOGNITION_MAX_LABEL_LEN]; /**< label string. */
- unsigned int raw_data_cnt; /**< raw data count which is a number of labels in label file. */
- float raw_data[MV_FACE_RECOGNITION_MAX_LABEL_CNT]; /**< raw data to each label. */
-} mv_face_recognition_result_s;
-
/**
* @brief The face recognition object handle.
*
#include "data_augment_flip.h"
#include "data_augment_rotate.h"
+namespace Mv
+{
+namespace FaceRecognition
+{
+namespace Status
+{
+ enum {
+ NONE = 0,
+ INITIALIZED,
+ REGISTERED,
+ INFERENCED,
+ DELETED
+ };
+}
+}
+}
+
+/**
+ * @brief The face recognition result structure.
+ * @details Contains face recognition result such as label, label index, raw data,
+ * and raw data count.
+ */
+typedef struct {
+ unsigned int label_idx; /**< label index of label file. */
+ std::vector<float> raw_data; /**< raw data to each label. */
+ std::string label; /**< label string. */
+} mv_face_recognition_result_s;
+
typedef struct {
mv_inference_target_device_e training_target_device_type;
mv_inference_backend_type_e training_engine_backend_type;
private:
FaceRecognitionConfig _config;
std::vector<std::unique_ptr<DataAugment>> _data_augments;
+ mv_face_recognition_result_s _result;
// FYI. This function should be called every time a new face is registered.
void ImportLabel();
std::unique_ptr<FeatureVectorManager> CreateFVM(const mv_inference_backend_type_e backend_type, std::string file_name);
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);
+ int GetAnswer();
std::vector<model_layer_info>& GetBackboneInputLayerInfo();
int GetVecFromMvSource(mv_source_h img_src, std::vector<float>& out_vec);
protected:
- bool _initialized;
+ unsigned int _status;
std::unique_ptr<mediavision::inference::Inference> _internal;
std::unique_ptr<mediavision::inference::Inference> _backbone;
std::unique_ptr<FaceNetInfo> _face_net_info;
std::unique_ptr<LabelManager> _label_manager;
public:
- // decision_threshold is used to decide correct answer. Correct answer should be bigger than -0.97.
FaceRecognition();
~ FaceRecognition();
int Initialize();
void SetConfig(FaceRecognitionConfig& config);
int RegisterNewFace(mv_source_h img_src, std::string label_name);
- int RecognizeFace(mv_source_h img_src, std::vector<float>& out_vec, unsigned int *out_idx);
+ int RecognizeFace(mv_source_h img_src);
int DeleteLabel(std::string label_name);
- int GetLabelWithIndex(std::string& out_label, unsigned int label_idx);
+ int GetLabel(const char **out_label);
};
#endif
\ No newline at end of file
*
* @since_tizen 7.0
*
- * @param [out] handle The handle to the face recognition object to be created
+ * @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
*
* @since_tizen 7.0
*
- * @param [in] handle The handle to the face recognition object to be destroyed.
+ * @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
*
* @since_tizen 7.0
*
- * @param [in] handle The handle to the face recognition object to be prepared.
+ * @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
*
* @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. (the maximum length of the label array is 256 words)
+ * @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. (the maximum length of the label array is 256 words)
*
* @return @c 0 on success, otherwise a negative error value
* @retval #MEDIA_VISION_ERROR_NONE Successful
*
* @since_tizen 7.0
*
- * @param [in] handle The handle to the face recognition object.
- * @param [in] label The label to be registered. (the maximum length of the label array is 256 words)
+ * @param[in] handle The handle to the face recognition object.
+ * @param[in] label The label to be registered. (the maximum length of the label array is 256 words)
*
* @return @c 0 on success, otherwise a negative error value
* @retval #MEDIA_VISION_ERROR_NONE Successful
/**
* @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] out_result The structure which is filled with inference result,
+ * @param[in] handle The handle to the face recognition object.
+ * @param[in] source The handle to the source of the media.
*
* @return @c 0 on success, otherwise a negative error value
* @retval #MEDIA_VISION_ERROR_NONE Successful
* @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,
- mv_face_recognition_result_s *out_result);
+ int mv_face_recognition_inference_open(mv_face_recognition_h handle, mv_source_h source);
+
+ /**
+ * @brief Get a label name and store it to @a out_label.
+ * @details Use this function to get a label name after calling mv_face_recognition_inference_open function.
+ *
+ * @since_tizen 7.0
+ *
+ * @param[in] handle The handle to the face recognition object.
+ * @param[out] out_label The array pointer for the label name to be stored.
+ *
+ * @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_INVALID_OPERATION Invalid operation
+ *
+ * @pre Request a inference by calling @ref mv_face_recognition_inference_open()
+ */
+ int mv_face_recognition_get_label_open(mv_face_recognition_h handle, const char **out_label);
#ifdef __cplusplus
}
using namespace std;
using namespace mediavision::inference;
using namespace TrainingEngineInterface::Common;
+using namespace Mv::FaceRecognition::Status;
using namespace Mediavision::MachineLearning::Exception;
FaceRecognition::FaceRecognition() :
- _initialized(false), _internal(), _backbone(), _face_net_info(), _training_model(), _label_manager()
+ _status(NONE), _internal(), _backbone(), _face_net_info(), _training_model(), _label_manager()
{
_data_augments.push_back(std::make_unique<DataAugmentDefault>());
/* Add other data argument classes. */
data_set_cnt += feature_vectors.size();
- // 2) If same feature vector isn't duplcated then write the feature vector to data set file.
+ // 2) If same feature vector isn't duplicated then write the feature vector to data set file.
if (!data_set->IsFeatureVectorDuplicated(feature_vec)) {
fvm_new->WriteFeatureVec(feature_vec, label_cnt, label_idx);
LOGD("Added a new feature vector to data set file.");
}
vector<model_layer_info>& input_layer_info = GetBackboneInputLayerInfo();
- // TODO. consider mutiple tensor info.
+ // TODO. consider multiple tensor info.
size_t re_width = input_layer_info[0].tensor_info.shape[0];
size_t re_height = input_layer_info[0].tensor_info.shape[1];
return ret;
- _initialized = true;
+ _status = INITIALIZED;
return MEDIA_VISION_ERROR_NONE;
}
{
vector<model_layer_info>& output_layer_info = _face_net_info->GetOutputLayerInfo();
- if (!_initialized) {
- LOGE("Initialization not ready yet.");
+ if (_status < INITIALIZED) {
+ LOGE("Initialization not ready yet. (%u)", _status);
return MEDIA_VISION_ERROR_INVALID_OPERATION;
}
// label_cnt can be changed every time the training is performed and all data set will be used for the training
// again in this case. So make sure to clear previous data set before next training.
_training_model->ClearDataSet(data_set);
+ _status = REGISTERED;
} catch (const BaseException& e) {
LOGE("%s", e.what());
return e.getError();
return MEDIA_VISION_ERROR_NONE;
}
-int FaceRecognition::GetAnswer(vector<float>& result_tensor, unsigned int *out_idx)
+int FaceRecognition::GetAnswer()
{
int answer_idx;
string result_str;
try {
- for (auto& r : result_tensor)
+ for (auto& r : _result.raw_data)
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();
+ answer_idx = max_element(_result.raw_data.begin(), _result.raw_data.end()) - _result.raw_data.begin();
// Check decision threshold.
- if (result_tensor[answer_idx] < _label_manager->GetDecisionThreshold()) {
+ if (_result.raw_data[answer_idx] < _label_manager->GetDecisionThreshold()) {
throw NoData("Not meet decision threshold.");
}
- float weighted = result_tensor[answer_idx] * _label_manager->GetDecisionWeight();
+ float weighted = _result.raw_data[answer_idx] * _label_manager->GetDecisionWeight();
// Check decision weight threshold.
- for (auto& r : result_tensor) {
- if (result_tensor[answer_idx] == r)
+ for (auto& r : _result.raw_data) {
+ if (_result.raw_data[answer_idx] == r)
continue;
if (weighted < r)
throw NoData("Not meet decision weight threshold");
}
- *out_idx = answer_idx;
+ _result.label_idx = answer_idx;
} catch (const BaseException& e) {
LOGE("%s", e.what());
return e.getError();
return MEDIA_VISION_ERROR_NONE;
}
-int FaceRecognition::RecognizeFace(mv_source_h img_src, vector<float>& out_vec, unsigned int *out_idx)
+int FaceRecognition::RecognizeFace(mv_source_h img_src)
{
- if (!_initialized) {
- LOGE("Initialization not ready yet.");
+ if (_status < INITIALIZED) {
+ LOGE("Initialization not ready yet.(%u)", _status);
return MEDIA_VISION_ERROR_INVALID_OPERATION;
}
// Face Recognition has following steps
// ------------------------------------
- // 1. Import labal data to in-memory from a file.
+ // 1. Import label data to in-memory from a file.
// 2. Do an inference with a backbone model to get feature vector.
// 3. Load internal model.
// 4. Do an inference with the internal model to get a label.
auto raw_buffer = static_cast<float *>(internal_output_buffer->buffer);
- copy(raw_buffer, raw_buffer + internal_output_buffer->size / sizeof(float), back_inserter(out_vec));
+ _result.raw_data.clear();
+ copy(raw_buffer, raw_buffer + internal_output_buffer->size / sizeof(float), back_inserter(_result.raw_data));
- return GetAnswer(out_vec, out_idx);
+ _status = INFERENCED;
+
+ return GetAnswer();
} catch (const BaseException& e) {
LOGE("%s", e.what());
return e.getError();
int FaceRecognition::DeleteLabel(string label_name)
{
+ if (_status < INITIALIZED) {
+ LOGE("Initialization not ready yet.(%u)", _status);
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
// Deleting a given label is to remove existing registered person from label and feature vector files.
try {
_training_model->ApplyDataSet(new_data_set);
_training_model->Compile();
_training_model->Train();
+
+ _status = DELETED;
} catch (const BaseException& e) {
LOGE("%s", e.what());
return e.getError();
return MEDIA_VISION_ERROR_NONE;
}
-int FaceRecognition::GetLabelWithIndex(string& out_label, unsigned int label_idx)
+int FaceRecognition::GetLabel(const char **out_label)
{
+ if (_status != INFERENCED) {
+ LOGE("Inference not completed yet.");
+ return MEDIA_VISION_ERROR_INVALID_OPERATION;
+ }
+
try {
- _label_manager->GetLabelString(out_label, label_idx);
+ _label_manager->GetLabelString(_result.label, _result.label_idx);
} catch (const BaseException& e) {
LOGE("%s", e.what());
return e.getError();
}
+ *out_label = _result.label.c_str();
+
return MEDIA_VISION_ERROR_NONE;
-}
+}
\ No newline at end of file
return ret;
}
-int mv_face_recognition_inference(mv_face_recognition_h handle, mv_source_h source,
- mv_face_recognition_result_s *out_result)
+int mv_face_recognition_inference(mv_face_recognition_h handle, mv_source_h source)
{
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_result);
MEDIA_VISION_FUNCTION_ENTER();
int ret = MEDIA_VISION_ERROR_NONE;
- ret = mv_face_recognition_inference_open(handle, source, out_result);
+ ret = mv_face_recognition_inference_open(handle, source);
+
+ MEDIA_VISION_FUNCTION_LEAVE();
+
+ return ret;
+}
+
+int mv_face_recognition_get_label(mv_face_recognition_h handle, const char **out_label)
+{
+ MEDIA_VISION_SUPPORT_CHECK(
+ __mv_inference_face_check_system_info_feature_supported());
+
+ MEDIA_VISION_INSTANCE_CHECK(handle);
+ MEDIA_VISION_INSTANCE_CHECK(out_label);
+
+ MEDIA_VISION_FUNCTION_ENTER();
+
+ int ret = MEDIA_VISION_ERROR_NONE;
+
+ ret = mv_face_recognition_get_label_open(handle, out_label);
MEDIA_VISION_FUNCTION_LEAVE();
return ret;
}
-int mv_face_recognition_inference_open(mv_face_recognition_h handle, mv_source_h source,
- mv_face_recognition_result_s *out_result)
+int mv_face_recognition_inference_open(mv_face_recognition_h handle, mv_source_h source)
{
LOGD("ENTER");
}
FaceRecognition *pFace = static_cast<FaceRecognition *>(handle);
- unsigned int out_idx;
- vector<float> out_vec;
- int ret = pFace->RecognizeFace(source, out_vec, &out_idx);
+ int ret = pFace->RecognizeFace(source);
if (ret == MEDIA_VISION_ERROR_NO_DATA) {
LOGW("Label not found.");
return ret;
}
- out_result->label_idx = out_idx;
- out_result->raw_data_cnt = min(static_cast<size_t>(MV_FACE_RECOGNITION_MAX_LABEL_CNT), out_vec.size());
+ if (ret != MEDIA_VISION_ERROR_NONE)
+ LOGE("Fail to recognize face.");
- copy_n(out_vec.begin(), out_result->raw_data_cnt, out_result->raw_data);
+ LOGD("LEAVE");
- if (ret != MEDIA_VISION_ERROR_NONE) {
- LOGE("Fail to recognize face.");
- return ret;
+ return ret;
+}
+
+int mv_face_recognition_get_label_open(mv_face_recognition_h handle, const char **out_label)
+{
+ LOGD("ENTER");
+
+ if (!handle) {
+ LOGE("Handle is NULL.");
+ return MEDIA_VISION_ERROR_INVALID_PARAMETER;
}
- string result_label;
+ FaceRecognition *pFace = static_cast<FaceRecognition *>(handle);
- ret = pFace->GetLabelWithIndex(result_label, out_idx);
+ int ret = pFace->GetLabel(out_label);
if (ret != MEDIA_VISION_ERROR_NONE) {
- LOGI("Fail to find label.");
+ LOGE("Fail to get label.");
return ret;
}
- if (result_label.length() >= MV_FACE_RECOGNITION_MAX_LABEL_LEN - 1)
- LOGW("Invalid label size. %d bytes will be filled only.", MV_FACE_RECOGNITION_MAX_LABEL_LEN - 1);
-
- int length = result_label.copy(out_result->label,
- min(result_label.length(), static_cast<size_t>(MV_FACE_RECOGNITION_MAX_LABEL_LEN)));
- out_result->label[length] = '\0';
-
LOGD("LEAVE");
return MEDIA_VISION_ERROR_NONE;
ret = ImageHelper::loadImageToSource(image_path.c_str(), mv_source);
ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
- mv_face_recognition_result_s result;
+ ret = mv_face_recognition_inference(handle, mv_source);
- ret = mv_face_recognition_inference(handle, mv_source, &result);
+ bool is_no_data = (ret == MEDIA_VISION_ERROR_NO_DATA);
+ const char *out_label = NULL;
+
+ ret = mv_face_recognition_get_label(handle, &out_label);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
auto it = find(cached_label.begin(), cached_label.end(), label);
if (it != cached_label.end()) {
total_positive_cnt++;
- if (label == string(result.label))
+ if (label == string(out_label))
true_positive_cnt++;
} else {
total_negative_cnt++;
- if (ret == MEDIA_VISION_ERROR_NO_DATA)
+ if (is_no_data)
true_negative_cnt++;
}
ret = ImageHelper::loadImageToSource(image_path.c_str(), mv_source);
ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
- mv_face_recognition_result_s result;
-
- ret = mv_face_recognition_inference(handle, mv_source, &result);
+ ret = mv_face_recognition_inference(handle, mv_source);
if (ret != MEDIA_VISION_ERROR_NO_DATA)
ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
ret = mv_destroy_source(mv_source);
ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
- if (answers[image_idx++] == result.label)
+ const char *out_label = NULL;
+
+ ret = mv_face_recognition_get_label(handle, &out_label);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ string label_str(out_label);
+
+ if (answers[image_idx++] == label_str)
correct_cnt++;
}
ret = ImageHelper::loadImageToSource(image_path.c_str(), mv_source);
ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
- mv_face_recognition_result_s result;
+ bool is_no_data = false;
+ const char *none_str = "none";
- ret = mv_face_recognition_inference(handle, mv_source, &result);
+ ret = mv_face_recognition_inference(handle, mv_source);
if (ret == MEDIA_VISION_ERROR_NO_DATA) {
- strcpy(result.label, "none");
+ is_no_data = true;
ret = MEDIA_VISION_ERROR_NONE;
}
ret = mv_destroy_source(mv_source);
ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
- if (answer[image_idx++] == result.label)
+ const char *out_label = NULL;
+
+ ret = mv_face_recognition_get_label(handle, &out_label);
+ ASSERT_EQ(ret, MEDIA_VISION_ERROR_NONE);
+
+ if (is_no_data)
+ out_label = const_cast<char *>(none_str);
+
+ string label_str(out_label);
+
+ if (answer[image_idx++] == label_str)
correct_cnt++;
}