Commit a5e2341e authored by yaoht's avatar yaoht
Browse files

fix cpp inputdata channel range problem

parent e80d6c72
#include <Filesystem.h>
#include <SimpleLog.h>
#include <YOLOX.h> #include <YOLOX.h>
#include <migraphx/onnx.hpp>
#include <migraphx/gpu/target.hpp> #include <migraphx/gpu/target.hpp>
#include <migraphx/onnx.hpp>
#include <migraphx/quantization.hpp> #include <migraphx/quantization.hpp>
#include <Filesystem.h>
#include <SimpleLog.h>
#define INPUT_W (640)
#define INPUT_H (640)
namespace migraphxSamples
{
DetectorYOLOX::DetectorYOLOX()
{
} namespace migraphxSamples {
DetectorYOLOX::~DetectorYOLOX()
{
configurationFile.release(); DetectorYOLOX::DetectorYOLOX() {}
} DetectorYOLOX::~DetectorYOLOX() { configurationFile.release(); }
ErrorCode DetectorYOLOX::Initialize(InitializationParameterOfDetector initializationParameterOfDetector, bool dynamic) ErrorCode DetectorYOLOX::Initialize(
{ InitializationParameterOfDetector initializationParameterOfDetector) {
// 读取配置文件 // 读取配置文件
std::string configFilePath=initializationParameterOfDetector.configFilePath; std::string configFilePath =
if(Exists(configFilePath)==false) initializationParameterOfDetector.configFilePath;
{ if (!Exists(configFilePath)) {
LOG_ERROR(stdout, "no configuration file!\n"); LOG_ERROR(stdout, "no configuration file!\n");
return CONFIG_FILE_NOT_EXIST; return CONFIG_FILE_NOT_EXIST;
} }
if(!configurationFile.open(configFilePath, cv::FileStorage::READ)) if (!configurationFile.open(configFilePath, cv::FileStorage::READ)) {
{
LOG_ERROR(stdout, "fail to open configuration file\n"); LOG_ERROR(stdout, "fail to open configuration file\n");
return FAIL_TO_OPEN_CONFIG_FILE; return FAIL_TO_OPEN_CONFIG_FILE;
} }
...@@ -41,165 +28,109 @@ ErrorCode DetectorYOLOX::Initialize(InitializationParameterOfDetector initializa ...@@ -41,165 +28,109 @@ ErrorCode DetectorYOLOX::Initialize(InitializationParameterOfDetector initializa
// 获取配置文件参数 // 获取配置文件参数
cv::FileNode netNode = configurationFile["DetectorYOLOX"]; cv::FileNode netNode = configurationFile["DetectorYOLOX"];
if(dynamic) modelPath = (std::string)netNode["ModelPathStatic"];
{ std::string pathOfClassNameFile = (std::string)netNode["ClassNameFile"];
modelPath=(std::string)netNode["ModelPathDynamic"];
}
else
{
modelPath=(std::string)netNode["ModelPathStatic"];
}
std::string pathOfClassNameFile=(std::string)netNode["ClassNameFile"];
yoloxParameter.confidenceThreshold = (float)netNode["ConfidenceThreshold"]; yoloxParameter.confidenceThreshold = (float)netNode["ConfidenceThreshold"];
yoloxParameter.nmsThreshold = (float)netNode["NMSThreshold"]; yoloxParameter.nmsThreshold = (float)netNode["NMSThreshold"];
yoloxParameter.objectThreshold = (float)netNode["ObjectThreshold"]; yoloxParameter.objectThreshold = (float)netNode["ObjectThreshold"];
yoloxParameter.numberOfClasses=(int)netNode["NumberOfClasses"]; yoloxParameter.numberOfClasses = (int)netNode["NumberOfClasses"];
useFP16=(bool)(int)netNode["UseFP16"]; useFP16 = (bool)(int)netNode["UseFP16"];
if(dynamic)
{
// 加载模型
if(Exists(modelPath)==false)
{
LOG_ERROR(stdout,"%s not exist!\n",modelPath.c_str());
return MODEL_NOT_EXIST;
}
migraphx::onnx_options onnx_options;
onnx_options.map_input_dims["images"]={1,3,800,800};
net = migraphx::parse_onnx(modelPath, onnx_options);
LOG_INFO(stdout,"succeed to load model: %s\n",GetFileName(modelPath).c_str());
// 获取模型输入/输出节点信息
std::cout<<"inputs:"<<std::endl;
std::unordered_map<std::string, migraphx::shape> inputs=net.get_inputs();
for(auto i:inputs)
{
std::cout<<i.first<<":"<<i.second<<std::endl;
}
std::cout<<"outputs:"<<std::endl;
std::unordered_map<std::string, migraphx::shape> outputs=net.get_outputs();
for(auto i:outputs)
{
std::cout<<i.first<<":"<<i.second<<std::endl;
}
inputName=inputs.begin()->first;
inputShape=inputs.begin()->second;
int N=inputShape.lens()[0];
int C=inputShape.lens()[1];
int H=inputShape.lens()[2];
int W=inputShape.lens()[3];
inputSize=cv::Size(W,H);
// log
LOG_INFO(stdout,"InputMaxSize:%dx%d\n",inputSize.width,inputSize.height);
}
else
{
// 加载模型 // 加载模型
if(Exists(modelPath)==false) if (!Exists(modelPath)) {
{ LOG_ERROR(stdout, "%s not exist!\n", modelPath.c_str());
LOG_ERROR(stdout,"%s not exist!\n",modelPath.c_str());
return MODEL_NOT_EXIST; return MODEL_NOT_EXIST;
} }
net = migraphx::parse_onnx(modelPath); net = migraphx::parse_onnx(modelPath);
LOG_INFO(stdout,"succeed to load model: %s\n",GetFileName(modelPath).c_str()); LOG_INFO(stdout, "succeed to load model: %s\n",
GetFileName(modelPath).c_str());
// 获取模型输入/输出节点信息 // 获取模型输入/输出节点信息
std::cout<<"inputs:"<<std::endl; std::cout << "inputs:" << std::endl;
std::unordered_map<std::string, migraphx::shape> inputs=net.get_inputs(); std::unordered_map<std::string, migraphx::shape> inputs = net.get_inputs();
for(auto i:inputs) for (auto i : inputs) {
{ std::cout << i.first << ":" << i.second << std::endl;
std::cout<<i.first<<":"<<i.second<<std::endl; }
} std::cout << "outputs:" << std::endl;
std::cout<<"outputs:"<<std::endl; std::unordered_map<std::string, migraphx::shape> outputs =
std::unordered_map<std::string, migraphx::shape> outputs=net.get_outputs(); net.get_outputs();
for(auto i:outputs) for (auto i : outputs) {
{ std::cout << i.first << ":" << i.second << std::endl;
std::cout<<i.first<<":"<<i.second<<std::endl; }
} inputName = inputs.begin()->first;
inputName=inputs.begin()->first; inputShape = inputs.begin()->second;
inputShape=inputs.begin()->second; int N = inputShape.lens()[0];
int N=inputShape.lens()[0]; int C = inputShape.lens()[1];
int C=inputShape.lens()[1]; int H = inputShape.lens()[2];
int H=inputShape.lens()[2]; int W = inputShape.lens()[3];
int W=inputShape.lens()[3]; inputSize = cv::Size(W, H);
inputSize=cv::Size(W,H);
// log // log
LOG_INFO(stdout,"InputSize:%dx%d\n",inputSize.width,inputSize.height); LOG_INFO(stdout, "InputSize:%dx%d\n", inputSize.width, inputSize.height);
}
LOG_INFO(stdout,"InputName:%s\n",inputName.c_str()); LOG_INFO(stdout, "InputName:%s\n", inputName.c_str());
LOG_INFO(stdout,"ConfidenceThreshold:%f\n",yoloxParameter.confidenceThreshold); LOG_INFO(stdout, "ConfidenceThreshold:%f\n",
LOG_INFO(stdout,"NMSThreshold:%f\n",yoloxParameter.nmsThreshold); yoloxParameter.confidenceThreshold);
LOG_INFO(stdout,"objectThreshold:%f\n",yoloxParameter.objectThreshold); LOG_INFO(stdout, "NMSThreshold:%f\n", yoloxParameter.nmsThreshold);
LOG_INFO(stdout,"NumberOfClasses:%d\n",yoloxParameter.numberOfClasses); LOG_INFO(stdout, "objectThreshold:%f\n", yoloxParameter.objectThreshold);
LOG_INFO(stdout, "NumberOfClasses:%d\n", yoloxParameter.numberOfClasses);
// 设置模型为GPU模式 // 设置模型为GPU模式
migraphx::target gpuTarget = migraphx::gpu::target{}; migraphx::target gpuTarget = migraphx::gpu::target{};
// 量化 // 量化
if(useFP16) if (useFP16) {
{
migraphx::quantize_fp16(net); migraphx::quantize_fp16(net);
} }
// 编译模型 // 编译模型
migraphx::compile_options options; migraphx::compile_options options;
options.device_id=0; options.device_id = 0;
options.offload_copy=true; options.offload_copy = true;
net.compile(gpuTarget,options); net.compile(gpuTarget, options);
LOG_INFO(stdout,"succeed to compile model: %s\n",GetFileName(modelPath).c_str()); LOG_INFO(stdout, "succeed to compile model: %s\n",
GetFileName(modelPath).c_str());
// warm up // warm up
std::unordered_map<std::string, migraphx::argument> inputData; std::unordered_map<std::string, migraphx::argument> inputData;
inputData[inputName]=migraphx::argument{inputShape}; inputData[inputName] = migraphx::argument{inputShape};
net.eval(inputData); net.eval(inputData);
// 读取类别名 // 读取类别名
if(!pathOfClassNameFile.empty()) if (!pathOfClassNameFile.empty()) {
{
std::ifstream classNameFile(pathOfClassNameFile); std::ifstream classNameFile(pathOfClassNameFile);
std::string line; std::string line;
while (getline(classNameFile, line)) while (getline(classNameFile, line)) {
{
classNames.push_back(line); classNames.push_back(line);
} }
} } else {
else
{
classNames.resize(yoloxParameter.numberOfClasses); classNames.resize(yoloxParameter.numberOfClasses);
} }
return SUCCESS; return SUCCESS;
} }
void DetectorYOLOX::generate_grids_and_stride(std::vector<int>& strides, std::vector<GridAndStride>& grid_strides) void DetectorYOLOX::generate_grids_and_stride(
{ std::vector<int> &strides, std::vector<GridAndStride> &grid_strides,
for (auto stride : strides) cv::Size inputSize) {
{ for (auto stride : strides) {
int num_grid_y = INPUT_H / stride; int num_grid_y = inputSize.height / stride;
int num_grid_x = INPUT_W / stride; int num_grid_x = inputSize.width / stride;
for (int g1 = 0; g1 < num_grid_y; g1++) for (int g1 = 0; g1 < num_grid_y; g1++) {
{ for (int g0 = 0; g0 < num_grid_x; g0++) {
for (int g0 = 0; g0 < num_grid_x; g0++)
{
grid_strides.push_back((GridAndStride){g0, g1, stride}); grid_strides.push_back((GridAndStride){g0, g1, stride});
} }
} }
} }
} }
void DetectorYOLOX::generate_yolox_proposals(std::vector<GridAndStride> grid_strides, float* feat_blob, float prob_threshold, std::vector<Object>& objects) void DetectorYOLOX::generate_yolox_proposals(
{ std::vector<GridAndStride> grid_strides, float *feat_blob,
float prob_threshold, std::vector<Object> &objects) {
const int num_anchors = grid_strides.size(); const int num_anchors = grid_strides.size();
float max_box_objectness =0; float max_box_objectness = 0;
for (int anchor_idx = 0; anchor_idx < num_anchors; anchor_idx++) for (int anchor_idx = 0; anchor_idx < num_anchors; anchor_idx++) {
{
const int grid0 = grid_strides[anchor_idx].grid0; const int grid0 = grid_strides[anchor_idx].grid0;
const int grid1 = grid_strides[anchor_idx].grid1; const int grid1 = grid_strides[anchor_idx].grid1;
const int stride = grid_strides[anchor_idx].stride; const int stride = grid_strides[anchor_idx].stride;
...@@ -207,30 +138,31 @@ void DetectorYOLOX::generate_yolox_proposals(std::vector<GridAndStride> grid_str ...@@ -207,30 +138,31 @@ void DetectorYOLOX::generate_yolox_proposals(std::vector<GridAndStride> grid_str
const int basic_pos = anchor_idx * (yoloxParameter.numberOfClasses + 5); const int basic_pos = anchor_idx * (yoloxParameter.numberOfClasses + 5);
// yolox/models/yolo_head.py decode logic // yolox/models/yolo_head.py decode logic
float x_center = (feat_blob[basic_pos+0] + grid0) * stride; float x_center = (feat_blob[basic_pos + 0] + grid0) * stride;
float y_center = (feat_blob[basic_pos+1] + grid1) * stride; float y_center = (feat_blob[basic_pos + 1] + grid1) * stride;
float w = exp(feat_blob[basic_pos+2]) * stride; float w = exp(feat_blob[basic_pos + 2]) * stride;
float h = exp(feat_blob[basic_pos+3]) * stride; float h = exp(feat_blob[basic_pos + 3]) * stride;
float x0 = x_center - w * 0.5f; float x0 = x_center - w * 0.5f;
float y0 = y_center - h * 0.5f; float y0 = y_center - h * 0.5f;
float box_objectness = feat_blob[basic_pos+4]; float box_objectness = feat_blob[basic_pos + 4];
max_box_objectness = box_objectness > max_box_objectness ? box_objectness : max_box_objectness; max_box_objectness = box_objectness > max_box_objectness
? box_objectness
: max_box_objectness;
float max_box_cls_score = 0; float max_box_cls_score = 0;
int max_score_class_idx = 0; int max_score_class_idx = 0;
for (int class_idx = 0; class_idx < yoloxParameter.numberOfClasses; class_idx++) for (int class_idx = 0; class_idx < yoloxParameter.numberOfClasses;
{ class_idx++) {
float box_cls_score = feat_blob[basic_pos + 5 + class_idx]; float box_cls_score = feat_blob[basic_pos + 5 + class_idx];
if(box_cls_score > max_box_cls_score) if (box_cls_score > max_box_cls_score) {
{
max_box_cls_score = box_cls_score; max_box_cls_score = box_cls_score;
max_score_class_idx = class_idx; max_score_class_idx = class_idx;
} }
} // class loop } // class loop
float box_prob = box_objectness * max_box_cls_score; float box_prob = box_objectness * max_box_cls_score;
if(box_objectness > yoloxParameter.objectThreshold && box_prob > yoloxParameter.confidenceThreshold) if (box_objectness > yoloxParameter.objectThreshold &&
{ box_prob > yoloxParameter.confidenceThreshold) {
Object obj; Object obj;
obj.rect.x = x0; obj.rect.x = x0;
obj.rect.y = y0; obj.rect.y = y0;
...@@ -243,22 +175,20 @@ void DetectorYOLOX::generate_yolox_proposals(std::vector<GridAndStride> grid_str ...@@ -243,22 +175,20 @@ void DetectorYOLOX::generate_yolox_proposals(std::vector<GridAndStride> grid_str
} // point anchor loop } // point anchor loop
} }
void DetectorYOLOX::qsort_descent_inplace(std::vector<Object>& faceobjects, int left, int right) void DetectorYOLOX::qsort_descent_inplace(std::vector<Object> &faceobjects,
{ int left, int right) {
int i = left; int i = left;
int j = right; int j = right;
float p = faceobjects[(left + right) / 2].prob; float p = faceobjects[(left + right) / 2].prob;
while (i <= j) while (i <= j) {
{
while (faceobjects[i].prob > p) while (faceobjects[i].prob > p)
i++; i++;
while (faceobjects[j].prob < p) while (faceobjects[j].prob < p)
j--; j--;
if (i <= j) if (i <= j) {
{
// swap // swap
std::swap(faceobjects[i], faceobjects[j]); std::swap(faceobjects[i], faceobjects[j]);
...@@ -267,53 +197,52 @@ void DetectorYOLOX::qsort_descent_inplace(std::vector<Object>& faceobjects, int ...@@ -267,53 +197,52 @@ void DetectorYOLOX::qsort_descent_inplace(std::vector<Object>& faceobjects, int
} }
} }
#pragma omp parallel sections #pragma omp parallel sections
{ {
#pragma omp section #pragma omp section
{ {
if (left < j) qsort_descent_inplace(faceobjects, left, j); if (left < j)
qsort_descent_inplace(faceobjects, left, j);
} }
#pragma omp section #pragma omp section
{ {
if (i < right) qsort_descent_inplace(faceobjects, i, right); if (i < right)
qsort_descent_inplace(faceobjects, i, right);
} }
} }
} }
void DetectorYOLOX::qsort_descent_inplace(std::vector<Object>& objects) void DetectorYOLOX::qsort_descent_inplace(std::vector<Object> &objects) {
{
if (objects.empty()) if (objects.empty())
return; return;
qsort_descent_inplace(objects, 0, objects.size() - 1); qsort_descent_inplace(objects, 0, objects.size() - 1);
} }
inline float DetectorYOLOX::intersection_area(const Object& a, const Object& b) inline float DetectorYOLOX::intersection_area(const Object &a,
{ const Object &b) {
cv::Rect_<float> inter = a.rect & b.rect; cv::Rect_<float> inter = a.rect & b.rect;
return inter.area(); return inter.area();
} }
void DetectorYOLOX::nms_sorted_bboxes(const std::vector<Object>& faceobjects, std::vector<int>& picked, float nms_threshold) void DetectorYOLOX::nms_sorted_bboxes(const std::vector<Object> &faceobjects,
{ std::vector<int> &picked,
float nms_threshold) {
picked.clear(); picked.clear();
const int n = faceobjects.size(); const int n = faceobjects.size();
std::vector<float> areas(n); std::vector<float> areas(n);
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++) {
{
areas[i] = faceobjects[i].rect.area(); areas[i] = faceobjects[i].rect.area();
} }
for (int i = 0; i < n; i++) for (int i = 0; i < n; i++) {
{ const Object &a = faceobjects[i];
const Object& a = faceobjects[i];
int keep = 1; int keep = 1;
for (int j = 0; j < (int)picked.size(); j++) for (int j = 0; j < (int)picked.size(); j++) {
{ const Object &b = faceobjects[picked[j]];
const Object& b = faceobjects[picked[j]];
// intersection over union // intersection over union
float inter_area = intersection_area(a, b); float inter_area = intersection_area(a, b);
...@@ -328,12 +257,15 @@ void DetectorYOLOX::nms_sorted_bboxes(const std::vector<Object>& faceobjects, st ...@@ -328,12 +257,15 @@ void DetectorYOLOX::nms_sorted_bboxes(const std::vector<Object>& faceobjects, st
} }
} }
void DetectorYOLOX::decode_outputs(float* prob, std::vector<Object>& objects, float scalew, float scaleh, const int img_w, const int img_h) { void DetectorYOLOX::decode_outputs(float *prob, std::vector<Object> &objects,
float scalew, float scaleh, const int img_w,
const int img_h, cv::Size inputSize) {
std::vector<Object> proposals; std::vector<Object> proposals;
std::vector<int> strides = {8, 16, 32}; std::vector<int> strides = {8, 16, 32};
std::vector<GridAndStride> grid_strides; std::vector<GridAndStride> grid_strides;
generate_grids_and_stride(strides, grid_strides); generate_grids_and_stride(strides, grid_strides, inputSize);
generate_yolox_proposals(grid_strides, prob, yoloxParameter.confidenceThreshold, proposals); generate_yolox_proposals(grid_strides, prob,
yoloxParameter.confidenceThreshold, proposals);
std::cout << "num of boxes before nms: " << proposals.size() << std::endl; std::cout << "num of boxes before nms: " << proposals.size() << std::endl;
qsort_descent_inplace(proposals); qsort_descent_inplace(proposals);
...@@ -341,14 +273,12 @@ void DetectorYOLOX::decode_outputs(float* prob, std::vector<Object>& objects, fl ...@@ -341,14 +273,12 @@ void DetectorYOLOX::decode_outputs(float* prob, std::vector<Object>& objects, fl
std::vector<int> picked; std::vector<int> picked;
nms_sorted_bboxes(proposals, picked, yoloxParameter.nmsThreshold); nms_sorted_bboxes(proposals, picked, yoloxParameter.nmsThreshold);
int count = picked.size(); int count = picked.size();
std::cout << "num of boxes: " << count << std::endl; std::cout << "num of boxes: " << count << std::endl;
objects.resize(count); objects.resize(count);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++) {
{
objects[i] = proposals[picked[i]]; objects[i] = proposals[picked[i]];
// adjust offset to original unpadded // adjust offset to original unpadded
...@@ -370,7 +300,8 @@ void DetectorYOLOX::decode_outputs(float* prob, std::vector<Object>& objects, fl ...@@ -370,7 +300,8 @@ void DetectorYOLOX::decode_outputs(float* prob, std::vector<Object>& objects, fl
} }
} }
void meshgrid(const cv::Range& x_range, const cv::Range& y_range, cv::Mat& xv, cv::Mat& yv) { void meshgrid(const cv::Range &x_range, const cv::Range &y_range, cv::Mat &xv,
cv::Mat &yv) {
// 初始化矩阵大小 // 初始化矩阵大小
int rows = y_range.end - y_range.start + 1; int rows = y_range.end - y_range.start + 1;
int cols = x_range.end - x_range.start + 1; int cols = x_range.end - x_range.start + 1;
...@@ -391,7 +322,8 @@ void meshgrid(const cv::Range& x_range, const cv::Range& y_range, cv::Mat& xv, c ...@@ -391,7 +322,8 @@ void meshgrid(const cv::Range& x_range, const cv::Range& y_range, cv::Mat& xv, c
cv::Mat demo_postprocess(cv::Mat outputs, cv::Size img_size, bool p6 = false) { cv::Mat demo_postprocess(cv::Mat outputs, cv::Size img_size, bool p6 = false) {
std::vector<cv::Mat> grids; std::vector<cv::Mat> grids;
std::vector<cv::Mat> expanded_strides; std::vector<cv::Mat> expanded_strides;
std::vector<int> strides = p6 ? std::vector<int>{8, 16, 32, 64} : std::vector<int>{8, 16, 32}; std::vector<int> strides =
p6 ? std::vector<int>{8, 16, 32, 64} : std::vector<int>{8, 16, 32};
std::vector<int> hsizes, wsizes; std::vector<int> hsizes, wsizes;
for (int stride : strides) { for (int stride : strides) {
...@@ -409,7 +341,8 @@ cv::Mat demo_postprocess(cv::Mat outputs, cv::Size img_size, bool p6 = false) { ...@@ -409,7 +341,8 @@ cv::Mat demo_postprocess(cv::Mat outputs, cv::Size img_size, bool p6 = false) {
} }
grids.push_back(grid); grids.push_back(grid);
cv::Mat expanded_stride = cv::Mat::ones(hsizes[i] * wsizes[i], 1, CV_32F) * strides[i]; cv::Mat expanded_stride =
cv::Mat::ones(hsizes[i] * wsizes[i], 1, CV_32F) * strides[i];
expanded_strides.push_back(expanded_stride); expanded_strides.push_back(expanded_stride);
} }
...@@ -420,12 +353,18 @@ cv::Mat demo_postprocess(cv::Mat outputs, cv::Size img_size, bool p6 = false) { ...@@ -420,12 +353,18 @@ cv::Mat demo_postprocess(cv::Mat outputs, cv::Size img_size, bool p6 = false) {
cv::Mat outputs_clone = outputs.clone(); cv::Mat outputs_clone = outputs.clone();
for (int i = 0; i < outputs_clone.rows; ++i) { for (int i = 0; i < outputs_clone.rows; ++i) {
outputs_clone.at<float>(i, 0) = (outputs.at<float>(i, 0) + grids_concatenated.at<float>(i, 0)) * outputs_clone.at<float>(i, 0) =
(outputs.at<float>(i, 0) + grids_concatenated.at<float>(i, 0)) *
expanded_strides_concatenated.at<float>(i, 0);
outputs_clone.at<float>(i, 1) =
(outputs.at<float>(i, 1) + grids_concatenated.at<float>(i, 1)) *
expanded_strides_concatenated.at<float>(i, 0);
outputs_clone.at<float>(i, 2) =
exp(outputs.at<float>(i, 2)) *
expanded_strides_concatenated.at<float>(i, 0); expanded_strides_concatenated.at<float>(i, 0);
outputs_clone.at<float>(i, 1) = (outputs.at<float>(i, 1) + grids_concatenated.at<float>(i, 1)) * outputs_clone.at<float>(i, 3) =
exp(outputs.at<float>(i, 3)) *
expanded_strides_concatenated.at<float>(i, 0); expanded_strides_concatenated.at<float>(i, 0);
outputs_clone.at<float>(i, 2) = exp(outputs.at<float>(i, 2)) * expanded_strides_concatenated.at<float>(i, 0);
outputs_clone.at<float>(i, 3) = exp(outputs.at<float>(i, 3)) * expanded_strides_concatenated.at<float>(i, 0);
} }
return outputs_clone; return outputs_clone;
...@@ -448,17 +387,23 @@ std::vector<int> nms(cv::Mat boxes, cv::Mat scores, float nms_thr) { ...@@ -448,17 +387,23 @@ std::vector<int> nms(cv::Mat boxes, cv::Mat scores, float nms_thr) {
// 根据分数排序的索引 // 根据分数排序的索引
std::vector<int> order(scores.rows); std::vector<int> order(scores.rows);
std::iota(order.begin(), order.end(), 0); std::iota(order.begin(), order.end(), 0);
std::sort(order.begin(), order.end(), [&scores](int i, int j) { return scores.at<float>(i) > scores.at<float>(j); }); std::sort(order.begin(), order.end(), [&scores](int i, int j) {
return scores.at<float>(i) > scores.at<float>(j);
});
// 执行 NMS // 执行 NMS
while (!order.empty()) { while (!order.empty()) {
int i = order[0]; int i = order[0];
keep.push_back(i); keep.push_back(i);
float xx1 = std::max(boxes.at<float>(i, 0), boxes.at<float>(order[1], 0)); float xx1 =
float yy1 = std::max(boxes.at<float>(i, 1), boxes.at<float>(order[1], 1)); std::max(boxes.at<float>(i, 0), boxes.at<float>(order[1], 0));
float xx2 = std::min(boxes.at<float>(i, 2), boxes.at<float>(order[1], 2)); float yy1 =
float yy2 = std::min(boxes.at<float>(i, 3), boxes.at<float>(order[1], 3)); std::max(boxes.at<float>(i, 1), boxes.at<float>(order[1], 1));
float xx2 =
std::min(boxes.at<float>(i, 2), boxes.at<float>(order[1], 2));
float yy2 =
std::min(boxes.at<float>(i, 3), boxes.at<float>(order[1], 3));
float w = std::max(0.0f, xx2 - xx1 + 1); float w = std::max(0.0f, xx2 - xx1 + 1);
float h = std::max(0.0f, yy2 - yy1 + 1); float h = std::max(0.0f, yy2 - yy1 + 1);
...@@ -478,13 +423,15 @@ std::vector<int> nms(cv::Mat boxes, cv::Mat scores, float nms_thr) { ...@@ -478,13 +423,15 @@ std::vector<int> nms(cv::Mat boxes, cv::Mat scores, float nms_thr) {
return keep; return keep;
} }
cv::Mat multiclass_nms_class_agnostic(cv::Mat boxes, cv::Mat scores, float nms_thr, float score_thr) { cv::Mat multiclass_nms_class_agnostic(cv::Mat boxes, cv::Mat scores,
float nms_thr, float score_thr) {
// 获取每个框的最高分数的索引和分数 // 获取每个框的最高分数的索引和分数
cv::Mat cls_inds; cv::Mat cls_inds;
cv::Mat cls_scores = cv::Mat::zeros(scores.rows, 1, CV_32F); cv::Mat cls_scores = cv::Mat::zeros(scores.rows, 1, CV_32F);
for (int i = 0; i < scores.rows; ++i) { for (int i = 0; i < scores.rows; ++i) {
int max_idx; int max_idx;
// cv::minMaxIdx(scores.row(i), nullptr, &cls_scores.at<float>(i), nullptr, &max_idx); // cv::minMaxIdx(scores.row(i), nullptr, &cls_scores.at<float>(i),
// nullptr, &max_idx);
double cls_score; double cls_score;
cv::minMaxIdx(scores.row(i), nullptr, &cls_score, nullptr, &max_idx); cv::minMaxIdx(scores.row(i), nullptr, &cls_score, nullptr, &max_idx);
cls_scores.at<float>(i) = static_cast<float>(cls_score); cls_scores.at<float>(i) = static_cast<float>(cls_score);
...@@ -500,7 +447,8 @@ cv::Mat multiclass_nms_class_agnostic(cv::Mat boxes, cv::Mat scores, float nms_t ...@@ -500,7 +447,8 @@ cv::Mat multiclass_nms_class_agnostic(cv::Mat boxes, cv::Mat scores, float nms_t
// 保留有效分数对应的框和类别索引 // 保留有效分数对应的框和类别索引
cv::Mat valid_scores = cls_scores(valid_score_mask); cv::Mat valid_scores = cls_scores(valid_score_mask);
cv::Mat valid_boxes = boxes.rowRange(0, boxes.rows).clone(); // 复制框数据以便后续修改 cv::Mat valid_boxes =
boxes.rowRange(0, boxes.rows).clone(); // 复制框数据以便后续修改
cv::Mat valid_cls_inds = cls_inds(valid_score_mask); cv::Mat valid_cls_inds = cls_inds(valid_score_mask);
// 应用 NMS 算法 // 应用 NMS 算法
...@@ -521,11 +469,11 @@ cv::Mat multiclass_nms_class_agnostic(cv::Mat boxes, cv::Mat scores, float nms_t ...@@ -521,11 +469,11 @@ cv::Mat multiclass_nms_class_agnostic(cv::Mat boxes, cv::Mat scores, float nms_t
return dets; return dets;
} }
ErrorCode
ErrorCode DetectorYOLOX::Detect(const cv::Mat &srcImage, std::vector<std::size_t> &relInputShape, std::vector<ResultOfDetection> &resultsOfDetection, bool dynamic) DetectorYOLOX::Detect(const cv::Mat &srcImage,
{ const std::vector<std::size_t> &relInputShape,
if(srcImage.empty()||srcImage.type()!=CV_8UC3) std::vector<ResultOfDetection> &resultsOfDetection) {
{ if (srcImage.empty() || srcImage.type() != CV_8UC3) {
LOG_ERROR(stdout, "image error!\n"); LOG_ERROR(stdout, "image error!\n");
return IMAGE_ERROR; return IMAGE_ERROR;
} }
...@@ -533,25 +481,15 @@ ErrorCode DetectorYOLOX::Detect(const cv::Mat &srcImage, std::vector<std::size_t ...@@ -533,25 +481,15 @@ ErrorCode DetectorYOLOX::Detect(const cv::Mat &srcImage, std::vector<std::size_t
// 数据预处理并转换为NCHW格式 // 数据预处理并转换为NCHW格式
inputSize = cv::Size(relInputShape[3], relInputShape[2]); inputSize = cv::Size(relInputShape[3], relInputShape[2]);
cv::Mat inputBlob; cv::Mat inputBlob;
cv::dnn::blobFromImage(srcImage, cv::dnn::blobFromImage(srcImage, inputBlob, 1, inputSize,
inputBlob, cv::Scalar(0, 0, 0), false, false);
// 1 / 255.0, float ratio = std::min(inputSize.width / srcImage.rows,
1, inputSize.height / srcImage.cols);
inputSize,
cv::Scalar(0, 0, 0),
true,
false);
float ratio = std::min(inputSize.width / srcImage.rows, inputSize.height / srcImage.cols);
// 创建输入数据 // 创建输入数据
migraphx::parameter_map inputData; migraphx::parameter_map inputData;
if(dynamic)
{ inputData[inputName] =
inputData[inputName]= migraphx::argument{migraphx::shape(inputShape.type(), relInputShape), (float*)inputBlob.data}; migraphx::argument{inputShape, (float *)inputBlob.data};
}
else
{
inputData[inputName]= migraphx::argument{inputShape, (float*)inputBlob.data};
}
// 推理 // 推理
std::vector<migraphx::argument> inferenceResults = net.eval(inputData); std::vector<migraphx::argument> inferenceResults = net.eval(inputData);
...@@ -562,36 +500,36 @@ ErrorCode DetectorYOLOX::Detect(const cv::Mat &srcImage, std::vector<std::size_t ...@@ -562,36 +500,36 @@ ErrorCode DetectorYOLOX::Detect(const cv::Mat &srcImage, std::vector<std::size_t
// 转换为cv::Mat // 转换为cv::Mat
migraphx::shape outputShape = result.get_shape(); migraphx::shape outputShape = result.get_shape();
std::cout << outputShape.lens()[2] << std::endl; int shape[] = {outputShape.lens()[0], outputShape.lens()[1],
int shape[]={outputShape.lens()[0],outputShape.lens()[1],outputShape.lens()[2]}; outputShape.lens()[2]};
cv::Mat out(3,shape,CV_32F); cv::Mat out(3, shape, CV_32F);
memcpy(out.data,result.data(),sizeof(float)*outputShape.elements()); memcpy(out.data, result.data(), sizeof(float) * outputShape.elements());
outs.push_back(out); outs.push_back(out);
//获取先验框的个数 // 获取先验框的个数
int numProposal = outs[0].size[1]; int numProposal = outs[0].size[1];
int numOut = outs[0].size[2]; int numOut = outs[0].size[2];
//变换输出的维度 // 变换输出的维度
outs[0] = outs[0].reshape(0, numProposal); outs[0] = outs[0].reshape(0, numProposal);
float* prob = (float*)outs[0].data; float *prob = (float *)outs[0].data;
std::vector<Object> objects; std::vector<Object> objects;
float scalew = inputSize.width / (srcImage.cols*1.0); float scalew = inputSize.width / (srcImage.cols * 1.0);
float scaleh = inputSize.height / (srcImage.rows*1.0); float scaleh = inputSize.height / (srcImage.rows * 1.0);
decode_outputs(prob, objects, scalew, scaleh, srcImage.cols, srcImage.rows); decode_outputs(prob, objects, scalew, scaleh, srcImage.cols, srcImage.rows,
inputSize);
for (size_t i = 0; i < objects.size(); ++i) for (size_t i = 0; i < objects.size(); ++i) {
{
ResultOfDetection result; ResultOfDetection result;
result.boundingBox=objects[i].rect; result.boundingBox = objects[i].rect;
result.confidence=objects[i].prob;// confidence result.confidence = objects[i].prob; // confidence
result.classID=objects[i].label; // label result.classID = objects[i].label; // label
result.className=classNames[objects[i].label]; result.className = classNames[objects[i].label];
resultsOfDetection.push_back(result); resultsOfDetection.push_back(result);
} }
return SUCCESS; return SUCCESS;
} }
} } // namespace migraphxSamples
#ifndef __DETECTOR_YOLOX_H__ #ifndef __DETECTOR_YOLOX_H__
#define __DETECTOR_YOLOX_H__ #define __DETECTOR_YOLOX_H__
#include <migraphx/program.hpp>
#include <CommonDefinition.h> #include <CommonDefinition.h>
#include <migraphx/program.hpp>
namespace migraphxSamples namespace migraphxSamples {
{
typedef struct _YOLOXParameter typedef struct _YOLOXParameter {
{
int numberOfClasses; int numberOfClasses;
float confidenceThreshold; float confidenceThreshold;
float nmsThreshold; float nmsThreshold;
float objectThreshold; float objectThreshold;
}YOLOXParameter; } YOLOXParameter;
struct Object struct Object {
{
cv::Rect_<float> rect; cv::Rect_<float> rect;
int label; int label;
float prob; float prob;
}; };
struct GridAndStride struct GridAndStride {
{
int grid0; int grid0;
int grid1; int grid1;
int stride; int stride;
}; };
class DetectorYOLOX class DetectorYOLOX {
{ public:
public:
DetectorYOLOX(); DetectorYOLOX();
~DetectorYOLOX(); ~DetectorYOLOX();
ErrorCode Initialize(InitializationParameterOfDetector initializationParameterOfDetector, bool dynamic); ErrorCode Initialize(
InitializationParameterOfDetector initializationParameterOfDetector);
void decode_outputs(float* prob, std::vector<Object>& objects, float scalew, float scaleh, const int img_w, const int img_h); ErrorCode Detect(const cv::Mat &srcImage,
void generate_grids_and_stride(std::vector<int>& strides, std::vector<GridAndStride>& grid_strides); const std::vector<std::size_t> &relInputShape,
void generate_yolox_proposals(std::vector<GridAndStride> grid_strides, float* feat_blob, float prob_threshold, std::vector<Object>& objects); std::vector<ResultOfDetection> &resultsOfDetection);
void qsort_descent_inplace(std::vector<Object>& faceobjects, int left, int right);
void qsort_descent_inplace(std::vector<Object>& objects); private:
void nms_sorted_bboxes(const std::vector<Object>& faceobjects, std::vector<int>& picked, float nms_threshold); void decode_outputs(float *prob, std::vector<Object> &objects, float scalew,
inline float intersection_area(const Object& a, const Object& b); float scaleh, const int img_w, const int img_h,
cv::Size inputSize);
void generate_grids_and_stride(std::vector<int> &strides,
std::vector<GridAndStride> &grid_strides,
cv::Size inputSize);
void generate_yolox_proposals(std::vector<GridAndStride> grid_strides,
float *feat_blob, float prob_threshold,
std::vector<Object> &objects);
void qsort_descent_inplace(std::vector<Object> &faceobjects, int left,
int right);
void qsort_descent_inplace(std::vector<Object> &objects);
void nms_sorted_bboxes(const std::vector<Object> &faceobjects,
std::vector<int> &picked, float nms_threshold);
inline float intersection_area(const Object &a, const Object &b);
ErrorCode Detect(const cv::Mat &srcImage, std::vector<std::size_t> &relInputShape, std::vector<ResultOfDetection> &resultsOfDetection, bool dynamic);
private:
cv::FileStorage configurationFile; cv::FileStorage configurationFile;
migraphx::program net; migraphx::program net;
...@@ -64,8 +69,6 @@ private: ...@@ -64,8 +69,6 @@ private:
YOLOXParameter yoloxParameter; YOLOXParameter yoloxParameter;
}; };
} } // namespace migraphxSamples
#endif #endif
#include <Filesystem.h>
#include <SimpleLog.h>
#include <YOLOX.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <SimpleLog.h>
#include <Filesystem.h>
#include <YOLOX.h>
void MIGraphXSamplesUsage(char* programName) void MIGraphXSamplesUsage(char *programName) {
{
printf("Usage : %s <index> \n", programName); printf("Usage : %s <index> \n", programName);
printf("index:\n"); printf("index:\n");
printf("\t 0) YOLOX sample.\n"); printf("\t 0) YOLOX sample.\n");
// printf("\t 1) YOLOX Dynamic sample.\n"); 暂不支持
} }
void Sample_YOLOX(); void Sample_YOLOX();
void Sample_YOLOX_Dynamic();
int main(int argc, char *argv[]) int main(int argc, char *argv[]) {
{ if (argc < 2 || argc > 2) {
if (argc < 2 || argc > 2)
{
MIGraphXSamplesUsage(argv[0]); MIGraphXSamplesUsage(argv[0]);
return -1; return -1;
} }
if (!strncmp(argv[1], "-h", 2)) if (!strncmp(argv[1], "-h", 2)) {
{
MIGraphXSamplesUsage(argv[0]); MIGraphXSamplesUsage(argv[0]);
return 0; return 0;
} }
switch (*argv[1]) switch (*argv[1]) {
{ case '0': {
case '0':
{
Sample_YOLOX(); Sample_YOLOX();
break; break;
} }
case '1': case '1': {
{
// Sample_YOLOX_Dynamic(); 暂不支持
break; break;
} }
default : default: {
{
MIGraphXSamplesUsage(argv[0]); MIGraphXSamplesUsage(argv[0]);
break; break;
} }
...@@ -49,119 +38,56 @@ int main(int argc, char *argv[]) ...@@ -49,119 +38,56 @@ int main(int argc, char *argv[])
return 0; return 0;
} }
void Sample_YOLOX() void Sample_YOLOX() {
{
// 创建YOLOX检测器 // 创建YOLOX检测器
migraphxSamples::DetectorYOLOX detector; migraphxSamples::DetectorYOLOX detector;
migraphxSamples::InitializationParameterOfDetector initParamOfDetectorYOLOX; migraphxSamples::InitializationParameterOfDetector initParamOfDetectorYOLOX;
initParamOfDetectorYOLOX.configFilePath = CONFIG_FILE; initParamOfDetectorYOLOX.configFilePath = CONFIG_FILE;
migraphxSamples::ErrorCode errorCode=detector.Initialize(initParamOfDetectorYOLOX, false); migraphxSamples::ErrorCode errorCode =
if(errorCode!=migraphxSamples::SUCCESS) detector.Initialize(initParamOfDetectorYOLOX, false);
{ if (errorCode != migraphxSamples::SUCCESS) {
LOG_ERROR(stdout, "fail to initialize detector!\n"); LOG_ERROR(stdout, "fail to initialize detector!\n");
exit(-1); exit(-1);
} }
LOG_INFO(stdout, "succeed to initialize detector\n"); LOG_INFO(stdout, "succeed to initialize detector\n");
// 读取测试图片 // 读取测试图片
cv::Mat srcImage = cv::imread("../Resource/Images/image_test.jpg",1); cv::Mat srcImage = cv::imread("../Resource/Images/image_test.jpg", 1);
// 静态推理固定尺寸 // 静态推理固定尺寸
std::vector<std::size_t> inputShape={1,3,640,640}; std::vector<std::size_t> inputShape = {1, 3, 640, 640};
// 推理 // 推理
std::vector<migraphxSamples::ResultOfDetection> predictions; std::vector<migraphxSamples::ResultOfDetection> predictions;
double time1 = cv::getTickCount(); double time1 = cv::getTickCount();
detector.Detect(srcImage,inputShape,predictions,false); detector.Detect(srcImage, inputShape, predictions, false);
double time2 = cv::getTickCount(); double time2 = cv::getTickCount();
double elapsedTime = (time2 - time1)*1000 / cv::getTickFrequency(); double elapsedTime = (time2 - time1) * 1000 / cv::getTickFrequency();
LOG_INFO(stdout, "inference time:%f ms\n", elapsedTime); LOG_INFO(stdout, "inference time:%f ms\n", elapsedTime);
// 获取推理结果 // 获取推理结果
LOG_INFO(stdout,"========== Detection Results ==========\n"); LOG_INFO(stdout, "========== Detection Results ==========\n");
for(int i=0;i<predictions.size();++i) for (int i = 0; i < predictions.size(); ++i) {
{ migraphxSamples::ResultOfDetection result = predictions[i];
migraphxSamples::ResultOfDetection result=predictions[i]; cv::rectangle(srcImage, result.boundingBox, cv::Scalar(0, 255, 255), 2);
cv::rectangle(srcImage,result.boundingBox,cv::Scalar(0,255,255),2);
std::string label = cv::format("%.2f", result.confidence); std::string label = cv::format("%.2f", result.confidence);
label = result.className + " " + label; label = result.className + " " + label;
int left = predictions[i].boundingBox.x; int left = predictions[i].boundingBox.x;
int top = predictions[i].boundingBox.y; int top = predictions[i].boundingBox.y;
int baseLine; int baseLine;
cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine); cv::Size labelSize =
top = max(top, labelSize.height); cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
cv::putText(srcImage, label, cv::Point(left, top-10), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 255), 2);
LOG_INFO(stdout,"box:%d %d %d %d,label:%d,confidence:%f\n",predictions[i].boundingBox.x,
predictions[i].boundingBox.y,predictions[i].boundingBox.width,predictions[i].boundingBox.height,predictions[i].classID,predictions[i].confidence);
}
cv::imwrite("Result.jpg",srcImage);
LOG_INFO(stdout,"Detection results have been saved to ./Result.jpg\n");
}
void Sample_YOLOX_Dynamic()
{
// 创建YOLOX检测器
migraphxSamples::DetectorYOLOX detector;
migraphxSamples::InitializationParameterOfDetector initParamOfDetectorYOLOX;
initParamOfDetectorYOLOX.configFilePath = CONFIG_FILE;
migraphxSamples::ErrorCode errorCode=detector.Initialize(initParamOfDetectorYOLOX, true);
if(errorCode!=migraphxSamples::SUCCESS)
{
LOG_ERROR(stdout, "fail to initialize detector!\n");
exit(-1);
}
LOG_INFO(stdout, "succeed to initialize detector\n");
// 读取测试图像
std::vector<cv::Mat> srcImages;
cv::String folder = "../Resource/Images/DynamicPics";
std::vector<cv::String> imagePathList;
cv::glob(folder,imagePathList);
for (int i = 0; i < imagePathList.size(); ++i)
{
cv:: Mat srcImage=cv::imread(imagePathList[i], 1);
srcImages.push_back(srcImage);
}
// 设置动态推理shape
std::vector<std::vector<std::size_t>> inputShapes;
inputShapes.push_back({1,3,416,416});
inputShapes.push_back({1,3,608,608});
for (int i = 0; i < srcImages.size(); ++i)
{
// 推理
std::vector<migraphxSamples::ResultOfDetection> predictions;
double time1 = cv::getTickCount();
detector.Detect(srcImages[i], inputShapes[i], predictions, true);
double time2 = cv::getTickCount();
double elapsedTime = (time2 - time1)*1000 / cv::getTickFrequency();
LOG_INFO(stdout, "inference image%d time:%f ms\n", i, elapsedTime);
// 获取推理结果
LOG_INFO(stdout,"========== Detection Image%d Results ==========\n", i);
for(int j=0;j<predictions.size();++j)
{
migraphxSamples::ResultOfDetection result=predictions[j];
cv::rectangle(srcImages[i],result.boundingBox,cv::Scalar(0,255,255),2);
std::string label = cv::format("%.2f", result.confidence);
label = result.className + " " + label;
int left = predictions[j].boundingBox.x;
int top = predictions[j].boundingBox.y;
int baseLine;
cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
top = max(top, labelSize.height); top = max(top, labelSize.height);
cv::putText(srcImages[i], label, cv::Point(left, top-10), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 255), 2); cv::putText(srcImage, label, cv::Point(left, top - 10),
cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 255), 2);
LOG_INFO(stdout,"box:%d %d %d %d,label:%d,confidence:%f\n",predictions[j].boundingBox.x,
predictions[j].boundingBox.y,predictions[j].boundingBox.width,predictions[j].boundingBox.height,predictions[j].classID,predictions[j].confidence); LOG_INFO(stdout, "box:%d %d %d %d,label:%d,confidence:%f\n",
} predictions[i].boundingBox.x, predictions[i].boundingBox.y,
std::string imgName = cv::format("Result%d.jpg", i); predictions[i].boundingBox.width,
cv::imwrite(imgName, srcImages[i]); predictions[i].boundingBox.height, predictions[i].classID,
LOG_INFO(stdout,"Detection results have been saved to ./Result%d.jpg\n", i); predictions[i].confidence);
} }
cv::imwrite("Result.jpg", srcImage);
LOG_INFO(stdout, "Detection results have been saved to ./Result.jpg\n");
} }
\ 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