From 0ecd6ae825d10bbef020de99a91d3ac4e87a15cd Mon Sep 17 00:00:00 2001 From: lihaowei Date: Mon, 14 Nov 2022 16:09:11 +0800 Subject: [PATCH 1/9] add Retinaface --- contrib/Retinaface/README.md | 238 +++++++++++++++ contrib/Retinaface/build.sh | 37 +++ contrib/Retinaface/config/aipp.cfg | 15 + contrib/Retinaface/config/face_Retina.cfg | 4 + contrib/Retinaface/images/process.png | Bin 0 -> 32124 bytes contrib/Retinaface/main.py | 142 +++++++++ contrib/Retinaface/model/run.sh | 18 ++ contrib/Retinaface/plugin/CMakeLists.txt | 31 ++ .../plugin/TotalYunetPostProcess.cpp | 283 ++++++++++++++++++ .../Retinaface/plugin/TotalYunetPostProcess.h | 67 +++++ contrib/Retinaface/plugin/build.sh | 36 +++ contrib/Retinaface/run.sh | 33 ++ contrib/Retinaface/test.py | 139 +++++++++ contrib/Retinaface/utils.py | 129 ++++++++ 14 files changed, 1172 insertions(+) create mode 100644 contrib/Retinaface/README.md create mode 100644 contrib/Retinaface/build.sh create mode 100644 contrib/Retinaface/config/aipp.cfg create mode 100644 contrib/Retinaface/config/face_Retina.cfg create mode 100644 contrib/Retinaface/images/process.png create mode 100644 contrib/Retinaface/main.py create mode 100644 contrib/Retinaface/model/run.sh create mode 100644 contrib/Retinaface/plugin/CMakeLists.txt create mode 100644 contrib/Retinaface/plugin/TotalYunetPostProcess.cpp create mode 100644 contrib/Retinaface/plugin/TotalYunetPostProcess.h create mode 100644 contrib/Retinaface/plugin/build.sh create mode 100644 contrib/Retinaface/run.sh create mode 100644 contrib/Retinaface/test.py create mode 100644 contrib/Retinaface/utils.py diff --git a/contrib/Retinaface/README.md b/contrib/Retinaface/README.md new file mode 100644 index 000000000..e46390a4e --- /dev/null +++ b/contrib/Retinaface/README.md @@ -0,0 +1,238 @@ +## Retinaface目标检测 + +## 1介绍 + +Retinaface基于MindX_SDK开发,在昇腾芯片上进行目标检测,并实现可视化呈现。输入单张图片,对其进行推理,输出推理结果。 + +### 1.1 支持的产品 + +本产品以昇腾310(推理)卡为硬件平台。 + +### 1.2 支持的版本 + +该项目支持的SDK版本为2.0.4,CANN版本为5.0.4。 + +### 1.3 软件方案介绍 + +表1.1 系统方案各子系统功能描述: + +| 序号 | 子系统 | 功能描述 | +| ---- | -------------- | ------------------------------------------------------------ | +| 1 | 图片输入 | 接收外部调用接口的输入视频路径,对视频进行拉流,并将拉去的裸流存储到缓冲区(buffer)中,并发送到下游插件。 | +| 2 | 模型推理插件 | 目标检测。 | +| 3 | 模型后处理插件 | 对模型输出的张量进行后处理,得到物体类型数据。 | + + + +### 1.4 代码目录结构与说明 + +本项目名为Retinaface目标检测,项目目录如下所示: + +```` +. +├── build.sh +├── run.sh +├── config +│   └── aipp.cfg +│ ├── face_Retina.cfg +├── main.py +├── test.py +├── utils.py +├── model +│   └── run.sh +├── plugin +│   └── build.sh +│   ├── CMakeLists.txt +│   ├── TotalYunetPostProcess.cpp +│   └── TotalYunetPostProcess.h +├── README.md +```` + + + +### 1.5 技术实现流程图 + +![流程图](images/process.png) + + + +### 1.6 特性及适用场景 + +本项目根据widerface数据集训练得到,适用于人脸检测,并且将人脸位置与五官位置标出。 + +本项目在绝大多数情况下准确,但是存在以下检测异常的情况: +1.正常检测中,由于模型本身的限制,会出现部分物体检测不到/检测错误; +2.图片中无检测目标时,会出现可视化异常,输出结果无图片信息 + + + + +## 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: mxVision SDK 安装路径 +ascend-toolkit-path: CANN 安装路径。 +``` + +## 3 软件依赖说明 + +本项目无特定软件依赖。 + +## 4.推理文件准备 +进入项目根目录,执行以下命令,创建所需文件夹: +``` +mkdir include +mkdir -p evaluate/widerface_txt/ +``` +下载本模型论文官方源码,可通过git clone下载: +``` +git clone https://github.com/biubug6/Pytorch_Retinaface.git +``` +或者直接下载zip代码包解压。 + +1、准备include目录中的文件 + +* 将Pytorch_Retinaface项目中的 + * Pytorch_Retinaface/layers/functions/prior_box.py + * Pytorch_Retinaface/utils/box_utils.py + * Pytorch_Retinaface/utils/nms/py_cpu_nms.py + + 放入本项目include文件夹下。 + +2、准备evaluate目录中的文件 +* 将Pytorch_Retinaface项目中的 + * Pytorch_Retinaface/widerface_evaluate + + 文件夹放入本项目evaluate文件夹下。 + +3、编译测试依赖代码 +进入evaluate/widerface_evaluate路径下: +``` + python3 setup.py build_ext --inplace +``` + +4、准备模型及标签文件 +在ModelZoo社区下载“ATC Retinaface(FP16) from Pytorch.zip”模型代码包并上传至服务器解压 +* 将模型代码包中的"retinaface.onnx"模型拷贝至项目根目录的"model"目录下 +* 将模型代码包中的"Retinaface/data/widerface/val/wider_val.txt"标签文件拷贝至"evaluate"目录下; + +## 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 编译运行 + +`main.py`:用来生成单张图片推理的可视化结果,以提供推理模型的应用实例。 + +1、在项目根目录下,cd到plugin目录,并执行以下命令进行编译: + +``` +mkdir build +cd build +cmake .. +make -j +make install +``` + +将build文件夹下`libtotalyunetpostprocess.so`修改权限为`640` +并且复制到MindSDK安装路径的`lib/modelpostprocessors`目录。 + + +2、查看项目根目录下的config/aipp.cfg权限是否为640,若不是请修改。 + + + +3、准备好测试图片`test.jpg`,放置在项目根目录。 + +4、运行`main.py`程序 + +在根目录,运行 + +```` +bash run.sh +```` + +最后会得到`result.jpg`即为输出结果 + + + +## 6 精度验证 + +本模型使用widerface数据集进行精度评估。 + +1.[下载](https://share.weiyun.com/5ot9Qv1)数据集放到Retinaface目录下 + +2. 打开test.py文件,在开头修改路径参数: +* RNDB修改为widerface验证集的位置。 +* RNDY修改为保存结果txt文件的文件夹位置。 + +3.在Retinaface目录运行 +``` +python3 test.py +``` +4、在`evaluate/widerface_evaluate`目录运行`python3 evaluation.py -p -g `,等待一段时间后即可得到结果。其中与2中RNDB相同,是widerface_evaluate中的groun_truth文件夹。 + diff --git a/contrib/Retinaface/build.sh b/contrib/Retinaface/build.sh new file mode 100644 index 000000000..0e678a3a6 --- /dev/null +++ b/contrib/Retinaface/build.sh @@ -0,0 +1,37 @@ +#!/bin/bash +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +set -e +current_folder="$( cd "$(dirname "$0")" ;pwd -P )" + + +SAMPLE_FOLDER=( +/plugin/ +) + + +err_flag=0 +for sample in "${SAMPLE_FOLDER[@]}";do + cd "${current_folder}/${sample}" + bash build.sh || { + echo -e "Failed to build ${sample}" + err_flag=1 + } +done + +if [ ${err_flag} -eq 1 ]; then + exit 1 +fi +exit 0 \ No newline at end of file diff --git a/contrib/Retinaface/config/aipp.cfg b/contrib/Retinaface/config/aipp.cfg new file mode 100644 index 000000000..47339dd28 --- /dev/null +++ b/contrib/Retinaface/config/aipp.cfg @@ -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 +} diff --git a/contrib/Retinaface/config/face_Retina.cfg b/contrib/Retinaface/config/face_Retina.cfg new file mode 100644 index 000000000..30e9ff3c2 --- /dev/null +++ b/contrib/Retinaface/config/face_Retina.cfg @@ -0,0 +1,4 @@ +CLASS_NUM=1 +SCORE_THRESH=0.8 +IOU_THRESH=0.9 + diff --git a/contrib/Retinaface/images/process.png b/contrib/Retinaface/images/process.png new file mode 100644 index 0000000000000000000000000000000000000000..d6cabc352174c741be4f649a7bea8ab850a7df4d GIT binary patch literal 32124 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
A3t2hdkEXI+)p@;0P&^0(v*^?s9WQs_+Qp%A zR~qD?R?9BMI*L1t_pvTpE8$7*rrigVr5zp$>Q%Zu^i?W>uq=_(Sdm0C5rK)r=&Q|| zp19lZgB3g0otF;0i{vAn;4K-%c^g)gt&&C5VZd^aRNJKh5U#L-s>CN1eVp_)wl`7KIcr`rvI@} zU!F^KM02EE4%oMW{m?tVQfGhAN@4;VHE?~>sLujMz{H&*5h7~m_g?C#UZK^D?V({d z=%`+euwTIpf|6uu3azg^_zk!l+}6T!8q&VPxTbxE(85>S+~ii_+n=o;dE2?XnI}GG(>AM{^qk$sYJ^C_$&qV>W9Ffv=~6p<-VT&>AR)js4l&$+EG2q z10O^|;sJvc8^*p(t9Ei%i`aZA(Q?;VK{_@)Q8QLb=on@WE8<;XE1xwL9puS{7_udip9dv4?)8 zUG@3`RrKUh?tx^78mzv zd6n^%*McR;K}X-*Jz8H7?z1pa*;WeoEAU%8V!Uu{K_)+jqq z)emMy(dnMAT7{q9Yw41*m#(HfD)AdpY2xI$@&<9#v%aE-*fbOfKXmbNthmetvWVK* zh#hgOMa|sk5>4VCya?_8LgV<~2RClM1i*S`JVE+jj?@GMCaid=^liDergI}8lcgR<~6@iAi(`?yMWwi z%Heg5J)6vxz@oaqjvv<3<*|-oMe@?4e~!!m`4^B0VAQ{XOm|94stnYrxDva2d*AU3 zc!0jRRsw+a$;i46FG2xB!Q2rxeP!-00Q9Mqyl*?MB%9Nx+#oj&d| z2ZLVe@#^N3N#a8!i?V+{7M~v$>8U#o{|)fEvh#oA2w%e^cYh;Vf=CzCPq=Nu35$o| zNC8Qr_mrzm1s&XF77`-SLRNlGYj}9L(m-IV4zmY{5sndwPyS`{3Y37=Pc+e%|0e`5 z=wui)F2OF{KZhcu^_V7WVk5dF;Iu)ezeXE=2hV+6th>_0)?xE6h@hgqmJPkW-qbZw zmzM{NsUB~eBKs$Q;Es$+8mUrsRXrZB0qX!y9{{Z7O`*-TPvyCT|KZv9_to79?p&S#ZlU`EGyop zI9R}8Hyu4@5?y?ugps=~0;_-xz=wWS{bQpN`^ylXMbuci)(=8+&+#!Md)@PKz-h&e zoCFC|ufuFe2avHBF-%k9h-58c$AfpR-hH_dV0n1v_4%-+O~X>1Fs?qSS$Rc8#ViaJ zVg9)=;gMXp$6*nU3vnel^bWDYQ`rG18ZY*KWc7|=T~Sk>s^hiKzrYKhJ8N22I?sCCPjOAd~}w zy`9acdtHcRw>_E)8tcK1M-^cf*`$ldo;pr5&T8-gKD*k10=zajCO$!Xe)_?g>0h(Z z4Zzcm0eb^;Iso)(RTRTNhi2scL4#^DXw(h`c=r{6cPo6sy`$B=?lgJ4YFTGlmZI^T z(GnO?lAzoD+>Yu}!Jk02$>qN(Hk-J2%RY)jcKTVXT~_MKYw8l(fkdW^I~TPg0fP## zAP_tcQh`4SElV8IT~Ab3wC7!}ocjT{6Wp8u9?n|qC~$@H#?`(sK*^rjx!6YZ?FT`C zpuQMj^>Qi4e{uCn)nESbbK +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; +} +namespace MxBase { + TotalYunetPostProcess& TotalYunetPostProcess::operator=(const TotalYunetPostProcess& other) + { + if (this == &other) { + return *this; + } + ObjectPostProcessBase::operator=(other); + return *this; + } + + APP_ERROR TotalYunetPostProcess::Init(const std::map >& postConfig) + { + LogInfo << "Start to Init TotalYunetPostProcess."; + 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 TotalYunetPostProcess."; + return APP_ERR_OK; + } + + APP_ERROR TotalYunetPostProcess::DeInit() + { + return APP_ERR_OK; + } + + void TotalYunetPostProcess::ObjectDetectionOutput(const std::vector & tensors, + std::vector >& objectInfos, + const std::vector & resizedImageInfos) + { + LogInfo << "TotalYunetPostProcess start to write results."; + + 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 loc = tensors[0].GetBuffer(); + auto conf = tensors[1].GetBuffer(); + auto shape = tensors[0].GetShape(); + auto keyshape = tensors[2].GetShape(); + auto key = tensors[2].GetBuffer(); + + 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 = resizedImageInfos[0].widthResize; + float height_resize = resizedImageInfos[0].heightResize; + float width_original = resizedImageInfos[0].widthOriginal; + float height_original = resizedImageInfos[0].heightOriginal; + float width_resize_scale = width_resize / width_original; + float height_resize_scale = height_resize / height_original; + 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 match; + for (uint32_t i = 0; i < batchSize; i++) { + std::vector objectInfo; + std::vector objectInfoSorted; + std::vector keypointInfo; + std::vector 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(j, LEFTTOPX) * IMAGE_WIDTH / width_resize_scale; + objInfo.y0 = res.at(j, LEFTTOPY) * IMAGE_HEIGHT / height_resize_scale; + objInfo.x1 = res.at(j, RIGHTTOPX) * IMAGE_WIDTH / width_resize_scale; + objInfo.y1 = res.at(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 (int k = 0; k < KEYPOINTNUM; k++) + { + float x = res.at(keypoint_Pos, RECTANGLEPOINT + k * DIM) * IMAGE_WIDTH / width_resize_scale; + float y = res.at(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 << "TotalYunetPostProcess write results successed."; + } + APP_ERROR TotalYunetPostProcess::Process(const std::vector &tensors, + std::vector> &objectInfos, + const std::vector &resizedImageInfos, + const std::map> &configParamMap) + { + LogInfo << "Start to Process TotalYunetPostProcess."; + 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 TotalYunetPostProcess."; + return APP_ERR_OK; + } + + /* + * @description: Generate prior boxes for detection boxes decoding + * @param anchors A Matrix used to save prior boxes that contains box coordinates(x0,y0,x1,y1), shape[21824,4] + */ + void TotalYunetPostProcess::GeneratePriorBox(cv::Mat &anchors) + { + std::vector>feature_maps(RIGHTTOPY, std::vector(DIM)); + for (int 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 (int 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(0, LEFTTOPX) = center_x / IMAGE_WIDTH; + anchor.at(0, LEFTTOPY) = center_y / IMAGE_HEIGHT; + anchor.at(0, RIGHTTOPX) = min_size / IMAGE_WIDTH; + anchor.at(0, RIGHTTOPY) = min_size / IMAGE_HEIGHT; + + anchor.at(0, LEFTTOPX + RECTANGLEPOINT) = prior_width; + anchor.at(0, LEFTTOPY + RECTANGLEPOINT) = prior_height; + anchor.at(0, RIGHTTOPX + RECTANGLEPOINT) = prior_center_x; + anchor.at(0, RIGHTTOPY + RECTANGLEPOINT) = prior_center_y; + + anchors.push_back(anchor); + } + } + } + } + } + /* + * @description: Generate prior boxes for detection boxes decoding + * @param loc: The matrix which contains box biases, shape[21824, 4] + * @param prior: The matrix which contains prior box coordinates, shape[21824,4] + * @param resize_scale_factor: The factor of min(WidthOriginal/WidthResize, HeightOriginal/HeightResize) + * @param boxes: The matrix which contains detection box coordinates(x0,y0,x1,y1), shape[21824,4] + */ + cv::Mat TotalYunetPostProcess::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 (int 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; + } + + extern "C" { + std::shared_ptr GetObjectInstance() + { + LogInfo << "Begin to get TotalYunetPostProcess instance."; + auto instance = std::make_shared(); + LogInfo << "End to get TotalYunetPostProcess instance."; + return instance; + } + } +} diff --git a/contrib/Retinaface/plugin/TotalYunetPostProcess.h b/contrib/Retinaface/plugin/TotalYunetPostProcess.h new file mode 100644 index 000000000..b65a9cb79 --- /dev/null +++ b/contrib/Retinaface/plugin/TotalYunetPostProcess.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) Huawei Technologies Co., Ltd. 2020-2021. 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 Yunet_POST_PROCESS_H +#define Yunet_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.2 + +namespace MxBase { + bool operator<(const ObjectInfo &a, const ObjectInfo &b) { + return a.confidence < b.confidence; + } + + class TotalYunetPostProcess : public ObjectPostProcessBase { + public: + TotalYunetPostProcess() = default; + + ~TotalYunetPostProcess() = default; + + TotalYunetPostProcess(const TotalYunetPostProcess& other); + + TotalYunetPostProcess& operator=(const TotalYunetPostProcess& other); + + APP_ERROR Init(const std::map >& postConfig) override; + + APP_ERROR DeInit() override; + + APP_ERROR Process(const std::vector &tensors, std::vector> &objectInfos, + const std::vector &resizedImageInfos = {}, + const std::map> &configParamMap = {}) override; + + protected: + void GeneratePriorBox(cv::Mat &anchors); + cv::Mat decode_for_loc(cv::Mat &loc, cv::Mat &prior, cv::Mat &key, float resize_scale_factor); + void ObjectDetectionOutput(const std::vector & tensors, + std::vector >& objectInfos, + const std::vector & resizedImageInfos = {}); + 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; + }; + + extern "C" { + std::shared_ptr GetObjectInstance(); + } +} +#endif diff --git a/contrib/Retinaface/plugin/build.sh b/contrib/Retinaface/plugin/build.sh new file mode 100644 index 000000000..006f86ba8 --- /dev/null +++ b/contrib/Retinaface/plugin/build.sh @@ -0,0 +1,36 @@ +#!/bin/bash +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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.mitations under the License. + +set -e + +current_folder="$( cd "$(dirname "$0")" ;pwd -P )" + +function build_plugin() { + build_path=$current_folder/build + if [ -d "$build_path" ]; then + rm -rf "$build_path" + else + echo "file $build_path is not exist." + fi + mkdir -p "$build_path" + cd "$build_path" + cmake .. + make -j + cd .. + exit 0 +} + +build_plugin +exit 0 \ No newline at end of file diff --git a/contrib/Retinaface/run.sh b/contrib/Retinaface/run.sh new file mode 100644 index 000000000..65177cb83 --- /dev/null +++ b/contrib/Retinaface/run.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +# Copyright 2020 Huawei Technologies Co., Ltd +# +# 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. + +set -e + +CUR_PATH=$(cd "$(dirname "$0")" || { warn "Failed to check path/to/run.sh" ; exit ; } ; pwd) + +# Simple log helper functions +info() { echo -e "\033[1;34m[INFO ][MxStream] $1\033[1;37m" ; } +warn() { echo >&2 -e "\033[1;31m[WARN ][MxStream] $1\033[1;37m" ; } + +export LD_LIBRARY_PATH=${MX_SDK_HOME}/lib:${MX_SDK_HOME}/opensource/lib:${MX_SDK_HOME}/opensource/lib64:/usr/local/Ascend/ascend-toolkit/latest/acllib/lib64:${LD_LIBRARY_PATH} +export GST_PLUGIN_SCANNER=${MX_SDK_HOME}/opensource/libexec/gstreamer-1.0/gst-plugin-scanner +export GST_PLUGIN_PATH=${MX_SDK_HOME}/opensource/lib/gstreamer-1.0:${MX_SDK_HOME}/lib/plugins + +#to set PYTHONPATH, import the StreamManagerApi.py +export PYTHONPATH=$PYTHONPATH:${MX_SDK_HOME}/python + +python3 main.py +exit 0 diff --git a/contrib/Retinaface/test.py b/contrib/Retinaface/test.py new file mode 100644 index 000000000..3ba71bfdd --- /dev/null +++ b/contrib/Retinaface/test.py @@ -0,0 +1,139 @@ +#!/usr/bin/env python +# coding=utf-8 + +""" +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. +""" + +import os +import stat +import argparse +import json +import shutil +import tqdm +import cv2 +import numpy as np +import MxpiDataType_pb2 as MxpiDataType +from PIL import Image +from utils import preprocess, postprocess +from StreamManagerApi import StreamManagerApi, MxDataInput, StringVector +from StreamManagerApi import StreamManagerApi, MxProtobufIn, InProtobufVector, StringVector + +RNDB = "./widerface/val/images/" +RNDY = "./evaluate/widerface_txt" +img_addresses = [] +streamManagerApi = StreamManagerApi() +ret = streamManagerApi.InitManager() +if ret != 0: + print("Failed to init Stream manager, ret=%s" % str(ret)) + exit() + +pipeline = { + "Retinaface": { + "stream_config": { + "deviceId": "3" + }, + "appsrc0": { + "props": { + "blocksize": "409600" + }, + "factory": "appsrc", + "next": "mxpi_tensorinfer0" + }, + "mxpi_tensorinfer0": { + "props": { + "singleBatchInfer": "1", + "dataSource": "appsrc0", + "modelPath": "./model/newRetinaface.om" + }, + "factory": "mxpi_tensorinfer", + "next": "appsink0" + }, + "appsink0": { + "props": { + "blocksize": "409600" + }, + "factory": "appsink" + } + } +} + +pipelineStr = json.dumps(pipeline).encode() +ret = streamManagerApi.CreateMultipleStreams(pipelineStr) +if ret != 0: + print("Failed to create Stream, ret=%s" % str(ret)) + exit() + +FLAGS = os.O_WRONLY | os.O_CREAT +MODES = stat.S_IWUSR | stat.S_IRUSR +with os.fdopen(os.open('./evaluate/wider_val.txt', FLAGS, MODES), 'r') as fr: + for img_address in fr: + print(img_address) + tensor_data , info = preprocess(RNDB + img_address.strip('\r\n')) + tensor = tensor_data[None, :] + STREAMNAME = b"Retinaface" + INPLUGINID = 0 + visionList = MxpiDataType.MxpiVisionList() + visionVec = visionList.visionVec.add() + visionInfo = visionVec.visionInfo + + visionInfo.width = 1000 + visionInfo.height = 1000 + visionInfo.widthAligned = 1000 + visionInfo.heightAligned = 1000 + visionData = visionVec.visionData + visionData.dataStr = tensor.tobytes() + visionData.deviceId = 0 + visionData.memType = 0 + visionData.dataSize = len(tensor) + + KEY_VALUE = b"appsrc0" + protobufVec = InProtobufVector() + + protobuf = MxProtobufIn() + protobuf.key = KEY_VALUE + protobuf.type = b"MxTools.MxpiVisionList" + protobuf.protobuf = visionList.SerializeToString() + protobufVec.push_back(protobuf) + + uniqueId = streamManagerApi.SendProtobuf(STREAMNAME, INPLUGINID, protobufVec) + KEY_VALUE = b"mxpi_tensorinfer0" + keyVec = StringVector() + keyVec.push_back(KEY_VALUE) + inferResult = streamManagerApi.GetProtobuf(STREAMNAME, 0, keyVec) + + infer_list = MxpiDataType.MxpiTensorPackageList() + infer_list.ParseFromString(inferResult[0].messageBuf) + infer_data0 = infer_list.tensorPackageVec[0].tensorVec[0].dataStr + loc = np.frombuffer(infer_data0, dtype=np.float32) + infer_data1 = infer_list.tensorPackageVec[0].tensorVec[1].dataStr + conf = np.frombuffer(infer_data1, dtype=np.float32) + infer_data2 = infer_list.tensorPackageVec[0].tensorVec[2].dataStr + landms = np.frombuffer(infer_data2, dtype=np.float32) + result , count = postprocess(loc , conf , landms , info) + dir_name = RNDY + "/" + os.path.split(img_address.strip('.jpg\r\n'))[0] + if not os.path.isdir(dir_name): + os.makedirs(dir_name) + print(dir_name) + txt_name = RNDY + "/" + img_address.strip('.jpg\r\n') + '.txt' + res_name = os.path.split(img_address.strip('.jpg\r\n'))[1] + "\n" + with os.fdopen(os.open(txt_name, FLAGS, MODES), 'w') as f: + f.write(res_name) + f.write('{:d}\n'.format(count)) + f.write(result) + f.close() + +streamManagerApi.DestroyAllStreams() + diff --git a/contrib/Retinaface/utils.py b/contrib/Retinaface/utils.py new file mode 100644 index 000000000..4d91b278d --- /dev/null +++ b/contrib/Retinaface/utils.py @@ -0,0 +1,129 @@ +# Copyright 2021 Huawei Technologies Co., Ltd +# +# 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. + +from __future__ import print_function +import os +import argparse +from glob import glob +import sys +import cv2 +import torch +import numpy as np +from PIL import Image +from PIL import ImageDraw + +from include.box_utils import decode, decode_landm +from include.prior_box import PriorBox +from include.py_cpu_nms import py_cpu_nms +cfg_mnet = { + 'name': 'mobilenet0.25', + 'min_sizes': [[16, 32], [64, 128], [256, 512]], + 'steps': [8, 16, 32], + 'variance': [0.1, 0.2], + 'clip': False, + 'loc_weight': 2.0, + 'gpu_train': True, + 'batch_size': 32, + 'ngpu': 1, + 'epoch': 250, + 'decay1': 190, + 'decay2': 220, + 'image_size': 640, + 'pretrain': True, + 'return_layers': {'stage1': 1, 'stage2': 2, 'stage3': 3}, + 'in_channel': 32, + 'out_channel': 64 +} + + +def preprocess(image_path): + img_raw = cv2.imread(image_path, cv2.IMREAD_COLOR) + img = np.float32(img_raw) + # testing scale + target_size = 1000 + im_shape = img.shape + im_size_min = np.min(im_shape[0:2]) + im_size_max = np.max(im_shape[0:2]) + resize = target_size / im_size_max + img = cv2.resize(img, None, None, fx=resize, fy=resize, interpolation=cv2.INTER_NEAREST) + width_pad = target_size - img.shape[1] + left = 0 + right = width_pad + height_pad = target_size - img.shape[0] + top = 0 + bottom = height_pad + img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=(0, 0, 0)) + im_height, im_width, _ = img.shape + scale = torch.Tensor([img.shape[1], img.shape[0], img.shape[1], img.shape[0]]) + img = torch.from_numpy(img).unsqueeze(0).byte() + info = np.array(resize, dtype=np.float32) + return img.numpy() , info + + +def postprocess(loc , conf , landms , resize): + loc = np.reshape(loc, [1, 41236, 4]) + conf = np.reshape(conf , [1, 41236, 2]) + landms = np.reshape(landms , [1, 41236, 10]) + scale = torch.ones(4,).fill_(1000) + loc = torch.Tensor(loc) + conf = torch.Tensor(conf) + landms = torch.Tensor(landms) + priorbox = PriorBox(cfg_mnet, image_size=(1000, 1000)) + priors = priorbox.forward() + prior_data = priors.data + boxes = decode(loc.data.squeeze(0), prior_data, [0.1, 0.2]) + boxes = boxes * scale / resize + boxes = boxes.numpy() + scores = conf.squeeze(0).data.numpy()[:, 1] + landms = decode_landm(landms.data.squeeze(0), prior_data, [0.1, 0.2]) + scale1 = torch.ones(10,).fill_(1000) + + landms = landms * scale1 / resize + landms = landms.numpy() + + inds = np.where(scores > 0.02)[0] + boxes = boxes[inds] + landms = landms[inds] + scores = scores[inds] + # keep top-K before NMS + order = scores.argsort()[::-1] + boxes = boxes[order] + landms = landms[order] + scores = scores[order] + + # do NMS + dets = np.hstack((boxes, scores[:, np.newaxis])).astype(np.float32, copy=False) + keep = py_cpu_nms(dets, 0.4) + dets = dets[keep, :] + landms = landms[keep] + + dets = np.concatenate((dets, landms), axis=1) + bboxs = dets + bboxs_num = str(len(bboxs)) + "\n" + a = Image.open("test.jpg") + result = '' + count = 0 + for box in bboxs: + x = int(box[0]) + y = int(box[1]) + w = int(box[2]) - int(box[0]) + h = int(box[3]) - int(box[1]) + confidence = str(box[4]) + if confidence != 0: + count += 1 + line = str(x) + " " + str(y) + " " + str(w) + " " + str(h) + " " + confidence + " \n" + result += line + aa = ImageDraw.ImageDraw(a) + aa.rectangle((x, y, x+w, y+h), outline='red', width=3) + return result , count -- Gitee From 935aa7118272b2c90b4531042e4d5ba7e9aa39e3 Mon Sep 17 00:00:00 2001 From: lihaowei Date: Thu, 17 Nov 2022 09:23:29 +0800 Subject: [PATCH 2/9] fix readme and utils --- contrib/Retinaface/README.md | 122 +++++++++++++++++++++++---- contrib/Retinaface/images/origin.png | Bin 0 -> 6789 bytes contrib/Retinaface/images/result.png | Bin 0 -> 6539 bytes contrib/Retinaface/main.py | 6 +- contrib/Retinaface/utils.py | 19 +++++ 5 files changed, 128 insertions(+), 19 deletions(-) create mode 100644 contrib/Retinaface/images/origin.png create mode 100644 contrib/Retinaface/images/result.png diff --git a/contrib/Retinaface/README.md b/contrib/Retinaface/README.md index e46390a4e..04af5eb40 100644 --- a/contrib/Retinaface/README.md +++ b/contrib/Retinaface/README.md @@ -35,6 +35,7 @@ Retinaface基于MindX_SDK开发,在昇腾芯片上进行目标检测,并实 ├── config │   └── aipp.cfg │ ├── face_Retina.cfg +├── images ├── main.py ├── test.py ├── utils.py @@ -114,7 +115,7 @@ mkdir -p evaluate/widerface_txt/ ``` git clone https://github.com/biubug6/Pytorch_Retinaface.git ``` -或者直接下载zip代码包解压。 +或者直接下载[论文代码仓库](https://github.com/biubug6/Pytorch_Retinaface)中的zip代码包解压。 1、准备include目录中的文件 @@ -138,25 +139,23 @@ git clone https://github.com/biubug6/Pytorch_Retinaface.git ``` 4、准备模型及标签文件 -在ModelZoo社区下载“ATC Retinaface(FP16) from Pytorch.zip”模型代码包并上传至服务器解压 +在ModelZoo社区[下载](https://www.hiascend.com/zh/software/modelzoo/models/detail/1/7270b02a457d4c4ab262277a646517f9)“ATC Retinaface(FP16) from Pytorch.zip”模型代码包并上传至服务器解压。 * 将模型代码包中的"retinaface.onnx"模型拷贝至项目根目录的"model"目录下 * 将模型代码包中的"Retinaface/data/widerface/val/wider_val.txt"标签文件拷贝至"evaluate"目录下; ## 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) +下载后解包,得到`Retinaface.onnx`,使用模型转换工具ATC将onnx模型转换为om模型,模型转换工具相关介绍参考[链接](https://support.huaweicloud.com/tg-cannApplicationDev330/atlasatc_16_0005.html) 模型转换步骤如下: -1、按照2环境依赖设置环境变量 - -2、`cd`到`model`文件夹,运行 +1、`cd`到`model`文件夹,运行 ```` bash run.sh ```` -3、执行该命令后会在指定输出.om模型路径生成项目指定模型文件newRetinaface.om。若模型转换成功则输出: +2、执行该命令后会在指定输出.om模型路径生成项目指定模型文件newRetinaface.om。若模型转换成功则输出: ``` ATC start working now, please wait for a moment. @@ -210,12 +209,51 @@ make install 4、运行`main.py`程序 -在根目录,运行 - -```` +确认并修改“main.py”中下列所示的代码: +``` +pipeline = { + "Retinaface": { + "stream_config": { + "deviceId": "3" # 运行NPU卡ID + }, + "appsrc0": { + "props": { + "blocksize": "409600" + }, + "factory": "appsrc", + "next": "mxpi_tensorinfer0" + }, + "mxpi_tensorinfer0": { + "props": { + "singleBatchInfer": "1", + "dataSource": "appsrc0", + "modelPath": "./model/newRetinaface.om" # 推理所需模型 + }, + "factory": "mxpi_tensorinfer", + "next": "mxpi_objectpostprocessor0" + }, + "mxpi_objectpostprocessor0": { + "props": { + "dataSource": "mxpi_tensorinfer0", + "postProcessConfigPath": "./config/face_Retina.cfg", # 推理所需的配置文件 + "postProcessLibPath": "libtotalyunetpostprocess.so" + }, + "factory": "mxpi_objectpostprocessor", + "next": "appsink0" + }, + "appsink0": { + "props": { + "blocksize": "409600" + }, + "factory": "appsink" + } + } + } +``` +在代码根目录下,执行以下命令进行推理: +``` bash run.sh -```` - +``` 最后会得到`result.jpg`即为输出结果 @@ -224,15 +262,67 @@ bash run.sh 本模型使用widerface数据集进行精度评估。 -1.[下载](https://share.weiyun.com/5ot9Qv1)数据集放到Retinaface目录下 +1.[下载](https://mindx.sdk.obs.cn-north-4.myhuaweicloud.com/mindxsdk-referenceapps%20/contrib/Retinaface/widerface.zip)数据集放到Retinaface目录下 -2. 打开test.py文件,在开头修改路径参数: +2.打开test.py文件,在开头修改路径参数: * RNDB修改为widerface验证集的位置。 * RNDY修改为保存结果txt文件的文件夹位置。 +如例: + ``` + RNDB = "./widerface/val/images/" + RNDY = "./evaluate/widerface_txt" + ``` -3.在Retinaface目录运行 +3.确认并修改“test.py”中下列所示的代码: +``` +pipeline = { + "Retinaface": { + "stream_config": { + "deviceId": "3" # 运行NPU卡ID + }, + "appsrc0": { + "props": { + "blocksize": "409600" + }, + "factory": "appsrc", + "next": "mxpi_tensorinfer0" + }, + "mxpi_tensorinfer0": { + "props": { + "singleBatchInfer": "1", + "dataSource": "appsrc0", + "modelPath": "./model/newRetinaface.om" # 推理所需模型 + }, + "factory": "mxpi_tensorinfer", + "next": "appsink0" + }, + "appsink0": { + "props": { + "blocksize": "409600" + }, + "factory": "appsink" + } + } +} +``` +在Retinaface目录运行 ``` python3 test.py ``` -4、在`evaluate/widerface_evaluate`目录运行`python3 evaluation.py -p -g `,等待一段时间后即可得到结果。其中与2中RNDB相同,是widerface_evaluate中的groun_truth文件夹。 +该程序会逐一推理widerface官方验证集之中的样本,并将结果保存在RNDB文件当中。 + +4、进入`evaluate/widerface_evaluate`目录下,运行`python3 evaluation.py -p -g `, 其中: + +* ``即RNDB是模型推理的结果。 + +* ``是widerface_evaluate中的groun_truth文件夹。 + +最终得到的精度如下图所示: + +![模型推理结果](images/result.png) + +原模型精度如下图所示: + +![源模型推理结果](images/origin.png) +符合精度偏差要求,精度达标。 \ No newline at end of file diff --git a/contrib/Retinaface/images/origin.png b/contrib/Retinaface/images/origin.png new file mode 100644 index 0000000000000000000000000000000000000000..43326c05ba85ef5fcbe52386783547f0a70d833a GIT binary patch literal 6789 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 BHctQm literal 0 HcmV?d00001 diff --git a/contrib/Retinaface/images/result.png b/contrib/Retinaface/images/result.png new file mode 100644 index 0000000000000000000000000000000000000000..30b205ada7b1f59a22f57a80e1caa99d324a6f02 GIT binary patch literal 6539 zcma)>cQjnzx4;Ksz9LA7ObCJyWr9STs3{V?h3GZWgXo0OeM1mrM(>HJQATewI$>ro zK@3KjD1#``M~^r8wYT2;DQ$WWHB)Z@fW_y} zO*QLq^9=yN&ZGY1(epP}8#%ll3wLY#_PH5_MOuy=G$InNroD~+80QKV5!sE^TAMojZsa zY`wRf6EK~-r#Uxwlm^S=*4|@Hzreh7H2!ru6qPyVfFQDa-{;&51pxGL=d0~DS~{Tv zz%$7#ai@MV4++_p$G&^ykf2uu0Bqr?1fXnWhuT2t&01(JFT=YE9%!jAGH{w>#RLF2 zJP1QxrwsBsy-5v4bf`TT=zF7jo#3&!r!y*F=*F5V98N15^ z)9xRgr~pS4^M_uvYvOuwPR3E!cuf%B^Q?NX*mR53OX*Fa6kSN8yK{i}AXjkijQd`# z#awVEmIiR0Nyro+x3k^n26<^;s4DiQ7b&0BPasJZ9L{2;%EpGL%k#QN+r<{^g1U*;LZEEwPYZG$8KE=Uuz!c7Jntru{KbFk8$LAhE3))SF=~qUUYz^+xu*j zatylV0}1(x_q&`PAR4{6sl%SE+?9oy zE^iv#AmiE(WMN~2@HkxBgeuQmG&Hm^yNhGxJBFsCopHKX&46@MXLQPPoheeNd@@k8 z0XDA}gX2TZ`HD`yd-9+DIhx|A4ypBHaUzXKeRgRuk}ltOxBwnZ$e_vSL4}uQ!8bmg z0!@o)0R@za4$~q>OHM*1z1!hwZtIRr)=do7ZS*|$?CnvzRq5u~?aizprL#GwZvUlX zWW2~kNcQ{bA%8ch-9N@qWk;p!#0mg}!NTBwmX!+izpRvL1psXLKid5d zCt}MYZvIe?bg?ghVm~yqL0iR*;uT(<4jD5Y(gOfL@&s{kxBE*QM8-6d&S0rLqpI#P zeODf7_+-F5FJJo$5Q!~)a{TEdmTJo~Mptn)!#K5`D1eY~^AOQr4XE6|({t3k%==rZ ztKB-mB1eJC7E`zNx|_ujM4KpEn*R{W@$em3^REM%P( zRMN^EGiLllGQ3tjN~8csuCx99`&`6+ z9f_sN`^~M3KLr!LHkTULwoGf7dz0qYiJ|U;+Z&?;OAIy0tVwtNsFn2)wy{qQeTZc| zwBU^yY-Hil^o=8a#17AyU&$r8`zJIdoc*DW*UVr!JNaZ253bfWeQ

1ZXY`ai}D2 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 v-k*p&)J}1s^k)w!DuC`n>OVXezn Date: Thu, 17 Nov 2022 09:41:51 +0800 Subject: [PATCH 3/9] fix code style --- contrib/Retinaface/utils.py | 1 + 1 file changed, 1 insertion(+) diff --git a/contrib/Retinaface/utils.py b/contrib/Retinaface/utils.py index 01f1fde76..54eeef195 100644 --- a/contrib/Retinaface/utils.py +++ b/contrib/Retinaface/utils.py @@ -65,6 +65,7 @@ def preprocess_for_main(image_path): im_height, im_width, _ = img.shape img = img.flatten() return img , [resize, left, top, right, bottom] + def preprocess(image_path): img_raw = cv2.imread(image_path, cv2.IMREAD_COLOR) -- Gitee From be997d79ee5055fc2803c204bdf6e0ebf417a367 Mon Sep 17 00:00:00 2001 From: lihaowei Date: Tue, 22 Nov 2022 13:06:10 +0800 Subject: [PATCH 4/9] fix test.py --- contrib/Retinaface/test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/Retinaface/test.py b/contrib/Retinaface/test.py index 3ba71bfdd..2d59c6536 100644 --- a/contrib/Retinaface/test.py +++ b/contrib/Retinaface/test.py @@ -76,7 +76,7 @@ if ret != 0: print("Failed to create Stream, ret=%s" % str(ret)) exit() -FLAGS = os.O_WRONLY | os.O_CREAT +FLAGS = os.O_RDWR | os.O_CREAT MODES = stat.S_IWUSR | stat.S_IRUSR with os.fdopen(os.open('./evaluate/wider_val.txt', FLAGS, MODES), 'r') as fr: for img_address in fr: -- Gitee From b1d26bc5c23f8b90e8f3125922e4c44dc06c5cb4 Mon Sep 17 00:00:00 2001 From: lihaowei Date: Wed, 23 Nov 2022 10:34:53 +0800 Subject: [PATCH 5/9] add path check and fix readme --- contrib/Retinaface/README.md | 15 +++++++++------ contrib/Retinaface/main.py | 10 ++++++++-- contrib/Retinaface/model/run.sh | 10 ---------- contrib/Retinaface/test.py | 2 +- 4 files changed, 18 insertions(+), 19 deletions(-) diff --git a/contrib/Retinaface/README.md b/contrib/Retinaface/README.md index 04af5eb40..15858394f 100644 --- a/contrib/Retinaface/README.md +++ b/contrib/Retinaface/README.md @@ -103,7 +103,12 @@ ascend-toolkit-path: CANN 安装路径。 ## 3 软件依赖说明 -本项目无特定软件依赖。 +* Cpython + + 可通过pip指令直接安装: + ``` + pip3 install cpython + ``` ## 4.推理文件准备 进入项目根目录,执行以下命令,创建所需文件夹: @@ -214,7 +219,7 @@ make install pipeline = { "Retinaface": { "stream_config": { - "deviceId": "3" # 运行NPU卡ID + "deviceId": "0" # 运行NPU卡ID }, "appsrc0": { "props": { @@ -262,7 +267,7 @@ bash run.sh 本模型使用widerface数据集进行精度评估。 -1.[下载](https://mindx.sdk.obs.cn-north-4.myhuaweicloud.com/mindxsdk-referenceapps%20/contrib/Retinaface/widerface.zip)数据集放到Retinaface目录下 +1.[下载](https://share.weiyun.com/5ot9Qv1)数据集放到Retinaface目录下 2.打开test.py文件,在开头修改路径参数: * RNDB修改为widerface验证集的位置。 @@ -278,7 +283,7 @@ bash run.sh pipeline = { "Retinaface": { "stream_config": { - "deviceId": "3" # 运行NPU卡ID + "deviceId": "0" # 运行NPU卡ID }, "appsrc0": { "props": { @@ -318,11 +323,9 @@ python3 test.py * ``是widerface_evaluate中的groun_truth文件夹。 最终得到的精度如下图所示: - ![模型推理结果](images/result.png) 原模型精度如下图所示: - ![源模型推理结果](images/origin.png) 符合精度偏差要求,精度达标。 \ No newline at end of file diff --git a/contrib/Retinaface/main.py b/contrib/Retinaface/main.py index 3ec6a76de..d95f354a8 100644 --- a/contrib/Retinaface/main.py +++ b/contrib/Retinaface/main.py @@ -40,7 +40,7 @@ if __name__ == '__main__': pipeline = { "Retinaface": { "stream_config": { - "deviceId": "3" + "deviceId": "0" }, "appsrc0": { "props": { @@ -81,7 +81,13 @@ if __name__ == '__main__': print("Failed to create Stream, ret=%s" % str(ret)) exit() - tensor_data , return_img = preprocess_for_main("./test.jpg") + img_path = "./test.jpg" + + if not os.path.exists(img_path): + print("Test image does not exsit!") + exit() + + tensor_data , return_img = preprocess_for_main(img_path) tensor = tensor_data[None, :] STREAMNAME = b"Retinaface" diff --git a/contrib/Retinaface/model/run.sh b/contrib/Retinaface/model/run.sh index 1772eb922..16fddd791 100644 --- a/contrib/Retinaface/model/run.sh +++ b/contrib/Retinaface/model/run.sh @@ -1,16 +1,6 @@ #!/bin/bash -# 设置环境变量(请确认install_path路径是否正确) -# Set environment PATH (Please confirm that the install_path is correct). - -export install_path=/usr/local/Ascend/ascend-toolkit/latest -export PATH=/usr/local/python3/bin:${install_path}/atc/ccec_compiler/bin:${install_path}/atc/bin:$PATH -export PYTHONPATH=${install_path}/atc/python/site-packages:${install_path}/atc/python/site-packages/auto_tune.egg/auto_tune:${install_path}/atc/python/site-packages/schedule_search.egg -export LD_LIBRARY_PATH=${install_path}/atc/lib64:$LD_LIBRARY_PATH -export ASCEND_OPP_PATH=${install_path}/opp - - # 执行,转换Retinaface模型 # Execute, transform Retinaface model. diff --git a/contrib/Retinaface/test.py b/contrib/Retinaface/test.py index 2d59c6536..5d19aba14 100644 --- a/contrib/Retinaface/test.py +++ b/contrib/Retinaface/test.py @@ -43,7 +43,7 @@ if ret != 0: pipeline = { "Retinaface": { "stream_config": { - "deviceId": "3" + "deviceId": "0" }, "appsrc0": { "props": { -- Gitee From acc216c4aa29979ba297daefa3222123f980cde6 Mon Sep 17 00:00:00 2001 From: lihaowei Date: Wed, 23 Nov 2022 11:03:44 +0800 Subject: [PATCH 6/9] fix code style --- contrib/Retinaface/main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/Retinaface/main.py b/contrib/Retinaface/main.py index d95f354a8..6739038f2 100644 --- a/contrib/Retinaface/main.py +++ b/contrib/Retinaface/main.py @@ -81,13 +81,13 @@ if __name__ == '__main__': print("Failed to create Stream, ret=%s" % str(ret)) exit() - img_path = "./test.jpg" + IMAGE = "./test.jpg" - if not os.path.exists(img_path): + if not os.path.exists(IMAGE): print("Test image does not exsit!") exit() - tensor_data , return_img = preprocess_for_main(img_path) + tensor_data , return_img = preprocess_for_main(IMAGE) tensor = tensor_data[None, :] STREAMNAME = b"Retinaface" -- Gitee From 69c5b2ea11da1ccaee2cb35d7168814e0aa31308 Mon Sep 17 00:00:00 2001 From: lihaowei Date: Wed, 23 Nov 2022 15:22:30 +0800 Subject: [PATCH 7/9] fix test --- contrib/Retinaface/test.py | 2 +- contrib/Retinaface/utils.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/contrib/Retinaface/test.py b/contrib/Retinaface/test.py index 5d19aba14..3dbb8b6cb 100644 --- a/contrib/Retinaface/test.py +++ b/contrib/Retinaface/test.py @@ -122,7 +122,7 @@ with os.fdopen(os.open('./evaluate/wider_val.txt', FLAGS, MODES), 'r') as fr: conf = np.frombuffer(infer_data1, dtype=np.float32) infer_data2 = infer_list.tensorPackageVec[0].tensorVec[2].dataStr landms = np.frombuffer(infer_data2, dtype=np.float32) - result , count = postprocess(loc , conf , landms , info) + result , count = postprocess(loc , conf , landms , info , RNDB + img_address.strip('\r\n')) dir_name = RNDY + "/" + os.path.split(img_address.strip('.jpg\r\n'))[0] if not os.path.isdir(dir_name): os.makedirs(dir_name) diff --git a/contrib/Retinaface/utils.py b/contrib/Retinaface/utils.py index 54eeef195..d6a9ae5bb 100644 --- a/contrib/Retinaface/utils.py +++ b/contrib/Retinaface/utils.py @@ -91,7 +91,7 @@ def preprocess(image_path): return img.numpy() , info -def postprocess(loc , conf , landms , resize): +def postprocess(loc , conf , landms , resize , img_path): loc = np.reshape(loc, [1, 41236, 4]) conf = np.reshape(conf , [1, 41236, 2]) landms = np.reshape(landms , [1, 41236, 10]) @@ -131,7 +131,7 @@ def postprocess(loc , conf , landms , resize): dets = np.concatenate((dets, landms), axis=1) bboxs = dets bboxs_num = str(len(bboxs)) + "\n" - a = Image.open("test.jpg") + a = Image.open(img_path) result = '' count = 0 for box in bboxs: -- Gitee From e43d610a211f7cd230398aee8a561d9847232c02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=8A=E4=BC=9F?= Date: Thu, 24 Nov 2022 03:52:37 +0000 Subject: [PATCH 8/9] fix readme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 李昊伟 --- contrib/Retinaface/README.md | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/contrib/Retinaface/README.md b/contrib/Retinaface/README.md index 15858394f..cd1a43c34 100644 --- a/contrib/Retinaface/README.md +++ b/contrib/Retinaface/README.md @@ -62,9 +62,12 @@ Retinaface基于MindX_SDK开发,在昇腾芯片上进行目标检测,并实 本项目根据widerface数据集训练得到,适用于人脸检测,并且将人脸位置与五官位置标出。 本项目在绝大多数情况下准确,但是存在以下检测异常的情况: + 1.正常检测中,由于模型本身的限制,会出现部分物体检测不到/检测错误; -2.图片中无检测目标时,会出现可视化异常,输出结果无图片信息 +2.图片中无检测目标时,会出现可视化异常,输出结果无图片信息; + +3.对于图片中一些侧脸和与人脸相似的动物脸的情况,模型可能会出现漏检测或者误检测; @@ -97,7 +100,7 @@ CANN 环境变量: - 环境变量介绍 ``` -SDK-path: mxVision SDK 安装路径 +SDK-path: mxVision SDK * 安装路径 ascend-toolkit-path: CANN 安装路径。 ``` @@ -110,6 +113,13 @@ ascend-toolkit-path: CANN 安装路径。 pip3 install cpython ``` +* Ipython + + 可通过pip指令直接安装: + ``` + pip3 install ipython + ``` + ## 4.推理文件准备 进入项目根目录,执行以下命令,创建所需文件夹: ``` @@ -314,7 +324,7 @@ pipeline = { ``` python3 test.py ``` -该程序会逐一推理widerface官方验证集之中的样本,并将结果保存在RNDB文件当中。 +该程序会逐一推理widerface官方验证集之中的样本,并将结果保存在RNDY文件当中。 4、进入`evaluate/widerface_evaluate`目录下,运行`python3 evaluation.py -p -g `, 其中: @@ -322,10 +332,16 @@ python3 test.py * ``是widerface_evaluate中的groun_truth文件夹。 +比如: +``` +python3 evaluation.py -p ../widerface_txt/ -g ground_truth/ +``` 最终得到的精度如下图所示: + ![模型推理结果](images/result.png) 原模型精度如下图所示: + ![源模型推理结果](images/origin.png) 符合精度偏差要求,精度达标。 \ No newline at end of file -- Gitee From 9da344476357242990e3044a5a768da5a0ba222f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E6=98=8A=E4=BC=9F?= Date: Thu, 24 Nov 2022 08:33:26 +0000 Subject: [PATCH 9/9] fix readme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 李昊伟 --- contrib/Retinaface/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/Retinaface/README.md b/contrib/Retinaface/README.md index cd1a43c34..a36105d01 100644 --- a/contrib/Retinaface/README.md +++ b/contrib/Retinaface/README.md @@ -328,7 +328,7 @@ python3 test.py 4、进入`evaluate/widerface_evaluate`目录下,运行`python3 evaluation.py -p -g `, 其中: -* ``即RNDB是模型推理的结果。 +* ``即RNDY是模型推理的结果。 * ``是widerface_evaluate中的groun_truth文件夹。 -- Gitee