Commit 166a5139 authored by change's avatar change
Browse files

init

parents
cmake_minimum_required(VERSION 3.16)
project(YoloV5s_ort)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_COMPILER g++)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -pthread -g")
add_definitions(-DUNICODE -D_UNICODE)
add_definitions("-Wall")
# project include
set(INCLUDE_PATH /usr/local/include
/usr/local/include/opencv4/
${CMAKE_CURRENT_SOURCE_DIR}/include
$ENV{ROCM_PATH}/include
$ENV{ROCM_PATH}/onnxruntime/include/)
include_directories(${INCLUDE_PATH})
# project lib path
set(LIBRARY_PATH /usr/local/lib
${CMAKE_CURRENT_SOURCE_DIR}/lib
$ENV{ROCM_PATH}/lib)
link_directories(${LIBRARY_PATH})
# project lib
set(LIBRARY opencv_core opencv_imgproc opencv_imgcodecs opencv_dnn opencv_highgui opencv_videoio
onnxruntime)
link_libraries(${LIBRARY})
# project source files
file(GLOB _SRC ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
set(_COMPILE_CODE ${_SRC})
add_executable(yolov5 ${_COMPILE_CODE})
# YoloV5
## 论文
## 模型结构
YOLOv5 是一种目标检测算法,采用单阶段(one-stage)的方法,基于轻量级的卷积神经网络结构,通过引入不同尺度的特征融合和特征金字塔结构来实现高效准确的目标检测。
![Backbone](Backbone.png)
## 算法原理
YOLOv5 是一种基于单阶段目标检测算法,通过将图像划分为不同大小的网格,预测每个网格中的目标类别和边界框,利用特征金字塔结构和自适应的模型缩放来实现高效准确的实时目标检测。
![Algorithm_principle](Algorithm_principle.png)
## 环境配置
### Docker(方法一)
拉取镜像:
```
docker pull image.sourcefind.cn:5000/dcu/admin/base/custom:opencv49_ffmpeg4.2.1_ubuntu20.04-dtk24.04.2
```
创建并启动容器:
```
docker run -it --network=host --ipc=host --name=yolov5s_ort --privileged --hostname localhost --shm-size=16G --device=/dev/kfd --device=/dev/mkfd --device=/dev/dri -v /opt/hyhal:/opt/hyhal:ro -v /your_code_path:/your_code_path --group-add video --cap-add=SYS_PTRACE --security-opt seccomp=unconfined 99d476c02fdd /bin/bash
```
## 数据集
无,使用提供的案例图像进行测试
## 推理
### 编译工程
```
git clone http://developer.sourcefind.cn/codes/modelzoo/yolov5s_onnxruntime.git
cd yolov5s_onnxruntime
mkdir build && cd build
cmake ../
make
```
### 运行示例
```
./yolov5
```
## result
该项目为多batch推理,单张图片推理结果如下,所有推理结果位于./build/下:
![img](bus.jpg)
### 精度
## 应用场景
### 算法类别
目标检测
### 热点应用行业
监控,交通,教育
## 源码仓库及问题反馈
- http://developer.hpccube.com/codes/modelzoo/video_ort.git
## 参考资料
- https://github.com/WongKinYiu/yolov7
person
bicycle
car
motorbike
aeroplane
bus
train
truck
boat
traffic light
fire hydrant
stop sign
parking meter
bench
bird
cat
dog
horse
sheep
cow
elephant
bear
zebra
giraffe
backpack
umbrella
handbag
tie
suitcase
frisbee
skis
snowboard
sports ball
kite
baseball bat
baseball glove
skateboard
surfboard
tennis racket
bottle
wine glass
cup
fork
knife
spoon
bowl
banana
apple
sandwich
orange
broccoli
carrot
hot dog
pizza
donut
cake
chair
sofa
pottedplant
bed
diningtable
toilet
tvmonitor
laptop
mouse
remote
keyboard
cell phone
microwave
oven
toaster
sink
refrigerator
book
clock
vase
scissors
teddy bear
hair drier
toothbrush
bus.jpg

481 KB

icon.png

77.3 KB

#ifndef __COMMON_UTILS_H__
#define __COMMON_UTILS_H__
#include <opencv2/core.hpp>
#include <onnxruntime_cxx_api.h>
#include <numeric>
#include <sys/stat.h>
std::vector<float> substractMeanNormalize(cv::Mat &src, const float *meanVals, const float *normVals);
std::vector<Ort::AllocatedStringPtr> getInputNames(Ort::Session *session);
std::vector<int64_t> getInputDim(Ort::Session *session);
std::vector<Ort::AllocatedStringPtr> getOutputNames(Ort::Session *session);
std::string getSrcImgFilePath(const char *path, const char *imgName);
#endif
// YOLOV5检测器
#ifndef __DETECTOR_YOLOV5_H__
#define __DETECTOR_YOLOV5_H__
#include <string>
#include <fstream>
#include <onnxruntime_cxx_api.h>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include "CommonUtils.h"
using namespace std;
using namespace cv;
typedef struct _ResultOfDetection
{
Rect boundingBox;
float confidence;
int classID;
string className;
bool exist;
_ResultOfDetection():confidence(0.0f),classID(0),exist(true){}
}ResultOfDetection;
class DetectorYOLOV5
{
public:
~DetectorYOLOV5();
void setNumThread(int numOfThread);
// 设置dcu索引
void setGpuIndex(int gpuIndex);
// 初始化模型
void initModel(const std::string &pathStr, const std::string &pathOfClassNameFile);
// 前处理+推理
void Detect(std::vector<cv::Mat> originSrc, std::vector<cv::String> imageNames);
// 后处理
void postprocess(cv::Mat& floatarray, const cv::Mat& originSrc, const cv::Size& inputSize, std::vector<ResultOfDetection>& resultsOfDetection, cv::String& imageName);
// 获取输入节点维度
std::vector<int64_t> getshape();
private:
Ort::Session *session;
Ort::Env env = Ort::Env(ORT_LOGGING_LEVEL_ERROR, "Yolov5");
Ort::SessionOptions sessionOptions = Ort::SessionOptions();
int numThread = 0;
vector<string> classNames;
std::vector<int64_t> inputDim;
std::vector<Ort::AllocatedStringPtr> inputNamesPtr;
std::vector<Ort::AllocatedStringPtr> outputNamesPtr;
const float meanValues[3] = {0, 0, 0};
const float normValues[3] = {1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0};
};
#endif
// 示例程序
#ifndef __MAIN_H__
#define __MAIN_H__
// YOLOV5 sample
void Ort_DetectorYOLOV5();
#endif
File added
# 模型唯一标识
modelCode = 505
# 模型名称
modelName=yolov5s_onnxruntime
# 模型描述
modelDescription=yolov5s使用onnxruntime实现推理,支持多batch,本案例中batch大小为4
# 应用场景
appScenario=推理,目标检测,监控,交通,教育
# 框架类型
frameType=onnxruntime
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <numeric>
#include "CommonUtils.h"
std::vector<float> substractMeanNormalize(cv::Mat &src, const float *meanVals, const float *normVals) {
auto inputTensorSize = src.cols * src.rows * src.channels();
std::vector<float> inputTensorValues(inputTensorSize);
size_t numChannels = src.channels();
size_t imageSize = src.cols * src.rows;
for (size_t pid = 0; pid < imageSize; pid++) {
for (size_t ch = 0; ch < numChannels; ++ch) {
float data = (float) (src.data[pid * numChannels + ch] * normVals[ch] - meanVals[ch] * normVals[ch]);
inputTensorValues[ch * imageSize + pid] = data;
}
}
return inputTensorValues;
}
std::vector<Ort::AllocatedStringPtr> getInputNames(Ort::Session *session) {
Ort::AllocatorWithDefaultOptions allocator;
const size_t numInputNodes = session->GetInputCount();
std::vector<Ort::AllocatedStringPtr> inputNamesPtr;
inputNamesPtr.reserve(numInputNodes);
std::vector<int64_t> input_node_dims;
// iterate over all input nodes
for (size_t i = 0; i < numInputNodes; i++) {
auto inputName = session->GetInputNameAllocated(i, allocator);
inputNamesPtr.push_back(std::move(inputName));
/*printf("inputName[%zu] = %s\n", i, inputName.get());
// print input node types
auto typeInfo = session->GetInputTypeInfo(i);
auto tensorInfo = typeInfo.GetTensorTypeAndShapeInfo();
ONNXTensorElementDataType type = tensorInfo.GetElementType();
printf("inputType[%zu] = %u\n", i, type);
// print input shapes/dims
input_node_dims = tensorInfo.GetShape();
printf("Input num_dims = %zu\n", input_node_dims.size());
for (size_t j = 0; j < input_node_dims.size(); j++) {
printf("Input dim[%zu] = %llu\n",j, input_node_dims[j]);
}*/
}
return inputNamesPtr;
}
std::vector<int64_t> getInputDim(Ort::Session *session)
{
std::vector<int64_t> input_node_dims;
auto typeInfo = session->GetInputTypeInfo(0);
auto tensorInfo = typeInfo.GetTensorTypeAndShapeInfo();
input_node_dims = tensorInfo.GetShape();
return input_node_dims;
}
std::vector<Ort::AllocatedStringPtr> getOutputNames(Ort::Session *session) {
Ort::AllocatorWithDefaultOptions allocator;
const size_t numOutputNodes = session->GetOutputCount();
std::vector<Ort::AllocatedStringPtr> outputNamesPtr;
outputNamesPtr.reserve(numOutputNodes);
std::vector<int64_t> output_node_dims;
for (size_t i = 0; i < numOutputNodes; i++) {
auto outputName = session->GetOutputNameAllocated(i, allocator);
outputNamesPtr.push_back(std::move(outputName));
/*printf("outputName[%zu] = %s\n", i, outputName.get());
// print input node types
auto type_info = session->GetOutputTypeInfo(i);
auto tensor_info = type_info.GetTensorTypeAndShapeInfo();
ONNXTensorElementDataType type = tensor_info.GetElementType();
printf("outputType[%zu] = %u\n", i, type);
// print input shapes/dims
output_node_dims = tensor_info.GetShape();
printf("output num_dims = %zu\n", output_node_dims.size());
for (size_t j = 0; j < output_node_dims.size(); j++) {
printf("output dim[%zu] = %llu\n",j, output_node_dims[j]);
}*/
}
return outputNamesPtr;
}
std::string getSrcImgFilePath(const char *path, const char *imgName) {
std::string filePath;
filePath.append(path).append(imgName);
return filePath;
}
#include "DetectorYOLOV5.h"
#include <filesystem>
using namespace std;
using namespace cv::dnn;
namespace fs = std::filesystem;
DetectorYOLOV5::~DetectorYOLOV5()
{
delete session;
inputNamesPtr.clear();
outputNamesPtr.clear();
}
void DetectorYOLOV5::setGpuIndex(int gpuIndex)
{
if (gpuIndex >= 0) {
OrtROCMProviderOptions rocm_options;
rocm_options.device_id = gpuIndex;
rocm_options.arena_extend_strategy = 0;
rocm_options.miopen_conv_exhaustive_search = 0;
rocm_options.do_copy_in_default_stream = 1;
sessionOptions.AppendExecutionProvider_ROCM(rocm_options);
}
else {
printf("det use CPU\n");
}
}
void DetectorYOLOV5::setNumThread(int numOfThread)
{
numThread = numOfThread;
sessionOptions.SetInterOpNumThreads(numThread);
sessionOptions.SetGraphOptimizationLevel(GraphOptimizationLevel::ORT_ENABLE_BASIC);
}
void DetectorYOLOV5::initModel(const std::string &pathStr, const std::string &pathOfClassNameFile)
{
fprintf(stdout, "Start init model for %s\n", pathStr.c_str());
session = new Ort::Session(env, pathStr.c_str(), sessionOptions);
inputDim = getInputDim(session);
inputNamesPtr = getInputNames(session);
outputNamesPtr = getOutputNames(session);
std::ifstream classNameFile(pathOfClassNameFile);
string line;
while (getline(classNameFile, line))
{
classNames.push_back(line);
}
}
std::vector<int64_t> DetectorYOLOV5::getshape()
{
return this->inputDim;
}
void DetectorYOLOV5::Detect(std::vector<cv::Mat> originSrc, std::vector<cv::String> imageNames)
{
std::vector<ResultOfDetection> resultsOfDetection;
cv::Size inputSize = cv::Size(inputDim[3], inputDim[2]);
int batch_num = originSrc.size();
std::vector<float> inputTensorData;
// size_t size = inputTensorData.size();
int imgchannels = 3;
for(int nbatch = 0; nbatch < batch_num; nbatch++)
{
cv::Mat src = originSrc[nbatch];
cv::Mat srcresize;
cv::resize(src, srcresize, inputSize, 0, 0, cv::INTER_LINEAR);
// cv::Mat srcresize = src;
std::vector<float> inputTensorValues = substractMeanNormalize(srcresize, meanValues, normValues);
inputTensorData.insert(inputTensorData.end(),inputTensorValues.begin(), inputTensorValues.end());
}
std::array<int64_t, 4> inputShape{batch_num, imgchannels, inputDim[2], inputDim[3]};
auto memoryInfo = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU);
Ort::Value inputTensor = Ort::Value::CreateTensor<float>(memoryInfo, inputTensorData.data(), inputTensorData.size(), inputShape.data(), inputShape.size());
std::vector<const char *> inputNames = {inputNamesPtr.data()->get()};
std::vector<const char *> outputNames = {outputNamesPtr.data()->get()};
// 推理
auto outputTensor = session->Run(Ort::RunOptions{nullptr}, inputNames.data(), &inputTensor, inputNames.size(), outputNames.data(), outputNames.size());
// 获取推理结果
std::vector<cv::Mat> outs;
std::vector<int64_t> outputShape = outputTensor[0].GetTensorTypeAndShapeInfo().GetShape();
float *floatArray = outputTensor.front().GetTensorMutableData<float>();
// 转换为cv::Mat
int shape[]={static_cast<int>(outputShape[0]), static_cast<int>(outputShape[1]), static_cast<int>(outputShape[2])};
cv::Mat out(3, shape, CV_32F, floatArray);
float* resptr = out.ptr<float>(0);
outs.push_back(out);
for(int batch = 0; batch < batch_num; batch++)
{
cv::String imageName = imageNames[batch];
float* dataptr = resptr + batch * out.size[1] * out.size[2];
int shape_b1[] = {1, out.size[1], out.size[2]};
cv::Mat batch_image(3, shape_b1, CV_32F, dataptr);
postprocess(batch_image, originSrc[batch], inputSize, resultsOfDetection, imageName);
}
}
void DetectorYOLOV5::postprocess(cv::Mat& res, const cv::Mat& originSrc, const cv::Size& inputSize, std::vector<ResultOfDetection> &resultsOfDetection, cv::String& imageName)
{
//获取先验框的个数
int numProposal = res.size[1];
cout << "numProposal: " << numProposal << endl;
//每个先验框的信息(85=80个类别概率+4个预测框+1对象得分)
int numOut = res.size[2];
cout << "numOut: " << numOut << endl;
//变换输出的维度
res = res.reshape(0, numProposal);
//生成先验框
std::vector<float> confidences;
std::vector<cv::Rect> boxes;
std::vector<int> classIds;
float ratioh = (float)originSrc.rows / inputSize.height;
float ratiow = (float)originSrc.cols / inputSize.width;
//计算cx,cy,w,h,box_sore,class_sore
int n = 0, rowInd = 0;
float* pdata = (float*)res.data;
for (n = 0; n < numProposal; n++)
{
float boxScores = pdata[4];
if (boxScores > 0.5)
{
cv::Mat scores = res.row(rowInd).colRange(5, numOut);
cv::Point classIdPoint;
double maxClassScore;
cv::minMaxLoc(scores, 0, &maxClassScore, 0, &classIdPoint);
maxClassScore *= boxScores;
if (maxClassScore > 0.25)
{
const int classIdx = classIdPoint.x;
float cx = pdata[0] * ratiow;
float cy = pdata[1] * ratioh;
float w = pdata[2] * ratiow;
float h = pdata[3] * ratioh;
int left = int(cx - 0.5 * w);
int top = int(cy - 0.5 * h);
confidences.push_back((float)maxClassScore);
boxes.push_back(cv::Rect(left, top, (int)(w), (int)(h)));
classIds.push_back(classIdx);
}
}
rowInd++;
pdata += numOut;
}
//执行nms消除冗余重叠boxes
std::vector<int> indices;
dnn::NMSBoxes(boxes, confidences, 0.25, 0.5, indices);
for (size_t i = 0; i < indices.size(); ++i)
{
int idx = indices[i];
int classID=classIds[idx];
string className=classNames[classID];
float confidence=confidences[idx];
cv::Rect box = boxes[idx];
ResultOfDetection result;
result.boundingBox=box;
result.confidence=confidence;// confidence
result.classID=classID; // label
result.className=className;
resultsOfDetection.push_back(result);
}
cout << "num of boxes: " << resultsOfDetection.size() << endl;
fprintf(stdout,"//////////////Detection Results//////////////\n");
for( size_t i = 0; i < resultsOfDetection.size(); ++i)
{
ResultOfDetection result = resultsOfDetection[i];
cv::rectangle(originSrc, result.boundingBox, Scalar(0,255,255),2);
cv::putText(originSrc, result.className, cv::Point(result.boundingBox.x, result.boundingBox.y-20), cv::FONT_HERSHEY_PLAIN, 2.0, Scalar(0, 0, 255), 2);
fprintf(stdout,"box:%d %d %d %d,label:%d,confidence:%.3f\n",result.boundingBox.x,
result.boundingBox.y,result.boundingBox.width,result.boundingBox.height,result.classID,result.confidence);
}
fs::path path(imageName);
fs::path filename = path.filename();
fs::path outpath = fs::path("../build") / filename;
cv::imwrite(outpath.string(), originSrc);
resultsOfDetection.clear();
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment