mirror of
https://github.com/Ascend/ascend_community_projects.git
synced 2025-09-26 20:01:17 +08:00
360 lines
13 KiB
C++
360 lines
13 KiB
C++
/*
|
|
# Copyright(C) 2022. Huawei Technologies Co.,Ltd. All rights reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
*/
|
|
|
|
#include <cstring>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <iostream>
|
|
#include "MxBase/Log/Log.h"
|
|
#include "MxStream/StreamManager/MxStreamManager.h"
|
|
#include "opencv4/opencv2/opencv.hpp"
|
|
const int color_list[20][3] = { {216, 82, 24}, {236, 176, 31}, {125, 46, 141}, {118, 171, 47}, {76, 189, 237}, {238, 19, 46},
|
|
{76, 76, 76}, {153, 153, 153}, {255, 0, 0}, {255, 127, 0}, {190, 190, 0}, {0, 255, 0}, {0, 0, 255},
|
|
{170, 0, 255}, {84, 84, 0}, {84, 170, 0}, {84, 255, 0}, {170, 84, 0}, {170, 170, 0}, {170, 255, 0}};
|
|
|
|
float pad_w = 0.0, pad_h = 0.0;
|
|
float ratio = 1.0;
|
|
|
|
|
|
namespace {
|
|
std::string ReadPipelineConfig(const std::string& pipelineConfigPath)
|
|
{
|
|
std::ifstream file(pipelineConfigPath.c_str(), std::ifstream::binary);
|
|
if (!file) {
|
|
LogError << pipelineConfigPath << " file dose not exist.";
|
|
return "";
|
|
}
|
|
file.seekg(0, std::ifstream::end);
|
|
uint32_t fileSize = file.tellg();
|
|
file.seekg(0);
|
|
auto dataPtr = new (std::nothrow) char[fileSize];
|
|
if (dataPtr == nullptr) {
|
|
LogError << GetError(APP_ERR_COMM_INIT_FAIL) << "The pointer is null.";
|
|
return "";
|
|
}
|
|
std::unique_ptr<char[]> data(dataPtr);
|
|
file.read(data.get(), fileSize);
|
|
file.close();
|
|
std::string pipelineConfig(data.get(), fileSize);
|
|
return pipelineConfig;
|
|
}
|
|
|
|
APP_ERROR ReadFile(const std::string& filePath, MxStream::MxstDataInput& dataBuffer)
|
|
{
|
|
char c[PATH_MAX + 1] = { 0x00 };
|
|
size_t count = filePath.copy(c, PATH_MAX + 1);
|
|
if (count != filePath.length()) {
|
|
LogError << "Failed to copy file path(" << c << ").";
|
|
return APP_ERR_COMM_FAILURE;
|
|
}
|
|
// Get the absolute path of input file
|
|
char path[PATH_MAX + 1] = { 0x00 };
|
|
if ((strlen(c) > PATH_MAX) || (realpath(c, path) == nullptr)) {
|
|
LogError << "Failed to get image, the image path is (" << filePath << ").";
|
|
return APP_ERR_COMM_NO_EXIST;
|
|
}
|
|
// Open file with reading mode
|
|
FILE *fp = fopen(path, "rb");
|
|
if (fp == nullptr) {
|
|
LogError << "Failed to open file (" << path << ").";
|
|
return APP_ERR_COMM_OPEN_FAIL;
|
|
}
|
|
// Get the length of input file
|
|
fseek(fp, 0, SEEK_END);
|
|
long fileSize = ftell(fp);
|
|
fseek(fp, 0, SEEK_SET);
|
|
// If file not empty, read it into FileInfo and return it
|
|
if (fileSize > 0) {
|
|
dataBuffer.dataSize = fileSize;
|
|
dataBuffer.dataPtr = new (std::nothrow) uint32_t[fileSize];
|
|
if (dataBuffer.dataPtr == nullptr) {
|
|
LogError << "allocate memory with \"new uint32_t\" failed.";
|
|
return APP_ERR_COMM_FAILURE;
|
|
}
|
|
|
|
uint32_t readRet = fread(dataBuffer.dataPtr, 1, fileSize, fp);
|
|
if (readRet <= 0) {
|
|
fclose(fp);
|
|
delete dataBuffer.dataPtr;
|
|
dataBuffer.dataPtr = nullptr;
|
|
return APP_ERR_COMM_READ_FAIL;
|
|
}
|
|
fclose(fp);
|
|
return APP_ERR_OK;
|
|
}
|
|
fclose(fp);
|
|
return APP_ERR_COMM_FAILURE;
|
|
}
|
|
}
|
|
struct Result
|
|
{
|
|
public:
|
|
float x0, y0, x1, y1;
|
|
std::string className;
|
|
int classId;
|
|
float conf;
|
|
};
|
|
cv::Mat letterBox(const cv::Mat& src)
|
|
{
|
|
int in_w = src.cols;
|
|
int in_h = src.rows;
|
|
int tar_w = 512;
|
|
int tar_h = 512;
|
|
|
|
ratio = std::min(float(tar_h) / in_h, float(tar_w) / in_w);
|
|
int inside_w = std::round(in_w * ratio);
|
|
int inside_h = std::round(in_h * ratio);
|
|
pad_w = tar_w - inside_w;
|
|
pad_h = tar_h - inside_h;
|
|
cv::Mat resize_img;
|
|
cv::resize(src, resize_img, cv::Size(inside_w, inside_h));
|
|
cv::cvtColor(resize_img, resize_img, cv::COLOR_BGR2RGB);
|
|
const int div = 2;
|
|
pad_w = pad_w / div;
|
|
pad_h = pad_h / div;
|
|
|
|
int topPad = int(std::round(pad_h - 0.1));
|
|
int btmPad = int(std::round(pad_h + 0.1));
|
|
int leftPad = int(std::round(pad_w - 0.1));
|
|
int rightPad = int(std::round(pad_w + 0.1));
|
|
int b = 0, g = 135, r = 0;
|
|
cv::copyMakeBorder(resize_img, resize_img, topPad, btmPad, leftPad, rightPad, cv::BORDER_CONSTANT, cv::Scalar(b, g, r));
|
|
cv::cvtColor(resize_img, resize_img, cv::COLOR_BGR2RGB);
|
|
|
|
return resize_img;
|
|
}
|
|
std::vector<Result> ParseResult(const std::string& result)
|
|
{
|
|
std::vector<Result> res;
|
|
web::json::value jsonText = web::json::value::parse(result);
|
|
if (jsonText.is_object()) {
|
|
web::json::object textObject = jsonText.as_object();
|
|
auto itInferObject = textObject.find("MxpiObject");
|
|
if (itInferObject == textObject.end() || (!itInferObject->second.is_array())) {
|
|
return {};
|
|
}
|
|
auto iter = itInferObject->second.as_array().begin();
|
|
for (; iter != itInferObject->second.as_array().end(); iter++) {
|
|
if (iter->is_object()) {
|
|
Result tmp;
|
|
auto modelInferObject = iter->as_object();
|
|
auto it = modelInferObject.find("classVec");
|
|
if (it != modelInferObject.end()) {
|
|
auto class_iter = it->second.as_array().begin();
|
|
if (class_iter->is_object()) {
|
|
auto classObject = class_iter->as_object();
|
|
auto class_it = classObject.find("className");
|
|
if (class_it != classObject.end()) {
|
|
tmp.className = class_it->second.as_string();
|
|
}
|
|
class_it = classObject.find("confidence");
|
|
if (class_it != classObject.end()) {
|
|
tmp.conf = float(class_it->second.as_double());
|
|
}
|
|
class_it = classObject.find("classId");
|
|
if (class_it != classObject.end()) {
|
|
tmp.classId = float(class_it->second.as_integer());
|
|
}
|
|
}
|
|
}
|
|
it = modelInferObject.find("x0");
|
|
if (it != modelInferObject.end()) {
|
|
tmp.x0 = float(it->second.as_double());
|
|
}
|
|
it = modelInferObject.find("x1");
|
|
if (it != modelInferObject.end()) {
|
|
tmp.x1 = float(it->second.as_double());
|
|
}
|
|
it = modelInferObject.find("y0");
|
|
if (it != modelInferObject.end()) {
|
|
tmp.y0 = float(it->second.as_double());
|
|
}
|
|
it = modelInferObject.find("y1");
|
|
if (it != modelInferObject.end()) {
|
|
tmp.y1 = float(it->second.as_double());
|
|
}
|
|
int topPad = int(std::round(pad_h - 0.1));
|
|
int leftPad = int(std::round(pad_w - 0.1));
|
|
tmp.x0 = std::max((tmp.x0 - leftPad) / ratio, 0.0f);
|
|
tmp.y0 = std::max((tmp.y0 - topPad) / ratio, 0.0f);
|
|
tmp.x1 = (tmp.x1 - leftPad) / ratio;
|
|
tmp.y1 = (tmp.y1 - topPad) / ratio;
|
|
|
|
res.push_back(tmp);
|
|
}
|
|
}
|
|
}
|
|
return res;
|
|
}
|
|
void SaveImage(const std::string& result, const cv::Mat src, const std::string& line)
|
|
{
|
|
auto res = ParseResult(result);
|
|
for (auto it : res) {
|
|
cv::Scalar color = cv::Scalar(color_list[it.classId][0], color_list[it.classId][1], color_list[it.classId][2]);
|
|
cv::Rect rect(it.x0, it.y0, it.x1 - it.x0, it.y1 - it.y0);
|
|
cv::rectangle(src, rect, color);
|
|
char text[256];
|
|
sprintf(text, "%s %.2f", it.className.c_str(), it.conf);
|
|
int baseLine = 0;
|
|
double fontScale = 0.4;
|
|
cv::Scalar fontColor = cv::Scalar(255, 255, 255);
|
|
cv::Size label_size = cv::getTextSize(text, cv::FONT_HERSHEY_SIMPLEX, 0.4, 1, &baseLine);
|
|
cv::rectangle(src, cv::Rect(cv::Point(it.x0, it.y0), cv::Size(label_size.width, label_size.height + baseLine)), color, -1);
|
|
cv::putText(src, text, cv::Point(it.x0, it.y0 + label_size.height), cv::FONT_HERSHEY_SIMPLEX, fontScale, fontColor);
|
|
}
|
|
cv::imwrite("./image_result/"+line+".jpg", src);
|
|
}
|
|
void SaveTxt(const std::string& result, const std::string& line)
|
|
{
|
|
auto res = ParseResult(result);
|
|
for (auto it : res) {
|
|
std::ofstream outfile("./txt_result/det_test_" + it.className + ".txt", std::ios::app);
|
|
char text[256];
|
|
sprintf(text, "%s %f %f %f %f %f\n", line.c_str(), it.conf, it.x0, it.y0, it.x1, it.y1);
|
|
outfile << text;
|
|
outfile.close();
|
|
}
|
|
}
|
|
|
|
double time_min = DBL_MAX;
|
|
double time_max = -DBL_MAX;
|
|
double time_avg = 0;
|
|
long loop_num = 0;
|
|
std::string pipelineConfigPath = "";
|
|
const std::string streamName = "detection";
|
|
std::string task;
|
|
std::string imageSetFile;
|
|
std::string imageSetPath;
|
|
bool saveImage = false, saveTxt = false;
|
|
int inPluginId = 0;
|
|
|
|
int work(const std::string& id, MxStream::MxStreamManager& mxStreamManager)
|
|
{
|
|
std::string img_path = imageSetPath+'/'+id+".jpg";
|
|
MxStream::MxstDataInput dataBuffer;
|
|
cv::Mat src;
|
|
int ret;
|
|
if (task == "eval") {
|
|
src = cv::imread(img_path);
|
|
cv::Mat img = letterBox(src);
|
|
cv::imwrite("./tmp.jpg", img);
|
|
ret = ReadFile("./tmp.jpg", dataBuffer);
|
|
}else if (task == "detect") {
|
|
src = cv::imread(img_path);
|
|
ret = ReadFile(img_path, dataBuffer);
|
|
}else {
|
|
ret = ReadFile(img_path, dataBuffer);
|
|
}
|
|
if (ret != APP_ERR_OK) {
|
|
LogError << GetError(ret) << "Failed to read image file.";
|
|
return ret;
|
|
}
|
|
// send data into stream
|
|
ret = mxStreamManager.SendData(streamName, inPluginId, dataBuffer);
|
|
if (ret != APP_ERR_OK) {
|
|
LogError << GetError(ret) << "Failed to send data to stream.";
|
|
delete dataBuffer.dataPtr;
|
|
dataBuffer.dataPtr = nullptr;
|
|
return ret;
|
|
}
|
|
// get stream output
|
|
MxStream::MxstDataOutput* output = mxStreamManager.GetResult(streamName, inPluginId);
|
|
if (output == nullptr) {
|
|
LogError << "Failed to get pipeline output.";
|
|
delete dataBuffer.dataPtr;
|
|
dataBuffer.dataPtr = nullptr;
|
|
return ret;
|
|
}
|
|
std::string result = std::string((char *)output->dataPtr, output->dataSize);
|
|
if (saveImage == true) { SaveImage(result, src, id); }
|
|
if (saveTxt == true) { SaveTxt(result, id); }
|
|
delete output;
|
|
delete dataBuffer.dataPtr;
|
|
dataBuffer.dataPtr = nullptr;
|
|
|
|
return 0;
|
|
}
|
|
int run()
|
|
{
|
|
std::ifstream in(imageSetFile);
|
|
std::string line;
|
|
// read pipeline config file
|
|
std::string pipelineConfig = ReadPipelineConfig(pipelineConfigPath);
|
|
if (pipelineConfig == "") {
|
|
LogError << "Read pipeline failed.";
|
|
return APP_ERR_COMM_INIT_FAIL;
|
|
}
|
|
MxStream::MxStreamManager mxStreamManager;
|
|
// init stream manager
|
|
APP_ERROR ret = mxStreamManager.InitManager();
|
|
if (ret != APP_ERR_OK) {
|
|
LogError << GetError(ret) << "Failed to init Stream manager.";
|
|
return ret;
|
|
}
|
|
// create stream by pipeline config file
|
|
ret = mxStreamManager.CreateMultipleStreams(pipelineConfig);
|
|
if (ret != APP_ERR_OK) {
|
|
LogError << GetError(ret) << "Failed to create Stream.";
|
|
return ret;
|
|
}
|
|
if (in) {
|
|
while (getline(in, line)) {
|
|
loop_num++;
|
|
auto start = clock();
|
|
work(line, mxStreamManager);
|
|
double time = (double)(clock() - start) / CLOCKS_PER_SEC;
|
|
time_min = (std::min)(time_min, time);
|
|
time_max = (std::max)(time_max, time);
|
|
time_avg += time;
|
|
}
|
|
time_avg /= loop_num;
|
|
}
|
|
in.close();
|
|
mxStreamManager.DestroyAllStreams();
|
|
return 0;
|
|
}
|
|
int main(int argc, char* argv[])
|
|
{
|
|
int index = 1;
|
|
task = argv[index++];
|
|
imageSetFile = argv[index++];
|
|
imageSetPath = argv[index];
|
|
if (task == "eval") {
|
|
pipelineConfigPath = "pipeline/eval.pipeline";
|
|
}else if (task == "speed" || task == "detect") {
|
|
pipelineConfigPath = "pipeline/detect.pipeline";
|
|
}else {
|
|
std::cout << "Undefined task!" << std::endl;
|
|
return 1;
|
|
}
|
|
if (task == "eval") { saveTxt = true; }
|
|
if (task == "detect") { saveImage = true; }
|
|
|
|
if (saveImage) { system("rm -rf image_result && mkdir image_result"); }
|
|
if (saveTxt) { system("rm -rf txt_result && mkdir txt_result"); }
|
|
int ret = run();
|
|
if (ret != 0) {
|
|
std::cout << "Failed to run" << std::endl;
|
|
return 1;
|
|
}
|
|
char msg[256];
|
|
const int millisecondPerSec = 1000;
|
|
sprintf(msg, "image count = %ld \nmin = %.2fms max = %.2fms avg = %.2fms \navg fps = %.2f fps\n", loop_num, time_min * millisecondPerSec, time_max * millisecondPerSec, time_avg * millisecondPerSec, millisecondPerSec / (time_avg * millisecondPerSec));
|
|
std::cout << "时间统计:\n";
|
|
std::cout << msg;
|
|
|
|
return 0;
|
|
} |