You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

211 lines
7.2 KiB

// Copyright (C) 2020 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
//
#include <rs-vino/age-gender-detection.h>
#include <rs-vino/openvino-helpers.h>
#include <rsutils/easylogging/easyloggingpp.h>
using namespace InferenceEngine;
namespace openvino_helpers
{
age_gender_detection::age_gender_detection(
const std::string &pathToModel,
bool isAsync,
int maxBatch, bool isBatchDynamic,
bool doRawOutputMessages
)
: base_detection( "age/gender", pathToModel, maxBatch, isBatchDynamic, isAsync, doRawOutputMessages)
, _n_enqued_frames(0)
{
}
void age_gender_detection::submit_request()
{
if( !_n_enqued_frames )
return;
_n_enqued_frames = 0;
base_detection::submit_request();
}
void age_gender_detection::enqueue( const cv::Mat &face )
{
if( !enabled() )
return;
if( !_request )
_request = net.CreateInferRequestPtr();
Blob::Ptr inputBlob = _request->GetBlob( input );
matU8ToBlob<uint8_t>( face, inputBlob, _n_enqued_frames );
++_n_enqued_frames;
}
age_gender_detection::Result age_gender_detection::operator[] (int idx) const
{
Blob::Ptr genderBlob = _request->GetBlob( outputGender );
Blob::Ptr ageBlob = _request->GetBlob( outputAge );
age_gender_detection::Result r = {
ageBlob->buffer().as<float*>()[idx] * 100,
genderBlob->buffer().as<float*>()[idx * 2 + 1]
};
if (doRawOutputMessages)
LOG(DEBUG) << "element" << idx << ", male prob = " << r.maleProb << ", age = " << r.age;
return r;
}
CNNNetwork age_gender_detection::read_network()
{
LOG(INFO) << "Loading " << topoName << " model from: " << pathToModel;
CNNNetwork network;
#ifdef OPENVINO2019
CNNNetReader netReader;
/** Read network model **/
netReader.ReadNetwork( pathToModel );
network = netReader.getNetwork();
/** Extract model name and load its weights **/
std::string binFileName = remove_ext( pathToModel ) + ".bin";
netReader.ReadWeights( binFileName );
#else
InferenceEngine::Core ie;
/** Read network model **/
network = ie.ReadNetwork(pathToModel);
#endif
/** Set batch size **/
//LOG(DEBUG) << "Batch size is set to " << maxBatch;
network.setBatchSize(maxBatch);
// Age/Gender Recognition network should have one input and two outputs
LOG(DEBUG) << "Checking Age/Gender Recognition network inputs";
InputsDataMap inputInfo(network.getInputsInfo());
if (inputInfo.size() != 1)
throw std::logic_error("Age/Gender Recognition network should have only one input");
InputInfo::Ptr& inputInfoFirst = inputInfo.begin()->second;
inputInfoFirst->setPrecision(Precision::U8);
input = inputInfo.begin()->first;
LOG(DEBUG) << "Checking Age/Gender Recognition network outputs";
OutputsDataMap outputInfo(network.getOutputsInfo());
if (outputInfo.size() != 2)
throw std::logic_error("Age/Gender Recognition network should have two output layers");
auto it = outputInfo.begin();
DataPtr ptrAgeOutput = (it++)->second;
DataPtr ptrGenderOutput = (it++)->second;
if (!ptrAgeOutput)
throw std::logic_error("Age output data pointer is not valid");
if (!ptrGenderOutput)
throw std::logic_error("Gender output data pointer is not valid");
#ifdef OPENVINO2019
auto genderCreatorLayer = ptrGenderOutput->getCreatorLayer().lock();
auto ageCreatorLayer = ptrAgeOutput->getCreatorLayer().lock();
if (!ageCreatorLayer)
throw std::logic_error("Age creator layer pointer is not valid");
if (!genderCreatorLayer)
throw std::logic_error("Gender creator layer pointer is not valid");
// if gender output is convolution, it can be swapped with age
if (genderCreatorLayer->type == "Convolution")
std::swap(ptrAgeOutput, ptrGenderOutput);
if (ptrAgeOutput->getCreatorLayer().lock()->type != "Convolution")
throw std::logic_error("In Age/Gender Recognition network, age layer (" + ageCreatorLayer->name +
") should be a Convolution, but was: " + ageCreatorLayer->type);
if (ptrGenderOutput->getCreatorLayer().lock()->type != "SoftMax")
throw std::logic_error("In Age/Gender Recognition network, gender layer (" + genderCreatorLayer->name +
") should be a SoftMax, but was: " + genderCreatorLayer->type);
if (doRawOutputMessages)
{
LOG(DEBUG) << "Age layer: " << ageCreatorLayer->name;
LOG(DEBUG) << "Gender layer: " << genderCreatorLayer->name;
}
#else
#ifdef OPENVINO_NGRAPH
if (auto ngraphFunction = network.getFunction())
{
// Looking for the age and gender nodes in the ngraph: the age layer node should be Convolution type.
// If we find ptrGenderOutput is with Convolution type, swap them.
for (const auto& op : ngraphFunction->get_ops())
{
std::string friendly_name = op->get_friendly_name();
std::string output_type = op->get_type_name();
if ((friendly_name.find(ptrGenderOutput->getName()) != std::string::npos) && (output_type == "Convolution"))
{
std::swap(ptrAgeOutput, ptrGenderOutput);
break;
}
}
bool outputAgeOk = false;
for (const auto& op : ngraphFunction->get_ops())
{
std::string friendly_name = op->get_friendly_name();
std::string output_type = op->get_type_name();
if ((friendly_name.find(ptrAgeOutput->getName()) != std::string::npos) && (output_type == "Convolution")) {
outputAgeOk = true;
break;
}
}
if (!outputAgeOk)
{
throw std::logic_error("In Age/Gender Recognition network, Age layer (" + ptrAgeOutput->getName() + ") should be a Convolution");
}
bool outputGenderOk = false;
for (const auto& op : ngraphFunction->get_ops()) {
std::string friendly_name = op->get_friendly_name();
std::string output_type = op->get_type_name();
if ((friendly_name.find(ptrGenderOutput->getName()) != std::string::npos) && (output_type == "Softmax")) {
outputGenderOk = true;
break;
}
}
if (!outputGenderOk)
{
throw std::logic_error("In Age/Gender Recognition network, Gender layer (" + ptrGenderOutput->getName() + ") should be a Softmax");
}
}
if (doRawOutputMessages)
{
LOG(DEBUG) << "Age layer: " << ptrAgeOutput->getName();
LOG(DEBUG) << "Gender layer: " << ptrGenderOutput->getName();
}
#endif
#endif
outputAge = ptrAgeOutput->getName();
outputGender = ptrGenderOutput->getName();
_enabled = true;
return network;
}
}