346 lines
15 KiB
C++
346 lines
15 KiB
C++
#include "SCRFDOVFaceDetector.h"
|
|
#include "Utility.h"
|
|
|
|
// Still not working
|
|
namespace ANSCENTER {
|
|
bool ANSOVSCRFDFD::Initialize(std::string licenseKey, ModelConfig modelConfig, const std::string& modelZipFilePath, const std::string& modelZipPassword, std::string& labelMap) {
|
|
bool result = ANSFDBase::Initialize(licenseKey, modelConfig, modelZipFilePath, modelZipPassword, labelMap);
|
|
labelMap = "Face";
|
|
// We do not need to check for the license
|
|
_licenseValid = true;
|
|
if (!_licenseValid) return false;
|
|
try {
|
|
_modelConfig = modelConfig;
|
|
_modelConfig.modelType = ModelType::FACEDETECT;
|
|
_modelConfig.detectionType = DetectionType::FACEDETECTOR;
|
|
|
|
// We need to get the modelfolder from here
|
|
std::string xmlfile = CreateFilePath(_modelFolder, "scrfdface.xml");
|
|
if (std::filesystem::exists(xmlfile)) {
|
|
_modelFilePath = xmlfile;
|
|
this->_logger.LogDebug("ANSOVSCRFDFD::Initialize. Loading SCRFD weight", _modelFilePath, __FILE__, __LINE__);
|
|
}
|
|
else {
|
|
this->_logger.LogError("ANSOVSCRFDFD::Initialize. Model scrfdface.xml file is not exist", _modelFilePath, __FILE__, __LINE__);
|
|
return false;
|
|
}
|
|
|
|
ov::Core core;
|
|
std::shared_ptr<ov::Model> model = core.read_model(_modelFilePath);
|
|
//ov::preprocess::PrePostProcessor ppp = ov::preprocess::PrePostProcessor(model);
|
|
const ov::Shape& inputShape = model->input().get_shape();
|
|
|
|
ov::Layout layout = ov::layout::get_layout(model->input());
|
|
if (layout.empty()) {
|
|
layout = getLayoutFromShape(model->input().get_partial_shape());
|
|
slog::warn << "Automatically detected layout '" << layout.to_string() << "' for input '"
|
|
<< model->input().get_any_name() << "' will be used." << slog::endl;
|
|
}
|
|
|
|
|
|
const ov::Layout& inputLayout = layout;
|
|
|
|
//ppp.input().tensor().set_element_type(ov::element::u8).set_layout("NHWC").set_color_format(ov::preprocess::ColorFormat::BGR);
|
|
//ppp.input().preprocess().convert_element_type(ov::element::f32).convert_color(ov::preprocess::ColorFormat::RGB).scale({ 255, 255, 255 });
|
|
//ppp.input().model().set_layout("NCHW");
|
|
////ppp.output().tensor().set_element_type(ov::element::f32);
|
|
|
|
ov::preprocess::PrePostProcessor ppp(model);
|
|
inputTransform.setPrecision(ppp, model->input().get_any_name());
|
|
ppp.input().tensor().set_layout({ "NHWC" });
|
|
|
|
ppp.input().model().set_layout(inputLayout);
|
|
|
|
// --------------------------- Reading image input parameters -------------------------------------------
|
|
inputsNames.push_back(model->input().get_any_name());
|
|
netInputWidth = inputShape[ov::layout::width_idx(inputLayout)];
|
|
netInputHeight = inputShape[ov::layout::height_idx(inputLayout)];
|
|
|
|
// --------------------------- Prepare output -----------------------------------------------------
|
|
|
|
int outputSize = model->outputs().size();
|
|
std::cout << "output Size:" << outputSize << std::endl;
|
|
|
|
|
|
const ov::Layout outputLayout{ "CHW" };
|
|
maxProposalsCount = model->outputs().front().get_shape()[ov::layout::height_idx(outputLayout)];
|
|
for (const auto& output : model->outputs()) {
|
|
const auto outTensorName = output.get_any_name();
|
|
outputsNames.push_back(outTensorName);
|
|
ppp.output(outTensorName).tensor().set_element_type(ov::element::f32).set_layout(outputLayout);
|
|
}
|
|
std::sort(outputsNames.begin(), outputsNames.end());
|
|
model = ppp.build();
|
|
compiled_model_ = core.compile_model(model, "GPU");
|
|
inference_request_ = compiled_model_.create_infer_request();
|
|
const std::vector<ov::Output<ov::Node>> inputs = model->inputs();
|
|
const ov::Shape input_shape = inputs[0].get_shape();
|
|
|
|
short height = input_shape[1];
|
|
short width = input_shape[2];
|
|
model_input_shape_ = cv::Size2f(width, height);
|
|
|
|
const std::vector<ov::Output<ov::Node>> outputs = model->outputs();
|
|
const ov::Shape output_shape = outputs[0].get_shape();
|
|
|
|
height = output_shape[1];
|
|
width = output_shape[2];
|
|
model_output_shape_ = cv::Size(width, height);
|
|
_isInitialized = true;
|
|
return true;
|
|
}
|
|
catch (std::exception& e) {
|
|
this->_logger.LogFatal("ANSOVSCRFDFD::Initialize", e.what(), __FILE__, __LINE__);
|
|
std::cout << "Error:" << e.what();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool ANSOVSCRFDFD::LoadModel(const std::string& modelZipFilePath, const std::string& modelZipPassword) {
|
|
try {
|
|
// We need to get the _modelFolder
|
|
bool result = ANSFDBase::LoadModel(modelZipFilePath, modelZipPassword);
|
|
if (!result) return false;
|
|
|
|
// We need to get the modelfolder from here
|
|
std::string xmlfile = CreateFilePath(_modelFolder, "scrfdface.xml");
|
|
if (std::filesystem::exists(xmlfile)) {
|
|
_modelFilePath = xmlfile;
|
|
this->_logger.LogDebug("ANSOVSCRFDFD::LoadModel. Loading scrfdface weight", _modelFilePath, __FILE__, __LINE__);
|
|
}
|
|
else {
|
|
this->_logger.LogError("ANSOVSCRFDFD::LoadModel. Model scrfdface.xml file is not exist", _modelFilePath, __FILE__, __LINE__);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
catch (std::exception& e) {
|
|
this->_logger.LogFatal("ANSOVSCRFDFD::LoadModel", e.what(), __FILE__, __LINE__);
|
|
return false;
|
|
}
|
|
|
|
}
|
|
bool ANSOVSCRFDFD::OptimizeModel(bool fp16, std::string& optimizedModelFolder) {
|
|
if (!FileExist(_modelFilePath)) {
|
|
optimizedModelFolder = "";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
cv::Rect ANSOVSCRFDFD::GetBoundingBox(const cv::Rect& src) {
|
|
cv::Rect box = src;
|
|
box.x = (box.x - 0.5 * box.width) * factor_.x;
|
|
box.y = (box.y - 0.5 * box.height) * factor_.y;
|
|
box.width *= factor_.x;
|
|
box.height *= factor_.y;
|
|
|
|
return box;
|
|
}
|
|
|
|
std::vector<Object>ANSOVSCRFDFD::PostProcessing() {
|
|
try {
|
|
std::vector<int> class_list;
|
|
std::vector<float> confidence_list;
|
|
std::vector<cv::Rect> box_list;
|
|
|
|
float* detections = inference_request_.get_output_tensor().data<float>();
|
|
const cv::Mat detection_outputs(model_output_shape_, CV_32F, (float*)detections);
|
|
|
|
for (int i = 0; i < detection_outputs.cols; ++i) {
|
|
const cv::Mat classes_scores = detection_outputs.col(i).rowRange(4, detection_outputs.rows);
|
|
|
|
cv::Point class_id;
|
|
double score;
|
|
|
|
cv::minMaxLoc(classes_scores, nullptr, &score, nullptr, &class_id);
|
|
|
|
if (score > 0.4) {
|
|
class_list.push_back(class_id.y);
|
|
confidence_list.push_back(score);
|
|
|
|
const float x = detection_outputs.at<float>(0, i);
|
|
const float y = detection_outputs.at<float>(1, i);
|
|
const float w = detection_outputs.at<float>(2, i);
|
|
const float h = detection_outputs.at<float>(3, i);
|
|
|
|
cv::Rect box;
|
|
|
|
box.x = static_cast<int>(x);
|
|
box.y = static_cast<int>(y);
|
|
box.width = static_cast<int>(w);
|
|
box.height = static_cast<int>(h);
|
|
|
|
box_list.push_back(box);
|
|
}
|
|
}
|
|
|
|
std::vector<int> NMS_result;
|
|
cv::dnn::NMSBoxes(box_list, confidence_list, 0.5, 0.5, NMS_result);
|
|
|
|
std::vector<Object> output;
|
|
for (int i = 0; i < NMS_result.size(); i++)
|
|
{
|
|
Object result;
|
|
int id = NMS_result[i];
|
|
result.classId = class_list[id];
|
|
result.confidence = confidence_list[id];
|
|
result.box = GetBoundingBox(box_list[id]);
|
|
output.push_back(result);
|
|
}
|
|
return output;
|
|
}
|
|
|
|
catch (const std::exception& e) {
|
|
std::vector<Object> result;
|
|
result.clear();
|
|
std::cout << "ANSOVDetector::PostprocessImage. " << e.what() << std::endl;
|
|
return result;
|
|
}
|
|
|
|
}
|
|
void ANSOVSCRFDFD::PreprocessImage(cv::Mat& frame) {
|
|
try {
|
|
cv::resize(frame, resized_frame_, model_input_shape_, 0, 0, cv::INTER_AREA);
|
|
factor_.x = static_cast<float>(frame.cols / model_input_shape_.width);
|
|
factor_.y = static_cast<float>(frame.rows / model_input_shape_.height);
|
|
float* input_data = (float*)resized_frame_.data;
|
|
input_tensor_ = ov::Tensor(compiled_model_.input().get_element_type(), compiled_model_.input().get_shape(), input_data);
|
|
inference_request_.set_input_tensor(input_tensor_);
|
|
}
|
|
catch (const std::exception& e) {
|
|
std::cout << "ANSOVSCRFDFD::PreprocessImage. " << e.what() << std::endl;
|
|
}
|
|
catch (...) {
|
|
std::cout << "ANSOVSCRFDFD::PreprocessImage. " << "unknown exception" << std::endl;
|
|
}
|
|
}
|
|
std::vector<Object> ANSOVSCRFDFD::RunInference(const cv::Mat& input) {
|
|
std::vector<Object> outputs;
|
|
outputs.clear();
|
|
if (!_licenseValid) {
|
|
if (_modelLoading.load()) return {};
|
|
this->_logger.LogError("ANSOVSCRFDFD::RunInference", "Invalid license", __FILE__, __LINE__);
|
|
return outputs;
|
|
}
|
|
if (!_isInitialized) {
|
|
this->_logger.LogError("ANSOVSCRFDFD::RunInference", "Model is not initialized", __FILE__, __LINE__);
|
|
return outputs;
|
|
}
|
|
try {
|
|
bool croppedFace = false; // Check if the image is cropped face image
|
|
cv::Mat im = input.clone();
|
|
//std::cout << "Width x Height=" << input.size[0] << "x" << input.size[1] << std::endl;
|
|
// We know that the image sizes <=300 px, it is likely that image is cropped for face only
|
|
if ((input.size[0] <= 300) || (input.size[1] <= 300)) croppedFace = true;
|
|
if (croppedFace) cv::copyMakeBorder(input, im, 200, 200, 200, 200, cv::BORDER_REPLICATE);
|
|
|
|
this->PreprocessImage(im);
|
|
|
|
// Perform inference
|
|
inference_request_.infer();
|
|
|
|
|
|
std::cout << "Model outputs:" << std::endl;
|
|
auto ovOutputs= compiled_model_.outputs();
|
|
for (int i = 0; i < ovOutputs.size();i++) {
|
|
auto output_tensor = inference_request_.get_output_tensor(i);
|
|
std::cout << "Output Tensor for " << ovOutputs[i].get_any_name() << " obtained." << std::endl;
|
|
}
|
|
|
|
auto scores_tensor = inference_request_.get_output_tensor(1);
|
|
auto scores_shape = scores_tensor.get_shape();
|
|
|
|
// Access the data from the tensor
|
|
float* scores_data = scores_tensor.data<float>();
|
|
int num_detections = scores_shape[2]; // Should be 800
|
|
|
|
// Define a confidence threshold
|
|
float confidence_threshold = 0.1;
|
|
|
|
// Collecting indices of valid detections
|
|
std::vector<int> valid_detections;
|
|
for (int i = 0; i < num_detections; i++) {
|
|
float score = scores_data[i];
|
|
/* std::cout << "score [" << i << "]=" << score << std:: endl;*/
|
|
if (score > confidence_threshold) {
|
|
valid_detections.push_back(i);
|
|
//std::cout << "Detection " << i << " is valid with a score of " << score << std::endl;
|
|
}
|
|
}
|
|
|
|
std::cout << "Total valid detections: " << valid_detections.size() << std::endl;
|
|
|
|
|
|
/* float* score = inference_request_.get_output_tensor(2).data<float>();
|
|
//if (score != nullptr) {
|
|
// std::cout << "Score:" << score[0]<<std::endl;
|
|
//}
|
|
float* bbox = inference_request_.get_output_tensor(5).data<float>();*/
|
|
// Get the output tensor
|
|
|
|
|
|
//// Step 0: Prepare input
|
|
//this->PreprocessImage(im);
|
|
|
|
////Synchronous mode
|
|
//inference_request_.infer();
|
|
//std::vector<Object> output = PostProcessing();
|
|
|
|
|
|
//if (res.size() > 0)
|
|
//{
|
|
// // Peform face alignment
|
|
// //std::vector<cv::Mat> detectedFaces =fastdeploy::vision::utils::AlignFaceWithFivePoints(im, res);
|
|
// std::vector<cv::Mat> detectedFaces = ANSUtilityHelper::AlignFaceWithFivePoints(im, res.boxes, res.landmarks);
|
|
// if (res.size() == detectedFaces.size())
|
|
// {
|
|
// for (int i = 0; i < res.boxes.size(); i++)
|
|
// {
|
|
// Object result;
|
|
// float confidence = res.scores[i];
|
|
// if (confidence > _modelConfig.detectionScoreThreshold)
|
|
// {
|
|
// int x_min = res.boxes[i][0];
|
|
// int y_min = res.boxes[i][1];
|
|
// int x_max = res.boxes[i][2];
|
|
// int y_max = res.boxes[i][3];
|
|
// result.classId = 0;
|
|
// result.className = "Face";
|
|
// result.confidence = confidence;
|
|
// result.box.x = x_min;
|
|
// result.box.y = y_min;
|
|
// if (croppedFace) {
|
|
// if (x_min <= 200) x_min = 200;
|
|
// if (y_min <= 200) y_min = 200;
|
|
// result.box.x = x_min - 200;
|
|
// result.box.y = y_min - 200;
|
|
// }
|
|
// result.box.width = x_max - x_min;
|
|
// result.box.height = y_max - y_min;
|
|
// result.mask = detectedFaces.at(i).clone();
|
|
// output.push_back(result);
|
|
// }
|
|
// }
|
|
// }
|
|
// //detectedFaces.clear();
|
|
//}
|
|
im.release();
|
|
return outputs;
|
|
}
|
|
catch (std::exception& e) {
|
|
this->_logger.LogFatal("ANSOVSCRFDFD::RunInference", e.what(), __FILE__, __LINE__);
|
|
return outputs;
|
|
}
|
|
}
|
|
|
|
ANSOVSCRFDFD::~ANSOVSCRFDFD() {
|
|
try {
|
|
}
|
|
catch (std::exception& e) {
|
|
this->_logger.LogFatal("ANSOVSCRFDFD::Destroy", e.what(), __FILE__, __LINE__);
|
|
}
|
|
}
|
|
bool ANSOVSCRFDFD::Destroy() {
|
|
return true;
|
|
}
|
|
} |