retinaface submit

This commit is contained in:
吴镇
2022-11-14 07:40:38 +08:00
parent 5423f976c4
commit 0384e6838c
11 changed files with 996 additions and 0 deletions

40
Retinaface/CMakeLists.txt Normal file
View File

@@ -0,0 +1,40 @@
cmake_minimum_required(VERSION 3.10)
project(retinaface)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
include_directories(./RetinafacePostProcess)
include_directories(./RetinafaceDetection)
include_directories(/usr/local/Ascend/ascend-toolkit/latest/arm64-linux/runtime/include/)
file(GLOB_RECURSE Retinaface_POSTPROCESS ${PROJECT_SOURCE_DIR}/RetinafacePostProcess/*cpp)
file(GLOB_RECURSE Retinaface_DETECTION ${PROJECT_SOURCE_DIR}/RetinafaceDetection/*cpp)
set(TARGET retinaface)
add_compile_options(-std=c++11 -fPIE -fstack-protector-all -fPIC -Wl,-z,relro,-z,now,-z,noexecstack -s -pie -Wall)
add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0 -Dgoogle=mindxsdk_private)
set(MX_SDK_HOME "$ENV{MX_SDK_HOME}")
include_directories(
${MX_SDK_HOME}/include
${MX_SDK_HOME}/opensource/include
${MX_SDK_HOME}/opensource/include/opencv4
${MX_SDK_HOME}/include/MxBase/postprocess/include
/usr/local/Ascend/ascend-toolkit/latest/include
)
link_directories(
${MX_SDK_HOME}/lib
${MX_SDK_HOME}/opensource/lib
${MX_SDK_HOME}/lib/modelpostprocessors
/usr/local/Ascend/ascend-toolkit/latest/acllib/lib64
/usr/local/Ascend/driver/lib64/
)
add_executable(retinaface main.cpp ${Retinaface_DETECTION} ${Retinaface_POSTPROCESS})
target_link_libraries(retinaface
glog
mxbase
cpprest
opencv_world
boost_filesystem
)

177
Retinaface/README.md Normal file
View File

@@ -0,0 +1,177 @@
## Retinaface目标检测
## 1 介绍
本开发样例是基于mxBase开发的端到端推理的C++应用程序,可在昇腾芯片上进行 Retinaface目标检测并把可视化结果保存到本地。其中包含Retinaface的后处理模块开发。
### 1.1 支持的产品
本产品以昇腾310推理卡为硬件平台。
### 1.2 支持的版本
该项目支持的SDK版本为2.0.4CANN版本为5.0.4。
### 1.3 软件方案介绍
表1.1 系统方案各子系统功能描述:
| 序号 | 子系统 | 功能描述 |
| ---- | -------------- | ------------------------------------------------------------ |
| 1 | 图片输入 | 接收外部调用接口的输入视频路径对视频进行拉流并将拉去的裸流存储到缓冲区buffer并发送到下游插件。 |
| 2 | 模型推理插件 | 目标检测。 |
| 3 | 模型后处理插件 | 对模型输出的张量进行后处理,得到物体类型数据。 |
### 1.4 代码目录结构与说明
本项目名为Retinaface目标检测项目目录如下所示
````
.
├── build.sh
├── config
│   ├── aipp.cfg
├── CMakeLists.txt
├── main.cpp
├── models
│   ├── newRetinaface.om
│   └── run.sh
├── README.md
├── RetinafaceDetection
│   ├── RetinafaceDetection.cpp
│   └── RetinafaceDetection.h
├── RetinafacePostProcess
│   ├── RetinafacePostProcess.cpp
│   └── RetinafacePostProcess.h
````
### 1.5 技术实现流程图
![流程图](images/process.png)
### 1.6 特性及适用场景
本项目根据widerface数据集训练得到适用于人脸检测并且将人脸位置与五官位置标出。
适用于测试图片中有人脸的情况。若测试图片中没有人脸则无法运行
## 2 环境依赖
推荐系统为ubuntu 18.04,环境软件和版本如下:
| 软件名称 | 版本 | 说明 | 获取方式 |
| ------------------- | ----- | ----------------------------- | :-------------------------------------------------------- |
| MindX SDK | 2.0.4 | mxVision软件包 | [链接](https://www.hiascend.com/software/Mindx-sdk) |
| ubuntu | 18.04 | 操作系统 | 请上ubuntu官网获取 |
| Ascend-CANN-toolkit | 5.0.4 | Ascend-cann-toolkit开发套件包 | [链接](https://www.hiascend.com/software/cann/commercial) |
在编译运行项目前,需要设置环境变量:
MindSDK 环境变量:
```
. ${SDK-path}/set_env.sh
```
CANN 环境变量:
```
. ${ascend-toolkit-path}/set_env.sh
```
- 环境变量介绍
```
SDK-path: SDK mxVision 安装路径
ascend-toolkit-path: CANN 安装路径
```
## 3 软件依赖说明
本项目无特定软件依赖。
## 4 模型转化
本项目中使用的模型是Retinaface模型onnx模型可以直接[下载](https://www.hiascend.com/zh/software/modelzoo/models/detail/1/7270b02a457d4c4ab262277a646517f9)。下载后解包,得到`Retinaface.onnx`使用模型转换工具ATC将onnx模型转换为om模型模型转换工具相关介绍参考[链接](https://support.huaweicloud.com/tg-cannApplicationDev330/atlasatc_16_0005.html)
模型转换步骤如下:
1、按照2环境依赖设置环境变量
2、`cd`到`model`文件夹,运行
````
bash run.sh
````
3、执行该命令后会在指定输出.om模型路径生成项目指定模型文件newRetinaface.om。若模型转换成功则输出
```
ATC start working now, please wait for a moment.
ATC run success, welcome to the next use.
```
aipp文件配置如下
```
aipp_op {
aipp_mode: static
input_format :RGB888_U8
src_image_size_w :1000
src_image_size_h :1000
mean_chn_0 :104
mean_chn_1 :117
mean_chn_2 :123
var_reci_chn_0 :1
var_reci_chn_1 :1
var_reci_chn_2 :1
}
```
## 5 编译运行
**步骤1** 修改`CMakeLists.txt`文件 将`set(MX_SDK_HOME ${SDK安装路径})` 中的`${SDK安装路径}`替换为实际的SDK安装路径
**步骤2** 按照**2环境依赖**设置环境变量。
**步骤3** 在项目主目录下执行如下编译命令:
````
bash build.sh
````
**步骤4** 制定jpg图片进行推理准备一张推理图片放入主目录下。eg:推理图片为test.jpg
```
./Retinaface ./test.jpg
```
得到`result.jpg`即为输出结果。
## 6 精度测试
本项目的所用模型和后处理插件编写都和https://gitee.com/bayf3/mindxsdk-referenceapps/tree/master/contrib/Retinaface地址处的一致。详细的精度测试请参考该代码。

View File

@@ -0,0 +1,283 @@
/*
* Copyright(C) 2021. Huawei Technologies 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 "RetinafaceDetection.h"
#include "MxBase/DeviceManager/DeviceManager.h"
#include "MxBase/Log/Log.h"
#include <unistd.h>
#include <sys/stat.h>
#include "boost/filesystem.hpp"
#include <boost/filesystem.hpp>
namespace fs = boost::filesystem;
using namespace MxBase;
namespace {
const uint32_t IMAGE_SIZE = 1000;
const int NETINPUTSIZE = 1000;
std::string imagePath;
int originImageW;
int originImageH;
float resize;
int padLeft;
int padRight;
int padTop;
int padBottom;
const uint32_t YUV_BYTE_NU = 3;
const uint32_t YUV_BYTE_DE = 2;
const uint32_t VPC_H_ALIGN = 2;
}
void RetinafaceDetection::SetRetinafacePostProcessConfig(const InitParam &initParam, std::map<std::string, std::shared_ptr<void>> &config)
{
MxBase::ConfigData configData;
const std::string checkTensor = initParam.checkTensor ? "true" : "false";
configData.SetJsonValue("CHECK_MODEL", checkTensor);
configData.SetJsonValue("CLASS_NUM", std::to_string(initParam.classNum));
auto jsonStr = configData.GetCfgJson().serialize();
config["postProcessConfigContent"] = std::make_shared<std::string>(jsonStr);
config["labelPath"] = std::make_shared<std::string>(initParam.labelPath);
}
APP_ERROR RetinafaceDetection::Init(const InitParam& initParam)
{
deviceId_ = initParam.deviceId;
APP_ERROR ret = MxBase::DeviceManager::GetInstance()->InitDevices();
if (ret != APP_ERR_OK) {
LogError << "Init devices failed, ret=" << ret << ".";
return ret;
}
ret = MxBase::TensorContext::GetInstance()->SetContext(initParam.deviceId);
if (ret != APP_ERR_OK) {
LogError << "Set context failed, ret=" << ret << ".";
return ret;
}
dvppWrapper_ = std::make_shared<MxBase::DvppWrapper>();
ret = dvppWrapper_->Init();
if (ret != APP_ERR_OK) {
LogError << "DvppWrapper init failed, ret=" << ret << ".";
return ret;
}
model_ = std::make_shared<MxBase::ModelInferenceProcessor>();
ret = model_->Init(initParam.modelPath, modelDesc_);
if (ret != APP_ERR_OK) {
LogError << "ModelInferenceProcessor init failed, ret=" << ret << ".";
return ret;
}
// init Retinafacepostprocess
std::map<std::string, std::shared_ptr<void>> config;
SetRetinafacePostProcessConfig(initParam, config);
post_ = std::make_shared<RetinafacePostProcess>();
cv::Mat originalImage = cv::imread(initParam.ImagePath);
ret = post_->Init(config, originalImage.rows, originalImage.cols);
if (ret != APP_ERR_OK) {
LogError << "Retinafacepostprocess init failed, ret = " << ret << ".";
return ret;
}
return APP_ERR_OK;
}
APP_ERROR RetinafaceDetection::DeInit() {
dvppWrapper_->DeInit();
model_->DeInit();
post_->DeInit();
MxBase::DeviceManager::GetInstance()->DestroyDevices();
return APP_ERR_OK;
}
// 获取图像数据将数据存入TensorBase中
APP_ERROR RetinafaceDetection::ReadImage(const std::string &imgPath, cv::Mat &imageMat) {
imageMat = cv::imread(imgPath, cv::IMREAD_COLOR);
return APP_ERR_OK;
}
APP_ERROR RetinafaceDetection::CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase)
{
const uint32_t dataSize = imageMat.cols * imageMat.rows * YUV444_RGB_WIDTH_NU;
LogInfo << "image size " << imageMat.cols << " " << imageMat.rows;
MemoryData memoryDataDst(dataSize, MemoryData::MEMORY_DEVICE, deviceId_);
MemoryData memoryDataSrc(imageMat.data, dataSize, MemoryData::MEMORY_HOST_MALLOC);
APP_ERROR ret = MemoryHelper::MxbsMallocAndCopy(memoryDataDst, memoryDataSrc);
if (ret != APP_ERR_OK) {
LogError << GetError(ret) << "Memory malloc failed.";
return ret;
}
std::vector<uint32_t> shape = {imageMat.rows * YUV444_RGB_WIDTH_NU, static_cast<uint32_t>(imageMat.cols)};
tensorBase = TensorBase(memoryDataDst, false, shape, TENSOR_DTYPE_UINT8);
return APP_ERR_OK;
}
// 模型推理
APP_ERROR RetinafaceDetection::Inference(const std::vector<MxBase::TensorBase>& inputs,
std::vector<MxBase::TensorBase>& outputs) {
auto dtypes = model_->GetOutputDataType();
for (size_t i = 0; i < modelDesc_.outputTensors.size(); ++i) {
std::vector<uint32_t> shape = {};
for (size_t j = 0; j < modelDesc_.outputTensors[i].tensorDims.size(); ++j) {
shape.push_back((uint32_t)modelDesc_.outputTensors[i].tensorDims[j]);
}
TensorBase tensor(shape, dtypes[i], MemoryData::MemoryType::MEMORY_DEVICE, deviceId_);
APP_ERROR ret = TensorBase::TensorBaseMalloc(tensor);
if (ret != APP_ERR_OK) {
LogError << "TensorBaseMalloc failed, ret=" << ret << ".";
return ret;
}
outputs.push_back(tensor);
}
// print the shape and type of inputs
std::cout << "inputs size = "<<inputs[0].GetSize() << "\n";
std::cout << "inputs GetByteSize = "<<inputs[0].GetByteSize() << "\n";
std::cout << "inputs number = "<< inputs.size() << "\n";
std::cout << "inputs shape size = "<< inputs[0].GetShape().size() << "\n";
std::cout << "Data type = "<< inputs[0].GetDataType() << "\n";
for (size_t i = 0; i<inputs[0].GetShape().size(); i++) {
std::cout << "value = ";
std::cout << inputs[0].GetShape()[i] << " ";
}
DynamicInfo dynamicInfo = {};
dynamicInfo.dynamicType = DynamicType::STATIC_BATCH;
LogInfo << "Ready to infer.";
APP_ERROR ret = model_->ModelInference(inputs, outputs, dynamicInfo);
if (ret != APP_ERR_OK) {
LogError << "ModelInference failed, ret=" << ret << ".";
return ret;
}
LogInfo << "End to model inference.";
return APP_ERR_OK;
}
// 后处理
APP_ERROR RetinafaceDetection::PostProcess(const std::vector<MxBase::TensorBase>& outputs,
std::vector<std::vector<MxBase::ObjectInfo>>& objInfos)
{
LogInfo << "start postprocess.\n";
APP_ERROR ret = post_->Process(outputs, objInfos);
if (ret != APP_ERR_OK) {
LogError << "Process failed, ret=" << ret << ".";
return ret;
}
ret = post_->DeInit();
if (ret != APP_ERR_OK) {
LogError << "RetinafacePostProcess DeInit failed";
return ret;
}
LogInfo << "End to Retinafacepostprocess.";
return APP_ERR_OK;
}
APP_ERROR RetinafaceDetection::WriteResult(const std::string& imgPath,
const std::vector<std::vector<MxBase::ObjectInfo>>& objInfos)
{
LogInfo << "start write result.";
cv::Mat writeImage = cv::imread(imagePath);
uint32_t objInfosSize = objInfos.size();
std::vector<MxBase::ObjectInfo> resultInfo;
std::cout << "objInfo number = " << objInfosSize << std::endl;
for (uint32_t i = 0; i<objInfosSize; i++) {
for (uint32_t j = 0; j<objInfos[i].size(); j++) {
resultInfo.push_back(objInfos[i][j]);
}
LogInfo << "result box number is : " << resultInfo.size();
for (uint32_t j = 0; j<resultInfo.size(); j++) {
/* 打印后处理之后的所有结果 */
// std::cout << "resultInfo[j].x0 = " << resultInfo[j].x0 << ", " << "resultInfo[j].x1 = " << resultInfo[j].x1 << ", " << ""
const uint32_t thickness = 2;
const cv::Scalar black = cv::Scalar(0, 0, 0);
int X0 = std::max((int)((resultInfo[j].x0 - padLeft) / resize), 0);
int X1 = std::max((int)((resultInfo[j].x1 - padLeft) / resize), 0);
int Y0 = std::max((int)((resultInfo[j].y0 - padTop) / resize), 0);
int Y1 = std::max((int)((resultInfo[j].y1 - padTop) / resize), 0);
cv::Point2i c1(X0, Y0);
cv::Point2i c2(X1, Y1);
cv::rectangle(writeImage, cv::Rect(X0, Y0, X1-X0, Y1-Y0), black, thickness);
}
}
cv::imwrite("./result.jpg", writeImage);
return APP_ERR_OK;
}
APP_ERROR RetinafaceDetection::Process(const std::string& imgPath) {
imagePath = imgPath;
cv::Mat originImage = cv::imread(imgPath);
if (originImage.data == NULL) {
LogInfo << "The image is not exist.\n";
return 0;
}
originImageW = originImage.cols;
originImageH = originImage.rows;
int imgsizeMax = originImageW;
if (imgsizeMax < originImageH) {
imgsizeMax = originImageH;
}
resize = (IMAGE_SIZE * 1.0 ) / (imgsizeMax * 1.0);
cv::Mat newImg;
cv::resize(originImage, newImg, cv::Size(), resize, resize, cv::INTER_NEAREST);
padRight = IMAGE_SIZE - newImg.cols;
padLeft = 0;
padBottom = IMAGE_SIZE - newImg.rows;
padTop = 0;
cv::Mat nnImage;
cv::copyMakeBorder(newImg, nnImage, padTop, padBottom, padLeft, padRight,
cv::BORDER_CONSTANT, 0);
std::cout<< "nnImage W = " << nnImage.cols << " " << "nnImage H = " << nnImage.rows << "\n";
std::string newImagePath = "./ImageforInfer.jpg";
cv::imwrite(newImagePath, nnImage);
cv::Mat imageMat;
APP_ERROR ret = ReadImage(newImagePath, imageMat);
if (ret != APP_ERR_OK) {
LogError << "ReadImage failed, ret=" << ret << ".";
return ret;
}
std::vector<MxBase::TensorBase> inputs = {};
std::vector<MxBase::TensorBase> outputs = {};
TensorBase tensorBase;
ret = CVMatToTensorBase(imageMat, tensorBase);
if (ret != APP_ERR_OK) {
LogError << "CVMatToTensorBase failed, ret=" << ret << ".";
return ret;
}
inputs.push_back(tensorBase);
ret = Inference(inputs, outputs);
if (ret != APP_ERR_OK) {
LogError << "Inference failed, ret=" << ret << ".";
return ret;
}
std::vector<std::vector<MxBase::ObjectInfo>> objInfos;
std::cout << std::endl;
std::cout << "outputSize = " << outputs.size() << std::endl;
for (uint32_t i = 0; i<outputs.size(); i++) {
for (uint32_t j = 0; j<outputs[i].GetShape().size(); j++) {
std::printf("outputs[%d][%d] = %d. ", i, j, outputs[i].GetShape()[j]);
}
std::cout << std::endl;
}
ret = PostProcess(outputs, objInfos);
if (ret != APP_ERR_OK) {
LogError << "PostProcess failed, ret=" << ret << ".";
return ret;
}
ret = WriteResult(imgPath, objInfos);
if (ret != APP_ERR_OK) {
LogError << "Save result failed, ret=" << ret << ".";
return ret;
}
return APP_ERR_OK;
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright(C) 2021. Huawei Technologies 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 MXBASE_RetinafaceDETECTION_H
#define MXBASE_RetinafaceDETECTION_H
#include <RetinafacePostProcess.h>
#include "MxBase/DvppWrapper/DvppWrapper.h"
#include "MxBase/ModelInfer/ModelInferenceProcessor.h"
#include "MxBase/Tensor/TensorContext/TensorContext.h"
struct InitParam {
uint32_t deviceId;
bool checkTensor;
std::string modelPath;
std::string labelPath;
uint32_t classNum;
std::string ImagePath;
};
class RetinafaceDetection {
public:
APP_ERROR Init(const InitParam& initParam);
APP_ERROR DeInit();
APP_ERROR Inference(const std::vector<MxBase::TensorBase>& inputs, std::vector<MxBase::TensorBase>& outputs);
APP_ERROR PostProcess(const std::vector<MxBase::TensorBase>& outputs, std::vector<std::vector<MxBase::ObjectInfo>>& objInfos);
APP_ERROR CVMatToTensorBase(const cv::Mat &imageMat, MxBase::TensorBase &tensorBase);
APP_ERROR Process(const std::string& imgPath);
APP_ERROR ReadImage(const std::string &imgPath, cv::Mat &imageMat);
APP_ERROR WriteResult(const std::string& imgPath,
const std::vector<std::vector<MxBase::ObjectInfo>>& objInfos);
void SetRetinafacePostProcessConfig(
const InitParam &initParam,
std::map<std::string, std::shared_ptr<void>> &config
);
private:
std::shared_ptr<MxBase::DvppWrapper> dvppWrapper_;
std::shared_ptr<MxBase::ModelInferenceProcessor> model_;
std::shared_ptr<RetinafacePostProcess> post_;
MxBase::ModelDesc modelDesc_;
uint32_t deviceId_ = 0;
};
#endif

View File

@@ -0,0 +1,271 @@
/*
* Copyright(C) 2021. Huawei Technologies 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 "RetinafacePostProcess.h"
#include "MxBase/Log/Log.h"
#include "MxBase/Maths/FastMath.h"
#include "MxBase/CV/ObjectDetection/Nms/Nms.h"
#include <map>
namespace {
const uint32_t LEFTTOPX = 0;
const uint32_t LEFTTOPY = 1;
const uint32_t RIGHTTOPX = 2;
const uint32_t RIGHTTOPY = 3;
const int PRIOR_PARAMETERS[3][2] = {{16, 32}, {64, 128}, {256, 512}};
const int PRIOR_PARAMETERS_COUNT = 2;
const float IMAGE_WIDTH = 1000.0;
const float IMAGE_HEIGHT = 1000.0;
const float STEPS[3] = {8.0, 16.0, 32.0};
const float VARIANCE[2] = {0.1, 0.2};
const uint32_t RECTANGLEPOINT = 4;
const uint32_t KEYPOINTNUM = 5;
const uint32_t POINT_SIZE = 1;
const uint32_t DIM = 2;
const uint32_t RECTANGLE_COLOR = 1;
const uint32_t KEYPOINT_COLOR = 2;
const uint32_t DIV_TWO = 2;
uint32_t ORIGIALWIDE;
uint32_t ORIGINALHEIGHT;
}
using namespace MxBase;
RetinafacePostProcess& RetinafacePostProcess::operator=(const RetinafacePostProcess& other) {
if (this == &other) {
return *this;
}
ObjectPostProcessBase::operator=(other);
return *this;
}
APP_ERROR RetinafacePostProcess::Init(const std::map<std::string, std::shared_ptr<void>>& postConfig, const int& OriginWide, const int& OriginHeight) {
LogDebug << "Start to Init RetinafacePostProcess.";
ORIGIALWIDE = OriginWide;
ORIGINALHEIGHT = OriginHeight;
APP_ERROR ret = ObjectPostProcessBase::Init(postConfig);
if (ret != APP_ERR_OK) {
LogError << GetError(ret) << "Fail to superInit in ObjectPostProcessBase.";
return ret;
}
LogInfo << "End to Init RetinafacePostprocess.";
return APP_ERR_OK;
}
APP_ERROR RetinafacePostProcess::DeInit() {
return APP_ERR_OK;
}
void RetinafacePostProcess::ObjectDetectionOutput(const std::vector <TensorBase>& tensors,
std::vector <std::vector<ObjectInfo>>& objectInfos,
const std::vector <ResizedImageInfo>& resizedImageInfos)
{
LogInfo << "RetinafacePostProcess start to write results.";
std::cout << "\n";
std::cout << "tensorsSize =" << tensors.size() << "\n";
for (uint32_t i = 0; i<tensors.size(); i++) {
for (uint32_t j = 0; j<tensors[i].GetShape().size(); j++) {
std::printf("tensors[%d][%d] = %d .", i, j, tensors[i].GetShape()[j]);
}
std::cout << std::endl;
}
for (auto num : { objectInfoTensor_, objectConfTensor_ }) {
if ((num >= tensors.size()) || (num < 0)) {
LogError << GetError(APP_ERR_INVALID_PARAM) << "TENSOR(" << num
<< ") must ben less than tensors'size(" << tensors.size() << ") and larger than 0.";
}
}
auto shape = tensors[0].GetShape();
auto keyshape = tensors[2].GetShape();
cv::Mat PriorBox;
cv::Mat location = cv::Mat(shape[1], shape[2], CV_32FC1, tensors[0].GetBuffer());
cv::Mat keylocation = cv::Mat(keyshape[1], keyshape[2], CV_32FC1, tensors[2].GetBuffer());
GeneratePriorBox(PriorBox);
float width_resize = 1000;
float height_resize = 1000;
float width_original = 1000;
float height_original = 1000;
float width_resize_scale = width_resize / (width_original * 1.0);
float height_resize_scale = height_resize / (height_original * 1.0);
float resize_scale_factor = 1.0;
if (width_resize_scale >= height_resize_scale) {
resize_scale_factor = height_resize_scale;
} else {
resize_scale_factor = width_resize_scale;
}
cv::Mat res = decode_for_loc(location, PriorBox, keylocation, resize_scale_factor);
uint32_t batchSize = shape[0];
uint32_t VectorNum = shape[1];
std::map<ObjectInfo, KeyPointDetectionInfo> match;
for (uint32_t i = 0; i < batchSize; i++) {
std::vector <ObjectInfo> objectInfo;
std::vector <ObjectInfo> objectInfoSorted;
std::vector <KeyPointDetectionInfo> keypointInfo;
std::vector <KeyPointDetectionInfo> keypointInfoSorted;
auto dataPtr_Conf = (float *) tensors[1].GetBuffer() + i * tensors[1].GetByteSize() / batchSize;
for (uint32_t j = 0; j < VectorNum; j++) {
float* begin_Conf = dataPtr_Conf + j * 2;
float conf = *(begin_Conf + 1);
if (conf > confThresh_) {
ObjectInfo objInfo;
objInfo.confidence = j;
objInfo.x0 = res.at<float>(j, LEFTTOPX) * IMAGE_WIDTH / width_resize_scale;
objInfo.y0 = res.at<float>(j, LEFTTOPY) * IMAGE_HEIGHT / height_resize_scale;
objInfo.x1 = res.at<float>(j, RIGHTTOPX) * IMAGE_WIDTH / width_resize_scale;
objInfo.y1 = res.at<float>(j, RIGHTTOPY) * IMAGE_HEIGHT / height_resize_scale;
objInfo.classId = RECTANGLE_COLOR;
objectInfo.push_back(objInfo);
}
}
MxBase::NmsSort(objectInfo, iouThresh_);
for (uint32_t j = 0; j < objectInfo.size(); j++) {
ObjectInfo obj = objectInfo[j];
KeyPointDetectionInfo kpInfo;
int keypoint_Pos = objectInfo[j].confidence;
float* begin_Conf = dataPtr_Conf + keypoint_Pos * 2;
float conf = *(begin_Conf + 1);
objectInfo[j].confidence = conf;
objectInfoSorted.push_back(objectInfo[j]);
for (uint32_t k = 0; k < KEYPOINTNUM; k++)
{
float x = res.at<float>(keypoint_Pos, RECTANGLEPOINT + k * DIM) * IMAGE_WIDTH / width_resize_scale;
float y = res.at<float>(keypoint_Pos, RECTANGLEPOINT + k * DIM + 1) * IMAGE_HEIGHT / height_resize_scale;
ObjectInfo objInfo;
objInfo.x0= x - POINT_SIZE;
objInfo.x1= x + POINT_SIZE;
objInfo.y0= y - POINT_SIZE;
objInfo.y1= y + POINT_SIZE;
objInfo.confidence = 0;
objInfo.classId = KEYPOINT_COLOR;
objectInfoSorted.push_back(objInfo);
}
}
objectInfos.push_back(objectInfoSorted);
}
LogInfo << "Retinaface write results successed.";
}
APP_ERROR RetinafacePostProcess::Process(const std::vector<TensorBase>& tensors,
std::vector<std::vector<ObjectInfo>>& objectInfos,
const std::vector<ResizedImageInfo>& resizedImageInfos,
const std::map<std::string, std::shared_ptr<void>>& configParamMap)
{
LogInfo << "Start to Process RetinafacePostProcess.";
APP_ERROR ret = APP_ERR_OK;
auto inputs = tensors;
ret = CheckAndMoveTensors(inputs);
if (ret != APP_ERR_OK) {
LogError << "CheckAndMoveTensors failed. ret=" << ret;
return ret;
}
ObjectDetectionOutput(inputs, objectInfos, resizedImageInfos);
LogInfo << "End to Process RetinafacePostProcess.";
return APP_ERR_OK;
}
void RetinafacePostProcess::GeneratePriorBox(cv::Mat& anchors)
{
std::vector<std::vector<int>>feature_maps(RIGHTTOPY, std::vector<int>(DIM));
for (uint32_t i = 0; i < feature_maps.size(); i++) {
feature_maps[i][0] = ceil(IMAGE_HEIGHT / STEPS[i]);
feature_maps[i][1] = ceil(IMAGE_WIDTH / STEPS[i]);
}
for (uint32_t k = 0; k < feature_maps.size(); k++) {
auto f = feature_maps[k];
float step = (float)STEPS[k];
for (int i = 0; i < f[0]; i++) {
for (int j = 0; j < f[1]; j++) {
for (int l = 0; l < PRIOR_PARAMETERS_COUNT && PRIOR_PARAMETERS[k][l] != -1; l++) {
float min_size = PRIOR_PARAMETERS[k][l];
cv::Mat anchor(1, RECTANGLEPOINT * DIM, CV_32F);
float center_x = (j + 0.5f) * step;
float center_y = (i + 0.5f) * step;
float xmin = (center_x - min_size / 2.f) / IMAGE_WIDTH;
float ymin = (center_y - min_size / 2.f) / IMAGE_HEIGHT;
float xmax = (center_x + min_size / 2.f) / IMAGE_WIDTH;
float ymax = (center_y + min_size / 2.f) / IMAGE_HEIGHT;
float prior_width = xmax - xmin;
float prior_height = ymax - ymin;
float prior_center_x = (xmin + xmax) / 2;
float prior_center_y = (ymin + ymax) / 2;
anchor.at<float>(0, LEFTTOPX) = center_x / IMAGE_WIDTH;
anchor.at<float>(0, LEFTTOPY) = center_y / IMAGE_HEIGHT;
anchor.at<float>(0, RIGHTTOPX) = min_size / IMAGE_WIDTH;
anchor.at<float>(0, RIGHTTOPY) = min_size / IMAGE_HEIGHT;
anchor.at<float>(0, LEFTTOPX + RECTANGLEPOINT) = prior_width;
anchor.at<float>(0, LEFTTOPY + RECTANGLEPOINT) = prior_height;
anchor.at<float>(0, RIGHTTOPX + RECTANGLEPOINT) = prior_center_x;
anchor.at<float>(0, RIGHTTOPY + RECTANGLEPOINT) = prior_center_y;
anchors.push_back(anchor);
}
}
}
}
}
cv::Mat RetinafacePostProcess::decode_for_loc(cv::Mat& loc, cv::Mat& prior, cv::Mat& key, float resize_scale_factor) {
LogInfo << loc.rows;
LogInfo << loc.cols;
LogInfo << prior.rows;
LogInfo << prior.cols;
LogInfo << key.rows;
LogInfo << key.cols;
cv::Mat loc_first = loc.colRange(0, 2);
cv::Mat loc_last = loc.colRange(2, 4);
cv::Mat prior_first = prior.colRange(0, 2);
cv::Mat prior_last = prior.colRange(2, 4);
cv::Mat prior_first2 = prior.colRange(4, 6);
cv::Mat prior_last2 = prior.colRange(6, 8);
cv::Mat facepoint = key.colRange(0, 10);
cv::Mat boxes1 = prior_first + (loc_first * VARIANCE[0]).mul(prior_last);
cv::Mat boxes2;
cv::exp(loc_last * VARIANCE[1], boxes2);
boxes2 = boxes2.mul(prior_last);
boxes1 = boxes1 - boxes2 / DIV_TWO;
boxes2 = boxes2 + boxes1;
cv::Mat boxes3;
for (uint32_t i = 0; i < KEYPOINTNUM; i++)
{
cv::Mat singlepoint = facepoint.colRange(i * 2, (i + 1) * 2);
singlepoint = prior_last2 + (singlepoint * VARIANCE[0]).mul(prior_first2);
if (i == 0) boxes3 = singlepoint;
else cv::hconcat(boxes3, singlepoint, boxes3);
}
cv::Mat boxes;
cv::hconcat(boxes1, boxes2, boxes);
cv::hconcat(boxes, boxes3, boxes);
if (resize_scale_factor == 0) {
LogError << "resize_scale_factor is 0.";
}
return boxes;
}

View File

@@ -0,0 +1,58 @@
/*
* Copyright(C) 2021. Huawei Technologies 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 Retinaface_POST_PROCESS_H
#define Retinaface_POST_PROCESS_H
#include "MxBase/PostProcessBases/ObjectPostProcessBase.h"
#include "MxBase/CV/ObjectDetection/Nms/Nms.h"
#include "opencv2/opencv.hpp"
#define DEFAULT_OBJECT_CONF_TENSOR 1
#define DEFAULT_OBJECT_INFO_TENSOR 0
#define DEFAULT_IOU_THRESH 0.4
#define DEFAULT_CONFIDENCE_THRESH 0.40
class RetinafacePostProcess : public MxBase::ObjectPostProcessBase {
public:
RetinafacePostProcess() = default;
~RetinafacePostProcess() = default;
RetinafacePostProcess(const RetinafacePostProcess& other);
RetinafacePostProcess& operator=(const RetinafacePostProcess& other);
APP_ERROR Init(const std::map<std::string, std::shared_ptr<void>>& postConfig, const int& OriginWide, const int& OriginHeight);
APP_ERROR DeInit() override;
APP_ERROR Process(const std::vector<MxBase::TensorBase>& tensors, std::vector<std::vector<MxBase::ObjectInfo>>& objectInfos,
const std::vector<MxBase::ResizedImageInfo>& resizedImageInfos = {},
const std::map<std::string, std::shared_ptr<void>>& paramMap = {}) override;
protected:
void ObjectDetectionOutput(const std::vector<MxBase::TensorBase>& tensors,
std::vector<std::vector<MxBase::ObjectInfo>>& objectInfos,
const std::vector<MxBase::ResizedImageInfo>& resizedImageInfos = {});
void GeneratePriorBox(cv::Mat& anchors);
cv::Mat decode_for_loc(cv::Mat& loc, cv::Mat& prior, cv::Mat& key, float resize_scale_factor);
private:
uint32_t objectConfTensor_ = DEFAULT_OBJECT_CONF_TENSOR;
uint32_t objectInfoTensor_ = DEFAULT_OBJECT_INFO_TENSOR;
float iouThresh_ = DEFAULT_IOU_THRESH;
float confThresh_ = DEFAULT_CONFIDENCE_THRESH;
};
#endif

35
Retinaface/build.sh Normal file
View File

@@ -0,0 +1,35 @@
#!/bin/bash
# Copyright(C) 2021. Huawei Technologies 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.
path_cur="$(dirname "$0")"
function build_retinaface()
{
cd "$path_cur" || exit
rm -rf build
mkdir -p build
cd build || exit
cmake ..
make
ret=$?
if [ ${ret} -ne 0 ]; then
echo "Failed to build retinaface."
exit ${ret}
fi
make install
}
build_retinaface

View File

@@ -0,0 +1,15 @@
aipp_op {
aipp_mode: static
input_format :RGB888_U8
src_image_size_w :1000
src_image_size_h :1000
mean_chn_0 :104
mean_chn_1 :117
mean_chn_2 :123
var_reci_chn_0 :1
var_reci_chn_1 :1
var_reci_chn_2 :1
}

0
Retinaface/images/.keep Normal file
View File

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

60
Retinaface/main.cpp Normal file
View File

@@ -0,0 +1,60 @@
/*
* Copyright(C) 2021. Huawei Technologies 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 <vector>
#include <RetinafaceDetection.h>
#include "MxBase/Log/Log.h"
std::string imgPath;
void InitRetinafaceParam(InitParam& initParam)
{
initParam.deviceId = 0;
initParam.checkTensor = true;
initParam.modelPath = "./model/newRetinaface.om";
initParam.classNum = 1;
initParam.labelPath = "";
initParam.ImagePath = imgPath;
}
int main(int argc, char* argv[])
{
if (argc <= 1) {
LogWarn << "Please input image path, such as './RetinafacePostProcess test.jpg'.";
return APP_ERR_OK;
}
imgPath = argv[1];
InitParam initParam;
InitRetinafaceParam(initParam);
auto Retinaface = std::make_shared<RetinafaceDetection>();
APP_ERROR ret = Retinaface->Init(initParam);
if (ret != APP_ERR_OK) {
LogError << "RetinafaceDetection init failed, ret=" << ret << ".";
return ret;
}
ret = Retinaface->Process(imgPath);
if (ret != APP_ERR_OK) {
LogError << "RetinafaceDetection process failed, ret=" << ret << ".";
Retinaface->DeInit();
return ret;
}
Retinaface->DeInit();
return APP_ERR_OK;
}