"vscode:/vscode.git/clone" did not exist on "47c77112227f6276fff51fd229cc98569edb713b"
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() DetectorYOLOX::DetectorYOLOX() {}
{
configurationFile.release(); 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;
} }
LOG_INFO(stdout, "succeed to open configuration file\n"); LOG_INFO(stdout, "succeed to open configuration file\n");
// 获取配置文件参数 // 获取配置文件参数
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)) {
// 加载模型 LOG_ERROR(stdout, "%s not exist!\n", modelPath.c_str());
if(Exists(modelPath)==false) return MODEL_NOT_EXIST;
{
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 net = migraphx::parse_onnx(modelPath);
{ LOG_INFO(stdout, "succeed to load model: %s\n",
// 加载模型 GetFileName(modelPath).c_str());
if(Exists(modelPath)==false)
{ // 获取模型输入/输出节点信息
LOG_ERROR(stdout,"%s not exist!\n",modelPath.c_str()); std::cout << "inputs:" << std::endl;
return MODEL_NOT_EXIST; std::unordered_map<std::string, migraphx::shape> inputs = net.get_inputs();
} for (auto i : inputs) {
net = migraphx::parse_onnx(modelPath); std::cout << i.first << ":" << i.second << std::endl;
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,"InputSize:%dx%d\n",inputSize.width,inputSize.height);
} }
std::cout << "outputs:" << std::endl;
LOG_INFO(stdout,"InputName:%s\n",inputName.c_str()); std::unordered_map<std::string, migraphx::shape> outputs =
LOG_INFO(stdout,"ConfidenceThreshold:%f\n",yoloxParameter.confidenceThreshold); net.get_outputs();
LOG_INFO(stdout,"NMSThreshold:%f\n",yoloxParameter.nmsThreshold); for (auto i : outputs) {
LOG_INFO(stdout,"objectThreshold:%f\n",yoloxParameter.objectThreshold); std::cout << i.first << ":" << i.second << std::endl;
LOG_INFO(stdout,"NumberOfClasses:%d\n",yoloxParameter.numberOfClasses); }
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, "InputSize:%dx%d\n", inputSize.width, inputSize.height);
LOG_INFO(stdout, "InputName:%s\n", inputName.c_str());
LOG_INFO(stdout, "ConfidenceThreshold:%f\n",
yoloxParameter.confidenceThreshold);
LOG_INFO(stdout, "NMSThreshold:%f\n", yoloxParameter.nmsThreshold);
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,58 +138,57 @@ void DetectorYOLOX::generate_yolox_proposals(std::vector<GridAndStride> grid_str ...@@ -207,58 +138,57 @@ 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;
obj.rect.width = w; obj.rect.width = w;
obj.rect.height = h; obj.rect.height = h;
obj.label = max_score_class_idx; obj.label = max_score_class_idx;
obj.prob = box_prob; obj.prob = box_prob;
objects.push_back(obj); objects.push_back(obj);
} }
} // 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,49 +257,51 @@ void DetectorYOLOX::nms_sorted_bboxes(const std::vector<Object>& faceobjects, st ...@@ -328,49 +257,51 @@ 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,
std::vector<Object> proposals; float scalew, float scaleh, const int img_w,
std::vector<int> strides = {8, 16, 32}; const int img_h, cv::Size inputSize) {
std::vector<GridAndStride> grid_strides; std::vector<Object> proposals;
generate_grids_and_stride(strides, grid_strides); std::vector<int> strides = {8, 16, 32};
generate_yolox_proposals(grid_strides, prob, yoloxParameter.confidenceThreshold, proposals); std::vector<GridAndStride> grid_strides;
std::cout << "num of boxes before nms: " << proposals.size() << std::endl; generate_grids_and_stride(strides, grid_strides, inputSize);
generate_yolox_proposals(grid_strides, prob,
qsort_descent_inplace(proposals); yoloxParameter.confidenceThreshold, proposals);
std::cout << "num of boxes before nms: " << proposals.size() << std::endl;
std::vector<int> picked;
nms_sorted_bboxes(proposals, picked, yoloxParameter.nmsThreshold); qsort_descent_inplace(proposals);
std::vector<int> picked;
int count = picked.size(); nms_sorted_bboxes(proposals, picked, yoloxParameter.nmsThreshold);
std::cout << "num of boxes: " << count << std::endl; int count = picked.size();
objects.resize(count); std::cout << "num of boxes: " << count << std::endl;
for (int i = 0; i < count; i++)
{ objects.resize(count);
objects[i] = proposals[picked[i]]; for (int i = 0; i < count; i++) {
objects[i] = proposals[picked[i]];
// adjust offset to original unpadded
float x0 = (objects[i].rect.x) / scalew; // adjust offset to original unpadded
float y0 = (objects[i].rect.y) / scaleh; float x0 = (objects[i].rect.x) / scalew;
float x1 = (objects[i].rect.x + objects[i].rect.width) / scalew; float y0 = (objects[i].rect.y) / scaleh;
float y1 = (objects[i].rect.y + objects[i].rect.height) / scaleh; float x1 = (objects[i].rect.x + objects[i].rect.width) / scalew;
float y1 = (objects[i].rect.y + objects[i].rect.height) / scaleh;
// clip
x0 = std::max(std::min(x0, (float)(img_w - 1)), 0.f); // clip
y0 = std::max(std::min(y0, (float)(img_h - 1)), 0.f); x0 = std::max(std::min(x0, (float)(img_w - 1)), 0.f);
x1 = std::max(std::min(x1, (float)(img_w - 1)), 0.f); y0 = std::max(std::min(y0, (float)(img_h - 1)), 0.f);
y1 = std::max(std::min(y1, (float)(img_h - 1)), 0.f); x1 = std::max(std::min(x1, (float)(img_w - 1)), 0.f);
y1 = std::max(std::min(y1, (float)(img_h - 1)), 0.f);
objects[i].rect.x = x0;
objects[i].rect.y = y0; objects[i].rect.x = x0;
objects[i].rect.width = x1 - x0; objects[i].rect.y = y0;
objects[i].rect.height = y1 - y0; objects[i].rect.width = x1 - x0;
} objects[i].rect.height = y1 - y0;
}
} }
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) =
expanded_strides_concatenated.at<float>(i, 0); (outputs.at<float>(i, 0) + grids_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);
expanded_strides_concatenated.at<float>(i, 0); outputs_clone.at<float>(i, 1) =
outputs_clone.at<float>(i, 2) = exp(outputs.at<float>(i, 2)) * expanded_strides_concatenated.at<float>(i, 0); (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);
...@@ -495,18 +442,19 @@ cv::Mat multiclass_nms_class_agnostic(cv::Mat boxes, cv::Mat scores, float nms_t ...@@ -495,18 +442,19 @@ cv::Mat multiclass_nms_class_agnostic(cv::Mat boxes, cv::Mat scores, float nms_t
// 过滤掉低于阈值的分数 // 过滤掉低于阈值的分数
cv::Mat valid_score_mask = cls_scores > score_thr; cv::Mat valid_score_mask = cls_scores > score_thr;
if (cv::countNonZero(valid_score_mask) == 0) { if (cv::countNonZero(valid_score_mask) == 0) {
return cv::Mat(); // 如果没有有效的分数,返回空矩阵 return cv::Mat(); // 如果没有有效的分数,返回空矩阵
} }
// 保留有效分数对应的框和类别索引 // 保留有效分数对应的框和类别索引
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 算法
std::vector<int> keep = nms(valid_boxes, valid_scores, nms_thr); std::vector<int> keep = nms(valid_boxes, valid_scores, nms_thr);
if (keep.empty()) { if (keep.empty()) {
return cv::Mat(); // 如果没有保留的框,返回空矩阵 return cv::Mat(); // 如果没有保留的框,返回空矩阵
} }
// 按行组合保留的框、分数和类别索引 // 按行组合保留的框、分数和类别索引
...@@ -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,65 +481,55 @@ ErrorCode DetectorYOLOX::Detect(const cv::Mat &srcImage, std::vector<std::size_t ...@@ -533,65 +481,55 @@ 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);
// 获取推理结果 // 获取推理结果
std::vector<cv::Mat> outs; std::vector<cv::Mat> outs;
migraphx::argument result = inferenceResults[0]; migraphx::argument result = inferenceResults[0];
// 转换为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();
ErrorCode Initialize(InitializationParameterOfDetector initializationParameterOfDetector, bool dynamic); ~DetectorYOLOX();
void decode_outputs(float* prob, std::vector<Object>& objects, float scalew, float scaleh, const int img_w, const int img_h);
void generate_grids_and_stride(std::vector<int>& strides, std::vector<GridAndStride>& grid_strides);
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); ErrorCode Initialize(
InitializationParameterOfDetector initializationParameterOfDetector);
ErrorCode Detect(const cv::Mat &srcImage,
const std::vector<std::size_t> &relInputShape,
std::vector<ResultOfDetection> &resultsOfDetection);
private:
void decode_outputs(float *prob, std::vector<Object> &objects, float scalew,
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);
private:
cv::FileStorage configurationFile; cv::FileStorage configurationFile;
migraphx::program net; migraphx::program net;
...@@ -57,15 +62,13 @@ private: ...@@ -57,15 +62,13 @@ private:
std::string inputName; std::string inputName;
std::string modelPath; std::string modelPath;
migraphx::shape inputShape; migraphx::shape inputShape;
bool useFP16; bool useFP16;
std::vector<std::string> classNames; std::vector<std::string> classNames;
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();
{ break;
Sample_YOLOX(); }
break; case '1': {
} break;
case '1': }
{ default: {
// Sample_YOLOX_Dynamic(); 暂不支持 MIGraphXSamplesUsage(argv[0]);
break; break;
} }
default :
{
MIGraphXSamplesUsage(argv[0]);
break;
}
} }
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 =
cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
top = max(top, labelSize.height); top = max(top, labelSize.height);
cv::putText(srcImage, 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[i].boundingBox.x,
predictions[i].boundingBox.y,predictions[i].boundingBox.width,predictions[i].boundingBox.height,predictions[i].classID,predictions[i].confidence); LOG_INFO(stdout, "box:%d %d %d %d,label:%d,confidence:%f\n",
} predictions[i].boundingBox.x, predictions[i].boundingBox.y,
cv::imwrite("Result.jpg",srcImage); predictions[i].boundingBox.width,
LOG_INFO(stdout,"Detection results have been saved to ./Result.jpg\n"); predictions[i].boundingBox.height, predictions[i].classID,
predictions[i].confidence);
}
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);
cv::putText(srcImages[i], 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);
}
std::string imgName = cv::format("Result%d.jpg", i);
cv::imwrite(imgName, srcImages[i]);
LOG_INFO(stdout,"Detection results have been saved to ./Result%d.jpg\n", i);
} }
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