目录
一. 安装vs2022
在vs2022中使用qt进行界面设计,两个软件项目互通_稷滼的博客-CSDN博客
二. 新建动态链接库项目
点击创建新项目,搜索dll找到动态链接库的项目新建
创建后的样子
三. 配置opencv,和相应的属性配置
前提给自己opencv配置好环境变量
根据自己安装的opencv路径添加
VC++目录->包含目录:opencv\build\include\opencv2和opencv\build\include
VC++目录->库目录:opencv\build\x64\vc15\lib和opencv\build\x64\vc15\bin
连接器->输入->附加依赖项:opencv_world460d.lib (带d的是运行的Debug,不带d是Release)
字符集改为多字节字符集
C/C++->预编译头->预编译头:改为创建(/Yc),后期根据自己需要更改,也可以把预编译头文件中的.h文件去掉
四. 代码
创建头文件和源文件,名字随意
//yolo.h
#pragma once
#ifndef MY_HEADER_H
#define MY_HEADER_H
#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
#include "windows.h"
using namespace std;
using namespace cv;
const int INPUT_WIDTH = 640;
const int INPUT_HEIGHT = 640;
const float SCORE_THRESHOLD = 0.5;
const float NMS_THRESHOLD = 0.45;
const float CONFIDENCE_THRESHOLD = 0.45;
extern "C" _declspec(dllexport) void pre_process(cv::Mat & image, cv::Mat & blob);
extern "C" _declspec(dllexport) void a_process(cv::Mat & blob, cv::dnn::Net & net, std::vector<cv::Mat>&outputs);
extern "C" _declspec(dllexport) void draw_result(cv::Mat & image, std::string label, cv::Rect box);
extern "C" _declspec(dllexport) cv::Mat post_process(cv::Mat& image, std::vector<cv::Mat>& outputs, std::vector<std::string>& class_name);
extern "C" _declspec(dllexport) int main();
#endif
//yolo.cpp
#include "yolo.h"
#include "pch.h"
void pre_process(cv::Mat& image, cv::Mat& blob)
{
cv::dnn::blobFromImage(image, blob, 1. / 255., cv::Size(INPUT_WIDTH, INPUT_HEIGHT), cv::Scalar(), true, false);
}
void a_process(cv::Mat& blob, cv::dnn::Net& net, std::vector<cv::Mat>& outputs)
{
net.setInput(blob);
net.forward(outputs, net.getUnconnectedOutLayersNames());
}
void draw_result(cv::Mat& image, std::string label, cv::Rect box)
{
cv::rectangle(image, box, cv::Scalar(255, 0, 0), 2);
int baseLine;
cv::Size label_size = cv::getTextSize(label, 0.8, 0.8, 1, &baseLine);
cv::Point tlc = cv::Point(box.x, box.y);
cv::Point brc = cv::Point(box.x, box.y + label_size.height + baseLine);
cv::putText(image, label, cv::Point(box.x, box.y), cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(0, 255, 255), 1);
}
cv::Mat post_process(cv::Mat& image, std::vector<cv::Mat>& outputs, std::vector<std::string>& class_name)
{
std::vector<int> class_ids;
std::vector<float> confidences;
std::vector<cv::Rect> boxes;
float x_factor = (float)image.cols / INPUT_WIDTH;
float y_factor = (float)image.rows / INPUT_HEIGHT;
float* data = (float*)outputs[0].data;
const int dimensions = 85;
const int rows = 25200;
for (int i = 0; i < rows; ++i)
{
float confidence = data[4];
if (confidence >= CONFIDENCE_THRESHOLD)
{
float* classes_scores = data + 5;
cv::Mat scores(1, class_name.size(), CV_32FC1, classes_scores);
cv::Point class_id;
double max_class_score;
cv::minMaxLoc(scores, 0, &max_class_score, 0, &class_id);
if (max_class_score > SCORE_THRESHOLD)
{
float x = data[0];
float y = data[1];
float w = data[2];
float h = data[3];
int left = int((x - 0.5 * w) * x_factor);
int top = int((y - 0.5 * h) * y_factor);
int width = int(w * x_factor);
int height = int(h * y_factor);
boxes.push_back(cv::Rect(left, top, width, height));
confidences.push_back(confidence);
class_ids.push_back(class_id.x);
}
}
data += dimensions;
}
std::vector<int> indices;
cv::dnn::NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, indices);
for (int i = 0; i < indices.size(); i++)
{
int idx = indices[i];
cv::Rect box = boxes[idx];
std::string label = class_name[class_ids[idx]] + ":" + cv::format("%.2f", confidences[idx]);
draw_result(image, label, box);
}
return image;
}
int main()
{
std::vector<std::string> class_name = { "person", "bicycle", "car","motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light", "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow", "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee", "skis", "snowboard", "sports ball" ,"toothbrush" };
std::string line;
//输入一个自己的视频路径,也可以加图片
cv::VideoCapture cap("C:/Users/le/Desktop/ceshi.mp4");
cv::Mat image, blob;
while (cap.read(image))
{
pre_process(image, blob);
cv::dnn::Net net = cv::dnn::readNet("C:/Users/le/Desktop/yolov5/yolov5-cls-det-seg-opencv-main/yolov5n-det.onnx");
std::vector<cv::Mat> detections;
a_process(blob, net, detections);
cv::Mat result = post_process(image, detections, class_name);
cv::imshow("detection", result);
if (waitKey(25) == 27) {
break;
}
}
cap.release();
return 0;
}
“extern”关键字是C/C++中用来声明外部变量或函数的关键字,它告诉编译器这个变量或函数在其他文件中定义,需要在当前文件中使用。因为在C/C++中,所有变量和函数默认都是内部的,也就是智能在当前文件中使用,如果要在其他文件中使用,需要使用extern关键字来声明。
“_declspec(dllexport)”是Windows平台特有的关键字,用于在编写动态链接库(DLL)时,指定导出函数或变量。在windows平台上,动态链接库的函数和变量需要使用_declspec(dllexport)关键字进行声明,一遍再DLL中进行导出。这样做可以使得其他程序可以调用这个DLL中的函数或变量。
总之,extern “C” _declspec(dllexport)是用来再C/C++语言中定义并导出函数或变量到动态链接库中的关键字。
如果自己的视频过大可以再代码中调整大小
cv::resize(result, result, cv::Size(680, 560));
调整好代码后,右击自己创建的项目,生成或重新生成。
跟这个差不多就是创建成功,显示的路径就是你的动态链接库所在的位置。
链接: https://pan.baidu.com/s/1HHbGwC62KG1skNc5ocvSXA
提取码: rjaz
这是代码中onnx模型
右击解决方案,添加新项目,整个空项目就可以
属性配置opencv
图中附加包含目录添加动态链接库中代码所在的路径(yolo.h和yolo.cpp)
图中附加库目录添加生成的动态链接库所在的路径
附加依赖项添加生成的lib的名称
#pragma comment(dll,"Dll1.dll") 添加自己的名称生成后运行
效果
有任何问题,评论区