change README

This commit is contained in:
吴镇
2022-10-10 05:09:35 +08:00
parent a2bf8cac7f
commit 9450d6662e
13 changed files with 1003 additions and 0 deletions

39
FCOS/CMakeLists.txt Normal file
View File

@@ -0,0 +1,39 @@
cmake_minimum_required(VERSION 3.10)
project(mxBase_sample)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
include_directories(./FCOSDection)
include_directories(./FCOSPostprocess)
include_directories(/usr/local/Ascend/ascend-toolkit/latest/arm64-linux/runtime/include/)
file(GLOB_RECURSE FCOS_POSTPROCESS ${PROJECT_SOURCE_DIR}/FCOSPostprocess/*cpp)
file(GLOB_RECURSE FCOS_DETECTION ${PROJECT_SOURCE_DIR}/FCOSDection/*cpp)
set(TARGET mxBase_sample)
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 ${SDK安装路径})
include_directories(
${MX_SDK_HOME}/include
${MX_SDK_HOME}/opensource/include
${MX_SDK_HOME}/opensource/include/opencv4
)
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(mxBase_sample main.cpp ${FCOS_DETECTION} ${FCOS_POSTPROCESS})
target_link_libraries(mxBase_sample
glog
mxbase
cpprest
opencv_world
boost_filesystem
)

View File

@@ -0,0 +1,416 @@
#include "FCOSDetection.h"
#include <sys/stat.h>
#include <unistd.h>
#include <boost/filesystem.hpp>
#include <fstream>
#include "MxBase/DeviceManager/DeviceManager.h"
#include "MxBase/Log/Log.h"
#include "boost/filesystem.hpp"
#include "opencv2/opencv.hpp"
namespace fs = boost::filesystem;
using namespace MxBase;
namespace {
const int RESTENSORF[2] = {100, 5};
const int RESTENSORS[2] = {100, 1};
const int NETINPUTWIDTH = 1333;
const int NETINPUTHEIGHT = 800;
const uint32_t VPC_H_ALIGN = 2;
const uint32_t YUV_BYTE_NU = 3;
const uint32_t YUV_BYTE_DE = 2;
std::string imagePath;
int originImageW;
int originImageH;
float scaleRatio;
int padLeft;
int padRight;
int padTop;
int padBottom;
} // namespace
// load label file.
APP_ERROR FCOSDetection::LoadLabels(const std::string &labelPath,
std::map<int, std::string> &labelMap) {
std::ifstream infile;
// open label file
infile.open(labelPath, std::ios_base::in);
std::string s;
// check label file validity
if (infile.fail()) {
LogError << "Failed to open label file: " << labelPath << ".";
return APP_ERR_COMM_OPEN_FAIL;
}
labelMap.clear();
// construct label map
int count = 0;
while (std::getline(infile, s)) {
if (s.find('#') <= 1) {
continue;
}
size_t eraseIndex = s.find_last_not_of("\r\n\t");
if (eraseIndex != std::string::npos) {
s.erase(eraseIndex + 1, s.size() - eraseIndex);
}
labelMap.insert(std::pair<int, std::string>(count, s));
count++;
}
infile.close();
return APP_ERR_OK;
}
// Set model configuration parameters.
void FCOSDetection::SetFCOSPostProcessConfig(
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("CLASS_NUM", std::to_string(initParam.classNum));
configData.SetJsonValue("INPUT_TYPE", std::to_string(initParam.inputType));
configData.SetJsonValue("CHECK_MODEL", checkTensor);
auto jsonStr = configData.GetCfgJson().serialize();
config["postProcessConfigContent"] = std::make_shared<std::string>(jsonStr);
config["labelPath"] = std::make_shared<std::string>(initParam.labelPath);
}
APP_ERROR FCOSDetection::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;
}
std::map<std::string, std::shared_ptr<void>> config;
SetFCOSPostProcessConfig(initParam, config);
// init FCOSPostprocess
post_ = std::make_shared<FCOSPostProcess>();
ret = post_->Init(config);
if (ret != APP_ERR_OK) {
LogError << "FCOSPostprocess init failed, ret=" << ret << ".";
return ret;
}
// load labels from file
ret = LoadLabels(initParam.labelPath, labelMap_);
if (ret != APP_ERR_OK) {
LogError << "Failed to load labels, ret=" << ret << ".";
return ret;
}
return APP_ERR_OK;
}
APP_ERROR FCOSDetection::DeInit() {
dvppWrapper_->DeInit();
model_->DeInit();
post_->DeInit();
MxBase::DeviceManager::GetInstance()->DestroyDevices();
return APP_ERR_OK;
}
// get the image and send data to TensorBase.
APP_ERROR FCOSDetection::ReadImage(const std::string &imgPath,
MxBase::TensorBase &tensor) {
MxBase::DvppDataInfo inputDataInfo = {};
MxBase::DvppDataInfo output = {};
std::ifstream file(imgPath, std::ios::binary);
// decode the image.
if (!file) {
LogError << "Invalid file.";
}
long fileSize = fs::file_size(imgPath);
std::vector<char> buffer;
buffer.resize(fileSize);
file.read(buffer.data(), fileSize);
file.close();
std::string fileStr(buffer.data(), fileSize);
MxBase::MemoryData hostMemory((void *)fileStr.c_str(), (size_t)fileStr.size(),
MemoryData::MEMORY_HOST, 0);
MxBase::MemoryData dvppMemory(nullptr, (size_t)fileStr.size(),
MemoryData::MEMORY_DVPP, 0);
APP_ERROR ret = MemoryHelper::MxbsMallocAndCopy(dvppMemory, hostMemory);
ret = dvppWrapper_->DvppJpegPredictDecSize(
hostMemory.ptrData, hostMemory.size, inputDataInfo.format,
output.dataSize);
inputDataInfo.dataSize = dvppMemory.size;
inputDataInfo.data = (uint8_t *)dvppMemory.ptrData;
ret = dvppWrapper_->DvppJpegDecode(inputDataInfo, output);
ret = MemoryHelper::Free(dvppMemory);
MxBase::MemoryData memoryData((void *)output.data, output.dataSize,
MxBase::MemoryData::MemoryType::MEMORY_DEVICE,
deviceId_);
// judge the image size after decode.
if (output.heightStride % VPC_H_ALIGN != 0) {
LogError << "Output data height(" << output.heightStride
<< ") can't be divided by " << VPC_H_ALIGN << ".";
MxBase::MemoryHelper::MxbsFree(memoryData);
return APP_ERR_COMM_INVALID_PARAM;
}
std::vector<uint32_t> shape = {
output.heightStride * YUV_BYTE_NU / YUV_BYTE_DE, output.widthStride};
tensor =
MxBase::TensorBase(memoryData, false, shape, MxBase::TENSOR_DTYPE_UINT8);
return APP_ERR_OK;
}
APP_ERROR FCOSDetection::Resize(const MxBase::TensorBase &inputTensor,
MxBase::TensorBase &outputTensor) {
auto shape = inputTensor.GetShape();
MxBase::DvppDataInfo input = {};
// Restore to original size.
input.height = (uint32_t)shape[0] * YUV_BYTE_DE / YUV_BYTE_NU;
input.width = shape[1];
input.heightStride = (uint32_t)shape[0] * YUV_BYTE_DE / YUV_BYTE_NU;
input.widthStride = shape[1];
input.dataSize = inputTensor.GetByteSize();
input.data = (uint8_t *)inputTensor.GetBuffer();
const uint32_t resizeHeight = 800;
const uint32_t resizeWidth = 1333;
MxBase::ResizeConfig resize = {};
resize.height = resizeHeight;
resize.width = resizeWidth;
MxBase::DvppDataInfo output = {};
// resize image
APP_ERROR ret = dvppWrapper_->VpcResize(input, output, resize);
if (ret != APP_ERR_OK) {
LogError << "VpcResize failed, ret=" << ret << ".";
return ret;
}
MxBase::MemoryData memoryData((void *)output.data, output.dataSize,
MxBase::MemoryData::MemoryType::MEMORY_DEVICE,
deviceId_);
// Determine the alignment size of the scaled image.
if (output.heightStride % VPC_H_ALIGN != 0) {
LogError << "Output data height(" << output.heightStride
<< ") can't be divided by " << VPC_H_ALIGN << ".";
MxBase::MemoryHelper::MxbsFree(memoryData);
return APP_ERR_COMM_INVALID_PARAM;
}
shape = {output.heightStride * YUV_BYTE_NU / YUV_BYTE_DE, output.widthStride};
outputTensor =
MxBase::TensorBase(memoryData, false, shape, MxBase::TENSOR_DTYPE_UINT8);
return APP_ERR_OK;
}
// model reasoning
APP_ERROR FCOSDetection::Inference(
const std::vector<MxBase::TensorBase> &inputs,
std::vector<MxBase::TensorBase> &outputs) {
auto dtypes = model_->GetOutputDataType();
/* create room for result
res_tensor[0] is 1*100*5
res_tensor[1] is 1*100*1 */
// create for res_tensor[0]
std::vector<uint32_t> shape1 = {};
shape1.push_back((uint32_t)RESTENSORF[0]);
shape1.push_back((uint32_t)RESTENSORF[1]);
MxBase::TensorBase tensor0(shape1, dtypes[0],
MxBase::MemoryData::MemoryType::MEMORY_DEVICE,
deviceId_);
APP_ERROR ret = MxBase::TensorBase::TensorBaseMalloc(tensor0);
if (ret != APP_ERR_OK) {
LogError << "TensorBaseMalloc failed, ret=" << ret << ".";
return ret;
}
outputs.push_back(tensor0);
// create for res_tensor[1]
std::vector<uint32_t> shape2 = {};
shape2.push_back((uint32_t)RESTENSORS[0]);
shape2.push_back((uint32_t)RESTENSORS[1]);
MxBase::TensorBase tensor1(shape2, dtypes[1],
MxBase::MemoryData::MemoryType::MEMORY_DEVICE,
deviceId_);
ret = MxBase::TensorBase::TensorBaseMalloc(tensor1);
if (ret != APP_ERR_OK) {
LogError << "TensorBaseMalloc failed, ret=" << ret << ".";
return ret;
}
outputs.push_back(tensor1);
MxBase::DynamicInfo dynamicInfo = {};
dynamicInfo.dynamicType = MxBase::DynamicType::STATIC_BATCH;
ret = model_->ModelInference(inputs, outputs, dynamicInfo);
if (ret != APP_ERR_OK) {
LogError << "ModelInference failed, ret=" << ret << ".";
return ret;
}
return APP_ERR_OK;
}
// postprocess.
APP_ERROR FCOSDetection::PostProcess(
const MxBase::TensorBase &tensor,
const std::vector<MxBase::TensorBase> &outputs,
std::vector<std::vector<MxBase::ObjectInfo>> &objInfos) {
// save the resize information.
auto shape = tensor.GetShape();
MxBase::ResizedImageInfo imgInfo;
imgInfo.widthOriginal = shape[1];
imgInfo.heightOriginal = shape[0] * YUV_BYTE_DE / YUV_BYTE_NU;
imgInfo.widthResize = NETINPUTWIDTH;
imgInfo.heightResize = NETINPUTHEIGHT;
imgInfo.resizeType = MxBase::RESIZER_STRETCHING;
std::vector<MxBase::ResizedImageInfo> imageInfoVec = {};
imageInfoVec.push_back(imgInfo);
// use FCOSPostprocess.
APP_ERROR ret = post_->Process(outputs, objInfos, imageInfoVec);
if (ret != APP_ERR_OK) {
LogError << "Process failed, ret=" << ret << ".";
return ret;
}
ret = post_->DeInit();
if (ret != APP_ERR_OK) {
LogError << "FCOSPostprocess DeInit failed";
return ret;
}
return APP_ERR_OK;
}
APP_ERROR FCOSDetection::WriteResult(
MxBase::TensorBase &tensor,
const std::vector<std::vector<MxBase::ObjectInfo>> &objInfos) {
APP_ERROR ret = tensor.ToHost();
if (ret != APP_ERR_OK) {
LogError << "ToHost faile";
return ret;
}
auto shape = tensor.GetShape();
cv::Mat imgBgr = cv::imread(imagePath);
uint32_t batchSize = objInfos.size();
std::vector<MxBase::ObjectInfo> resultInfo;
for (uint32_t i = 0; i < batchSize; 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++) {
const cv::Scalar green = cv::Scalar(0, 255, 0);
const cv::Scalar black = cv::Scalar(0, 0, 0);
const uint32_t thickness = 1;
const uint32_t lineType = 8;
const float fontScale = 1.0;
int newX0 = std::max((int)((resultInfo[j].x0 - padLeft) / scaleRatio), 0);
int newX1 = std::max((int)((resultInfo[j].x1 - padLeft) / scaleRatio), 0);
int newY0 = std::max((int)((resultInfo[j].y0 - padTop) / scaleRatio), 0);
int newY1 = std::max((int)((resultInfo[j].y1 - padTop) / scaleRatio), 0);
int baseline = 0;
const int WIDEBIAS = 15;
const int HEIGHTBIAS = 3;
const int YBIAS = 2;
const float FONT = 3.0;
std::string holdStr = std::to_string(resultInfo[j].confidence * 100.0);
std::string confStr = holdStr.substr(0, holdStr.find(".") + 2 + 1);
confStr = confStr + "% ";
const uint32_t fontFace = cv::FONT_HERSHEY_SCRIPT_COMPLEX;
cv::Point2i c1(newX0, newY0);
cv::Point2i c2(newX1, newY1);
cv::Size sSize = cv::getTextSize(confStr, fontFace, fontScale / 3,
thickness, &baseline);
cv::Size textSize =
cv::getTextSize(labelMap_[((int)resultInfo[j].classId)], fontFace,
fontScale / FONT, thickness, &baseline);
cv::rectangle(imgBgr, c1,
cv::Point(c1.x + textSize.width + WIDEBIAS + sSize.width,
c1.y - textSize.height - HEIGHTBIAS),
green, -1);
// 在图像上绘制文字
cv::putText(imgBgr,
labelMap_[((int)resultInfo[j].classId)] + ": " + confStr,
cv::Point(newX0, newY0 - YBIAS), cv::FONT_HERSHEY_SIMPLEX,
fontScale / FONT, black, thickness, lineType);
// 绘制矩形
cv::rectangle(imgBgr,
cv::Rect(newX0, newY0, newX1 - newX0, newY1 - newY0), green,
thickness);
}
}
cv::imwrite("./result.jpg", imgBgr);
return APP_ERR_OK;
}
APP_ERROR FCOSDetection::Process(const std::string &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;
scaleRatio = (float)NETINPUTWIDTH * 1.0 / (originImageW * 1.0);
float hold = (float)NETINPUTHEIGHT * 1.0 / (originImageH * 1.0);
if (hold < scaleRatio) {
scaleRatio = hold;
}
int newW = (int)originImageW * scaleRatio;
int newH = (int)originImageH * scaleRatio;
cv::Mat newImage;
cv::resize(originImage, newImage, cv::Size(newW, newH), 0, 0, cv::INTER_AREA);
const int PAD = 2;
padLeft = std::max((int)((NETINPUTWIDTH - newW) / PAD), 0);
padTop = std::max((int)((NETINPUTHEIGHT - newH) / PAD), 0);
padRight = std::max(NETINPUTWIDTH - newW - padLeft, 0);
padBottom = std::max(NETINPUTHEIGHT - newH - padTop, 0);
cv::copyMakeBorder(newImage, newImage, padTop, padBottom, padLeft, padRight,
cv::BORDER_CONSTANT, 0);
std::string newImagePath = "./ImageforInfer.jpg";
cv::imwrite(newImagePath, newImage);
MxBase::TensorBase inTensor;
APP_ERROR ret = ReadImage(newImagePath, inTensor);
imagePath = imgPath;
if (ret != APP_ERR_OK) {
LogError << "ReadImage failed, ret=" << ret << ".";
return ret;
}
MxBase::TensorBase outTensor;
ret = Resize(inTensor, outTensor);
if (ret != APP_ERR_OK) {
LogError << "Resize failed, ret=" << ret << ".";
return ret;
}
std::vector<MxBase::TensorBase> inputs = {};
std::vector<MxBase::TensorBase> outputs = {};
inputs.push_back(outTensor);
ret = Inference(inputs, outputs);
if (ret != APP_ERR_OK) {
LogError << "Inference failed, ret=" << ret << ".";
return ret;
}
std::vector<std::vector<MxBase::ObjectInfo>> objInfos;
ret = PostProcess(inTensor, outputs, objInfos);
if (ret != APP_ERR_OK) {
LogError << "PostProcess failed, ret=" << ret << ".";
return ret;
}
ret = WriteResult(inTensor, objInfos);
if (ret != APP_ERR_OK) {
LogError << "Save result failed, ret=" << ret << ".";
return ret;
}
return APP_ERR_OK;
}

View File

@@ -0,0 +1,65 @@
/*
* Copyright(C) 2022. 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_FCOSDETECTION_H
#define MXBASE_FCOSDETECTION_H
#include <FCOSDetectionPostProcess.h>
#include "MxBase/DvppWrapper/DvppWrapper.h"
#include "MxBase/ModelInfer/ModelInferenceProcessor.h"
#include "MxBase/Tensor/TensorContext/TensorContext.h"
struct InitParam {
uint32_t deviceId;
std::string labelPath;
bool checkTensor;
std::string modelPath;
uint32_t classNum;
uint32_t inputType;
};
class FCOSDetection {
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 MxBase::TensorBase &tensor,
const std::vector<MxBase::TensorBase> &outputs,
std::vector<std::vector<MxBase::ObjectInfo>> &objInfos);
APP_ERROR Process(const std::string &imgPath);
protected:
APP_ERROR ReadImage(const std::string &imgPath, MxBase::TensorBase &tensor);
APP_ERROR Resize(const MxBase::TensorBase &inputTensor,
MxBase::TensorBase &outputTensor);
APP_ERROR LoadLabels(const std::string &labelPath,
std::map<int, std::string> &labelMap);
APP_ERROR WriteResult(
MxBase::TensorBase &tensor,
const std::vector<std::vector<MxBase::ObjectInfo>> &objInfos);
void SetFCOSPostProcessConfig(
const InitParam &initParam,
std::map<std::string, std::shared_ptr<void>> &config);
private:
std::shared_ptr<MxBase::DvppWrapper>
dvppWrapper_; // 封装DVPP基本编码、解码、扣图功能
std::shared_ptr<MxBase::ModelInferenceProcessor> model_; // 模型推理功能处理
std::shared_ptr<FCOSPostProcess> post_;
MxBase::ModelDesc modelDesc_ = {}; // 模型描述信息
std::map<int, std::string> labelMap_ = {};
uint32_t deviceId_ = 0;
};
#endif

View File

@@ -0,0 +1,142 @@
/*
* Copyright(C) 2022. 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 "FCOSDetectionPostProcess.h"
#include "MxBase/CV/ObjectDetection/Nms/Nms.h"
#include "MxBase/Log/Log.h"
#include "MxBase/Maths/FastMath.h"
namespace {
const float RATE = 0.3;
const float MINRATE = 0.56;
const uint32_t L = 0;
const uint32_t T = 1;
const uint32_t R = 2;
const uint32_t B = 3;
const int NETINPUTWIDTH = 1333;
const int NETINPUTHEIGHT = 800;
const uint32_t CENTERPOINT = 4;
const float THRESHOLD_ = 0.3;
} // namespace
using namespace MxBase;
FCOSPostProcess &FCOSPostProcess::operator=(const FCOSPostProcess &other) {
if (this == &other) {
return *this;
}
ObjectPostProcessBase::operator=(other);
return *this;
}
APP_ERROR FCOSPostProcess::Init(
const std::map<std::string, std::shared_ptr<void>> &postConfig) {
LogInfo << "Start to Init FCOSDetectionPostProcess";
APP_ERROR ret = ObjectPostProcessBase::Init(postConfig);
if (ret != APP_ERR_OK) {
LogError << GetError(ret)
<< "Fail to superInit in FCOSDetectionPostProcess.";
return ret;
}
LogInfo << "End to Init FCOSDetectionPostProcess.";
return APP_ERR_OK;
}
APP_ERROR FCOSPostProcess::DeInit() { return APP_ERR_OK; }
/*
input:
tensors:the output of mxpi_tensorinfer0 , the output of the model.
objectInfos:save result.
return:
return the postprocess result.
*/
APP_ERROR FCOSPostProcess::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 FCOSDetectionPostProcess.";
APP_ERROR ret = APP_ERR_OK;
auto inputs = tensors;
ret = CheckAndMoveTensors(inputs);
if (ret != APP_ERR_OK) {
LogError << "CheckAndMoveTensors failed. ret=" << ret;
return ret;
}
LogInfo << "FCOSDetectionPostProcess start to write results.";
for (auto num : {0, 1}) {
if (((uint32_t)num >= (uint32_t)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();
if (shape.size() == 0) {
return APP_ERR_OK;
}
LogInfo << "start to process.";
if (tensors[0].GetBuffer() == NULL || tensors[1].GetBuffer() == NULL) {
LogError << "tensors buffer is NULL.\n";
return APP_ERR_OK;
}
std::vector<ObjectInfo> objectInfo;
auto res0 = (float *)tensors[0].GetBuffer();
auto classIdx = (__int64 *)tensors[1].GetBuffer();
auto shape1 = tensors[1].GetShape();
for (uint32_t i = 0; i < shape[1]; i++) {
float *beginRes = res0 + i * 5;
if (*(beginRes + CENTERPOINT) >= THRESHOLD_) {
ObjectInfo objInfo;
objInfo.x0 = *(beginRes + L);
objInfo.y0 = *(beginRes + T);
objInfo.x1 = *(beginRes + R);
objInfo.y1 = *(beginRes + B);
objInfo.confidence = *(beginRes + CENTERPOINT);
objInfo.classId = (float)classIdx[i];
LogInfo << "start postprocessbbox.";
PostprocessBBox(objInfo, resizedImageInfos[0].widthOriginal,
resizedImageInfos[0].heightOriginal, NETINPUTWIDTH,
NETINPUTHEIGHT);
objectInfo.push_back(objInfo);
}
}
MxBase::NmsSort(objectInfo, RATE);
objectInfos.push_back(objectInfo);
LogInfo << "FCOSDetectionPostProcess write results successed.";
LogInfo << "End to Process FCOSDetectionPostProcess.";
return APP_ERR_OK;
}
void FCOSPostProcess::PostprocessBBox(ObjectInfo &objInfo, int imageWidth,
int imageHeight, int netInWidth,
int netInHeight) {
float scale = netInWidth * 1.0 / imageWidth * 1.0;
if (scale > (netInHeight * 1.0 / imageHeight * 1.0)) {
scale = (netInHeight * 1.0 / imageHeight * 1.0);
}
float padW = netInWidth * 1.0 - imageWidth * 1.0 * scale;
float padH = netInHeight * 1.0 - imageHeight * 1.0 * scale;
float padLeft = padW / 2;
float padTop = padH / 2;
objInfo.x0 = (objInfo.x0 - padLeft) / scale;
objInfo.y0 = (objInfo.y0 - padTop) / scale;
objInfo.x1 = (objInfo.x1 - padLeft) / scale;
objInfo.y1 = (objInfo.y1 - padTop) / scale;
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright(C) 2022. 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 FCOS_POST_PROCESS_H
#define FCOS_POST_PROCESS_H
#include "MxBase/CV/ObjectDetection/Nms/Nms.h"
#include "MxBase/PostProcessBases/ObjectPostProcessBase.h"
#include "opencv2/opencv.hpp"
class FCOSPostProcess : public MxBase::ObjectPostProcessBase {
public:
FCOSPostProcess() = default;
~FCOSPostProcess() = default;
FCOSPostProcess(const FCOSPostProcess &other);
APP_ERROR Init(
const std::map<std::string, std::shared_ptr<void>> &postConfig) override;
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>> &configParamMap = {})
override;
FCOSPostProcess &operator=(const FCOSPostProcess &other);
protected:
void PostprocessBBox(MxBase::ObjectInfo &objInfo, int imageWidth,
int imageHeight, int netInWidth, int netInHeight);
private:
uint32_t classNum_ = 0;
bool softmax_ = true;
uint32_t topK_ = 1;
float min_confidence = 0.5;
};
#endif

151
FCOS/README.md Normal file
View File

@@ -0,0 +1,151 @@
# C++基于MxBase的FCOS目标检测
## 1 介绍
本开发样例是基于mxBase开发的端到端推理的C++应用程序可在昇腾芯片上进行FCOS目标检测并把可视化结果保存到本地。其中包含FCOS的后处理模块开发。 该项目的主要处理流程为: Init > ReadImage >Resize > Inference >PostProcess >DeInit。
### 1.1 支持的产品
本产品以昇腾310推理卡为硬件平台。
### 1.2 支持的版本
该项目支持的SDK版本为2.0.4CANN版本为5.0.4。
### 1.3 软件方案介绍
基于C++的FCOS目标检测的业务流程为
1.将待检测的图片放到相应的文件夹下。
2.首先对图片进行预处理(改变图像大小、归一化、填充操作)。
3.将图片传入FCOS类当中。
4.对图片进行推理。
5.对推理的结果进行后处理。
6.最后在目标图片当中绘制目标框以及类别。
| 序号 | 子系统 | 功能描述 |
| ---- | ---------- | ------------------------------------------------------------------------------------------ |
| 1 | 图片输入 | 将图片放到对应的文件夹下 |
| 2 | 图像前处理 | 对图片进行resize、填充以及归一化等。 |
| 3 | 模型推理 | 对已经处理后的图片进行推理,得到推理的张量数据流。 |
| 4 | 模型后处理 | 利用后处理类对图片最后输出的张量进行后处理。对模型输出的目标框进行去重,排序和筛选等工作。 |
| 5 | 绘制目标框 | 将最后的结果绘制到目标图片上。 |
### 1.4 代码目录结构与说明
本项目名为FCOS目标检测项目的目录如下所示
```
|- models
| |- aipp_FCOS.aippconfig //模型转换配置文件
| |_ Fcos_tf_bs.cfg
|- FCOSDection
| |- FCOSDetection.cpp
| |_ FCOSDetection.h
|- FCOSPostprocess
| |- FCOSDetectionPostProcess.cpp
| |_ FCOSDetectionPostProcess.h
|- build.sh
|- CMakeLists.txt
|- main.py
|- binresult
|- evaluate.py
|_ README.md
```
### 1.5 技术实现流程图
![avatar](./image/image1.png)
### 1.6 特性及适用场景
本项目是一个目标检测项目用于检测coco数据集中的80种物体类别。并且在结果输出检测出的物体的置信度和目标框信息。在大多数测试样例中输入的图片物体要清晰并且重叠区域少。另一方面图片的输入的格式要和模型的规定的输入要求相符合。
但是存在以下检测错误的情况:
1.图片过于模糊;
2.图片中物体重合严重;
3.识别的图片长宽不符合要求。
## 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) |
在编译运行项目前,需要设置环境变量:
- 环境变量介绍
```
. /usr/local/Ascend/ascend-toolkit/set_env.sh
. ${SDK安装路径}/mxVision/set_env.sh
```
## 3 模型转换
**步骤一**在ModelZoo上下载FCOS的模型。点击[下载](https://www.hiascend.com/zh/software/modelzoo/models/detail/1/6fcc4747a48245d29351c26cd052dd13)。
**步骤二**将获取到的模型放置到models文件夹中。
**步骤三**:执行模型转换命令。
转换模型
```
atc --model=fcos.onnx --framework=5 --soc_version=Ascend310 --input_format=NCHW --input_shape="input:1,3,800,1333" --output=fcos_bs1 --insert_op_conf=FCOS.aippconfig --precision_mode=force_fp32
```
执行完该命令之后会在models文件夹下生成.om模型并且转换成功之后会在终端输出
```
ATC start working now, please wait for a moment.
ATC run success, welcome to the next use.
```
## 4 编译与运行
**步骤1** 修改CMakeLists.txt文件 将set(MX_SDK_HOME {SDK安装路径}) 中的{SDK安装路径}替换为实际的SDK安装路径。从https://github.com/pjreddie/darknet/blob/master/data/coco.names 下载coco.names,然后将这个文件放到models文件夹下。
**步骤2** cd到FCOS目录下执行如下编译命令 bash build.sh
**步骤3** 制定jpg图片进行推理准备一张推理图片放入FCOS 目录下。
```
./mxBase_sample ./test.jpg
```
## 5 精度测试
本项目和 https://gitee.com/ascend/mindxsdk-referenceapps/tree/master/contrib/FCOS 地址处的项目的模型和后处理过程一样。详细的精度测试参考地址处的项目。
## 6 常见问题
### 6.1 类别标签问题
**问题描述:**
在main.cpp中类别标签路径如下
```c++
void InitFCOSParam(InitParam &initParam)
{
initParam.deviceId = 0;
initParam.labelPath = "./models/coco.names";
initParam.checkTensor = true;
initParam.modelPath = "./models/fcos_bs1.om";
initParam.inputType = 0;
initParam.classNum = CLASS_NU;
}
```
若没有加入标签,报错如下:
![avatar](image/image3.png)
无法运行。
**解决方案:**
这里需要将从网站https://github.com/pjreddie/darknet/blob/master/data/coco.names 处下载相应的标签。

50
FCOS/build.sh Normal file
View File

@@ -0,0 +1,50 @@
# Copyright(C) 2022. 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 check_env()
{
if [ ! "${ASCEND_VERSION}" ]; then
export ASCEND_VERSION=ascend-toolkit/latest
echo "Set ASCEND_VERSION to the default value: ${ASCEND_VERSION}"
else
echo "ASCEND_VERSION is set to ${ASCEND_VERSION} by user"
fi
if [ ! "${ARCH_PATTERN}" ]; then
# set ARCH_PATTERN to ./ when it was not specified by user
export ARCH_PATTERN=./
echo "ARCH_PATTERN is set to the default value: ${ARCH_PATTERN}"
else
echo "ARCH_PATTERN is set to ${ARCH_PATTERN} by user"
fi
}
function build_FCOS()
{
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 FCOS."
exit ${ret}
fi
make install
}
check_env
build_FCOS

BIN
FCOS/image/image1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

BIN
FCOS/image/image2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

BIN
FCOS/image/image3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

62
FCOS/main.cpp Normal file
View File

@@ -0,0 +1,62 @@
/*
* Copyright(C) 2022. 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 <FCOSDetection.h>
#include <iostream>
#include <vector>
#include "MxBase/Log/Log.h"
namespace {
const uint32_t CLASS_NU = 80;
}
void InitFCOSParam(InitParam& initParam) {
initParam.deviceId = 0;
initParam.labelPath = "./models/coco.names";
initParam.checkTensor = true;
initParam.modelPath = "./models/fcos_bs1.om";
initParam.inputType = 0;
initParam.classNum = CLASS_NU;
}
int main(int argc, char* argv[]) {
if (argc <= 1) {
LogWarn << "Please input image path.";
return APP_ERR_OK;
}
InitParam initParam;
InitFCOSParam(initParam);
std::printf("Initialize FCOS param successfully.\n");
auto FCOS = std::make_shared<FCOSDetection>();
// initialize information of model reasoning.
APP_ERROR ret = FCOS->Init(initParam);
if (ret != APP_ERR_OK) {
LogError << "FCOSDetection initialize failed. ";
return ret;
}
std::string imgPath = argv[1];
// start reasoning.
ret = FCOS->Process(imgPath);
if (ret != APP_ERR_OK) {
LogError << "FCOSDetection process failed.";
FCOS->DeInit();
return ret;
}
FCOS->DeInit();
return APP_ERR_OK;
}

View File

@@ -0,0 +1,25 @@
aipp_op {
aipp_mode : static
src_image_size_w : 1344
src_image_size_h : 800
input_format : YUV420SP_U8
csc_switch : true
rbuv_swap_switch : true
crop :true
load_start_pos_w :0
load_start_pos_h :0
crop_size_w :1333
crop_size_h :800
input_bias_0 : 0
input_bias_1 : 128
input_bias_2 : 128
mean_chn_0 : 103
mean_chn_1 : 116
mean_chn_2 : 123
min_chn_0 :0.0
min_chn_1 :0.0
min_chn_2 :0.0
var_reci_chn_0 :1.0
var_reci_chn_1 :1.0
var_reci_chn_2 :1.0
}

View File

@@ -0,0 +1,6 @@
CLASS_NUM=80
SCORE_THRESH=0.05
OBJECTNESS_THRESH=0.2
IOU_THRESH=0.5
MODEL_TYPE=1
FRAMEWORK=Pytorch