文章目录
- YOLOv3 从入门到部署:(五)YOLOv3模型的部署(基于C++ opencv)
-
YOLOv3 从入门到部署:(五)YOLOv3模型的部署(基于C++ opencv)
目录
关于opencv的DNN介绍
DNN是一个opencv的前向推理模块,支持从.onnx,.weights等格式的文件导入网络模型,然后进行前向推理。但是目前DNN有很多网络层不被支持,在我所使用的4.5.1版本中,即使是简单的torch.arange和torch.exp都不被支持。不过我最近发现在4.5.2预览版本的api文档中,DNN已经支持了这些网络层,也就是说以后使用DNN部署模型会更加方便。对于没有的网络层,我们可以使用自定义的方法,详细内容见下面的代码.
参考代码
链接1
链接2
本博客代码
https://github.com/qqsuhao/yolo-fastest-xl-based-on-opencv-DNN-using-onnx
代码讲解
yolo.h
#pragma once
#include <fstream>
#include <sstream>
#include <iostream>
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/core.hpp>
#include <opencv2/dnn/layer.details.hpp>
using namespace cv;
using namespace dnn;
using namespace std;
struct Net_config
{
float confThreshold;
float nmsThreshold;
int inpWidth;
int inpHeight;
string classesFile;
string modelConfiguration;
string modelWeights;
string netname;
};
class YOLO {
public:
YOLO(Net_config config);
void detect(Mat& frame);
void setcapSize(int width, int height);
private:
float confThreshold;
float nmsThreshold;
int inpWidth;
int inpHeight;
int capWidth;
int capHeight;
float scaleHeight;
float scaleWidth;
char netname[20];
vector<string> classes;
Net net;
void postprocess(Mat& frame, const vector<Mat>& outs);
void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame);
};
class ExpLayer : public cv::dnn::Layer {
public:
ExpLayer(const cv::dnn::LayerParams ¶ms) : Layer(params) {
}
static cv::Ptr<cv::dnn::Layer> create(cv::dnn::LayerParams& params) {
return cv::Ptr<cv::dnn::Layer>(new ExpLayer(params));
}
virtual bool getMemoryShapes(const std::vector<std::vector<int> > &inputs,
const int requiredOutputs,
std::vector<std::vector<int> > &outputs,
std::vector<std::vector<int> > &internals) const CV_OVERRIDE {
CV_UNUSED(requiredOutputs); CV_UNUSED(internals);
std::vector<int> outShape(4);
outShape[0] = inputs[0][0];
outShape[1] = inputs[0][1];
outShape[2] = inputs[0][2];
outShape[3] = inputs[0][3];
outputs.assign(1, outShape);
return false;
}
virtual void forward(cv::InputArrayOfArrays inputs_arr,
cv::OutputArrayOfArrays outputs_arr,
cv::OutputArrayOfArrays internals_arr) CV_OVERRIDE {
std::vector<cv::Mat> inputs, outputs;
inputs_arr.getMatVector(inputs);
outputs_arr.getMatVector(outputs);
cv::Mat& inp = inputs[0];
cv::Mat& out = outputs[0];
exp(inp, out);
}
};
yolo.cpp
#include "yolo.h"
YOLO::YOLO(Net_config config) {
cout << "Net use " << config.netname << endl;
this->confThreshold = config.confThreshold;
this->nmsThreshold = config.nmsThreshold;
this->inpWidth = config.inpWidth;
this->inpHeight = config.inpHeight;
strcpy_s(this->netname, config.netname.c_str());
ifstream ifs(config.classesFile.c_str());
string line;
while (getline(ifs, line)) this->classes.push_back(line);
this->net = readNetFromONNX(config.modelConfiguration);
this->net.setPreferableBackend(DNN_BACKEND_OPENCV);
this->net.setPreferableTarget(DNN_TARGET_CPU);
}
void YOLO::setcapSize(int width, int height) {
this->capHeight = height;
this->capWidth = width;
this->scaleHeight = float(this->capHeight) / this->inpHeight;
this->scaleWidth = float(this->capWidth) / this->inpWidth;
}
void YOLO::postprocess(Mat& frame, const vector<Mat>& outs)
{
vector<int> classIds;
vector<float> confidences;
vector<float> scores;
vector<Rect> boxes;
for (size_t i = 0; i < outs.size(); ++i) {
float* data = (float*)outs[i].data;
for (int j = 0; j < outs[i].rows; ++j, data += outs[i].cols) {
Mat score = outs[i].row(j).colRange(5, outs[i].cols);
Point classIdPoint;
double max_score;
minMaxLoc(score, 0, &max_score, 0, &classIdPoint);
if (data[4] > this->confThreshold) {
int centerX = (int)(data[0] * this->scaleWidth);
int centerY = (int)(data[1] * this->scaleHeight);
int width = (int)(data[2] * this->scaleWidth);
int height = (int)(data[3] * this->scaleHeight);
int left = centerX - width / 2;
int top = centerY - height / 2;
classIds.push_back(classIdPoint.x);
confidences.push_back(data[classIdPoint.x+5]);
scores.push_back(max_score*data[4]);
boxes.push_back(Rect(left, top, width, height));
}
}
}
vector<int> indices;
NMSBoxes(boxes, scores, this->confThreshold, this->nmsThreshold, indices);
for (size_t i = 0; i < indices.size(); ++i) {
int idx = indices[i];
Rect box = boxes[idx];
this->drawPred(classIds[idx], confidences[idx], box.x, box.y,
box.x + box.width, box.y + box.height, frame);
}
}
void YOLO::drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame)
{
rectangle(frame, Point(left, top), Point(right, bottom), Scalar(0, 0, 255), 3);
string label = format("%.2f", conf);
if (!this->classes.empty()) {
CV_Assert(classId < (int)this->classes.size());
label = this->classes[classId] + ":" + label;
}
int baseLine;
Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
top = max(top, labelSize.height);
putText(frame, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0, 255, 0), 2);
}
void YOLO::detect(Mat& frame) {
Mat blob;
blobFromImage(frame, blob, double(1 / 255.0), Size(this->inpWidth, this->inpHeight), Scalar(0, 0, 0), true, false);
this->net.setInput(blob);
vector<Mat> outs_blob;
vector<Mat> outs;
vector<String> names = this->net.getUnconnectedOutLayersNames();
this->net.forward(outs_blob, names);
int i = 0;
for (i = 0; i < outs_blob.size(); i++) {
vector<Mat> out;
imagesFromBlob(outs_blob[i], out);
outs.push_back(out[0]);
}
this->postprocess(frame, outs);
vector<double> layersTimes;
double freq = getTickFrequency() / 1000;
double t = net.getPerfProfile(layersTimes) / freq;
string label = format("%s Inference time : %.2f ms", this->netname, t);
putText(frame, label, Point(0, 30), FONT_HERSHEY_SIMPLEX, 1, Scalar(0, 0, 255), 2);
}
mian.cpp
#include "yolo.h"
using namespace cv;
using namespace std;
int main() {
CV_DNN_REGISTER_LAYER_CLASS(Exp, ExpLayer);
Net_config yolo_nets[1] = {
{ 0.5f, 0.3f, 320, 320,"coco.names", "yolo-fastest-xl.onnx", "yolo-fastest-xl.onnx", "yolo-fastest-xl" }
};
YOLO yolo_model(yolo_nets[0]);
static const string kWinName = "Deep learning object detection in OpenCV";
namedWindow(kWinName, WINDOW_KEEPRATIO);
VideoCapture cap;
cap.open(0);
Mat srcimg;
while (1) {
cap >> srcimg;
yolo_model.setcapSize(srcimg.cols, srcimg.rows);
yolo_model.detect(srcimg);
imshow(kWinName, srcimg);
waitKey(10);
}
destroyAllWindows();
return 0;
}
效果展示
release模式下,推理速度大约是50ms左右。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)