第一步:安装Opencv
安装Opencv参考链接:安装OpenCV
获取yolov5s.pt权值文件
使用的是轻量的yolov5s
模型,在本地训练后,通过命令发送发到树莓派上:
- 首先查看树莓派地址:
ifconfig # 查看地址
连接的wify,可以看到所属的地址端口。
- 将本地导出的
best.onnx
权值文件发送到树莓派上:
scp best.onnx <用户名>@<树莓派地址>:<保存文件地址>
- 推理代码
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <chrono> // 添加时间测量头文件
using namespace cv;
using namespace cv::dnn;
std::vector<std::string> classes = {
"defective_insulator","broken_defect","good_insulator","flashover_defect"
};
int main() {
// 1. 输入图片路径
std::string img_path = "images/insulator.jpg"; // 输入图片路径
Mat frame = imread(img_path);
if(frame.empty()) {
std::cerr << "Error: Could not read the image." << std::endl;
return -1;
}
// 2. 加载模型
Net net = cv::dnn::readNetFromONNX("weights/ZJ/best.onnx");
net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
net.setPreferableTarget(cv::dnn::DNN_TARGET_OPENCL);
// 打印模型信息
// std::cout << "Network layers:" << std::endl;
// for (int i = 0; i < net.getLayerNames().size(); i++) {
// std::cout << net.getLayerNames()[i] << std::endl;
// }
if (net.empty()) {
std::cerr << "Error: Could not load the neural network." << std::endl;
return -1;
}
// 3. 预处理参数设置
const int input_width = 512;
const int input_height = 512;
float x_factor = frame.cols / (float)input_width; // 修改为动态计算
float y_factor = frame.rows / (float)input_height;
// 预处理计时
auto preprocess_start = std::chrono::high_resolution_clock::now();
// 4. 图像预处理(增加letterbox处理)
Mat resized;
int new_width, new_height;
if (frame.cols > frame.rows) {
new_width = input_width;
new_height = (int)(frame.rows * input_width / (float)frame.cols);
} else {
new_height = input_height;
new_width = (int)(frame.cols * input_height / (float)frame.rows);
}
resize(frame, resized, Size(new_width, new_height));
Mat blob = blobFromImage(resized, 1/255.0, Size(input_width, input_height), Scalar(0,0,0), true, false);
// blob.convertTo(blob, CV_16F); // 半精度计算
// 预处理计时结束
auto preprocess_end = std::chrono::high_resolution_clock::now();
// 推理计时
auto inference_start = std::chrono::high_resolution_clock::now();
net.setInput(blob);
// 5. 推理后处理
cv::Mat preds =net.forward();
// 推理计时结束
auto inference_end = std::chrono::high_resolution_clock::now();
// 后处理计时
auto postprocess_start = std::chrono::high_resolution_clock::now();
std::vector<int> class_ids;
std::vector<float> confidences;
std::vector<Rect> boxes;
std::cout << "rows: "<< preds.size[1]<< " data: " << preds.size[2] << std::endl;
// cv::Mat det_output(preds.size[1], preds.size[2], CV_32F, preds.ptr<float>());
cv::Mat det_output = preds.reshape(1, preds.size[1]); // 避免内存复制
//In a typical YOLO output, the format is [x_center, y_center, width, height, object_confidence, class_score1, class_score2, ..., class_scoreN] for each bounding box.
for (int i = 0; i < det_output.rows; i++) {
float confidence = det_output.at<float>(i, 4);
cv::Mat class_scores = det_output.row(i).colRange(5, 5 + classes.size());
Point class_id_point;
double max_class_score;
minMaxLoc(class_scores, NULL, &max_class_score, NULL, &class_id_point);
int class_id = class_id_point.x;
float final_confidence = confidence * max_class_score;
// std::cout << "Final confidence: " << final_confidence << std::endl;
if (final_confidence < 0.45) {
continue;
}
float cx = det_output.at<float>(i, 0);
float cy = det_output.at<float>(i, 1);
float ow = det_output.at<float>(i, 2);
float oh = det_output.at<float>(i, 3);
int x = static_cast<int>((cx - 0.5 * ow) * x_factor);
int y = static_cast<int>((cy - 0.5 * oh) * y_factor);
int width = static_cast<int>(ow * x_factor);
int height = static_cast<int>(oh * y_factor);
boxes.push_back(Rect(x, y, width, height));
confidences.push_back(final_confidence);
class_ids.push_back(class_id);
}
std::vector<int> indices;
dnn::NMSBoxes(boxes, confidences, 0.6, 0.3, indices);
// Draw the final bounding boxes
for (size_t i = 0; i < indices.size(); ++i) {
int idx = indices[i];
Rect box = boxes[idx];
cv::rectangle(frame, cv::Point(box.x, box.y), cv::Point(box.x + box.width, box.y + box.height), cv::Scalar(0, 0, 255), 2, 8);
std::string label = classes[class_ids[idx]] + ": " + std::to_string(confidences[idx]);
putText(frame, label.c_str(), Point(box.x, box.y - 10), FONT_HERSHEY_SIMPLEX, 0.9, Scalar(0, 255, 0), 2);
}
auto postprocess_end = std::chrono::high_resolution_clock::now();
// 输出各阶段耗时(单位:ms)
float preprocess_time = std::chrono::duration_cast<std::chrono::milliseconds>(preprocess_end - preprocess_start).count();
float inference_time = std::chrono::duration_cast<std::chrono::milliseconds>(inference_end - inference_start).count();
float postprocess_time = std::chrono::duration_cast<std::chrono::milliseconds>(postprocess_end - postprocess_start).count();
// 计算总耗时(单位:ms)
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(postprocess_end - preprocess_start).count();
std::cout << "预处理: " << preprocess_time << " ms" << std::endl;
std::cout << "推理: " << inference_time << " ms" << std::endl;
std::cout << "后处理: " << postprocess_time << " ms" << std::endl;
std::cout << "总耗时: " << duration << " ms" << std::endl;
float fps = 1000.0 / duration; // 计算FPS
std::cout << "FPS: " << fps << std::endl;
// 6. 显示结果(取消视频循环)
imshow("Object Detection", frame);
waitKey(0); // 改为等待按键
return 0;
}