Qt C++使用YOLOV2模型实时检测摄像头视频中的车辆的源代码(CPU检测)

Qt C++使用YOLOV2模型实时检测摄像头视频中的车辆的源代码(CPU检测)
一、主函数

#include <QApplication>
#include <opencv2/opencv.hpp>
#include "dnnvehicledetectclass.h"
using namespace cv;
using namespace std;

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);
    DnnVehicleDetectClass dnn;
    VideoCapture cap("rtsp://admin:admin123@192.168.1.108:554/cam/realmonitor?channel=1&subtype=1");
    if (!cap.isOpened()) {
        cerr << "Failed to open video stream!" << endl;
        return -1;
    }
    
    Mat frame;
    while (true) {
        cap.read(frame);
        if (frame.empty()) {
            cerr << "Failed to read frame from video stream!" << endl;
            break;
        }
        dnn.dnnVehicleDetect(frame);
        imshow("Frame", frame);
        
        // Check for ESC key press
        if (waitKey(30) == 27) { // 使用 30 毫秒延迟
            break;
        }
    }
    
    // Release resources
    cap.release();
    destroyAllWindows();
    return 0;
}

#include "main.moc"

二、 DnnVehicleDetectClass的头文件

#ifndef DNNVEHICLEDETECTCLASS_H
#define DNNVEHICLEDETECTCLASS_H
#include <QDir>
#include <QString>
#include <QDebug>
#include <QTimer>
#include <direct.h>
#include <QThread>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

class DnnVehicleDetectClass: public QThread {

    Q_OBJECT

public:
    DnnVehicleDetectClass();
    static vector<String> getOutputsNames(const cv::dnn::Net& net);
    void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame, const vector<string>& classes);
    void postprocess(Mat& frame, const vector<Mat>& outs, const vector<string>& classes);
    Mat dnnVehicleDetect(Mat img);
};

#endif // DNNVEHICLEDETECTCLASS_H

三、 DnnVehicleDetectClass的源文件

#include "dnnvehicledetectclass.h"

DnnVehicleDetectClass::DnnVehicleDetectClass()
{

}

// 从网络获取输出层名称的函数
vector<String> DnnVehicleDetectClass::getOutputsNames(const cv::dnn::Net& net) {
    static vector<String> names;
    if (names.empty()) {
        //获取输出层的索引,即具有未连接输出的层
        vector<int> outLayers = net.getUnconnectedOutLayers();
        vector<String> layersNames = net.getLayerNames();
        names.resize(outLayers.size());
        for (size_t i = 0; i < outLayers.size(); ++i)
            names[i] = layersNames[outLayers[i] - 1];
    }
    return names;
}

// 在图像上绘制边界框的函数
void DnnVehicleDetectClass::drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame, const vector<string>& classes) {
    rectangle(frame, Point(left, top), Point(right, bottom), Scalar(255, 178, 50), 3);
    
    // 获取类名及其可信度的标签
    string label = format("%.2f", conf);
    if (!classes.empty()) {
        CV_Assert(classId < (int)classes.size());
        label = classes[classId] + ": " + label;
    }
    
    // 在边界框的顶部显示标签
    int baseLine;
    Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
    top = max(top, labelSize.height);
    rectangle(frame, Point(left, top - round(1.5*labelSize.height)), Point(left + round(1.5*labelSize.width), top + baseLine), Scalar(255, 255, 255), FILLED);
    putText(frame, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 0.75, Scalar(0,0,0), 1);
}

// 使用非最大值抑制删除低置信度边界框的功能
void DnnVehicleDetectClass::postprocess(Mat& frame, const vector<Mat>& outs, const vector<string>& classes) {
    vector<int> classIds;
    vector<float> confidences;
    vector<Rect> boxes;
    
    for (size_t i = 0; i < outs.size(); ++i) {
        // 网络生成形状为NxC的输出blob,其中N是检测到的对象的数量
        // C是类别数+4,其中前4个数字是[center_x,center_y,width,height]
        float* data = (float*)outs[i].data;
        for (int j = 0; j < outs[i].rows; ++j, data += outs[i].cols) {
            Mat scores = outs[i].row(j).colRange(5, outs[i].cols);
            Point classIdPoint;
            double confidence;
            minMaxLoc(scores, 0, &confidence, 0, &classIdPoint);
            if (confidence > 0.5) { // Confidence threshold
                int centerX = (int)(data[0] * frame.cols);
                int centerY = (int)(data[1] * frame.rows);
                int width = (int)(data[2] * frame.cols);
                int height = (int)(data[3] * frame.rows);
                int left = centerX - width / 2;
                int top = centerY - height / 2;
                
                classIds.push_back(classIdPoint.x);
                confidences.push_back((float)confidence);
                boxes.push_back(Rect(left, top, width, height));
            }
        }
    }
    
    //执行非最大抑制,以消除置信度较低的冗余重叠框。
    vector<int> indices;
    dnn::NMSBoxes(boxes, confidences, 0.5, 0.4, indices);
    for (size_t i = 0; i < indices.size(); ++i) {
        int idx = indices[i];
        Rect box = boxes[idx];
        drawPred(classIds[idx], confidences[idx], box.x, box.y, box.x + box.width, box.y + box.height, frame, classes);
    }
}

Mat DnnVehicleDetectClass::dnnVehicleDetect(Mat img) {
    try {
        //加载预训练模型
        cv::dnn::Net net = cv::dnn::readNetFromDarknet("./yolo.cfg", "./yolov2.weights");
        if (net.empty()) {
            cerr << "Failed to load the network!" << endl; //网络加载失败
            return cv::Mat();
        }
        cout << "Successfully loaded the network!" << endl; //网络加载成功
        
        
        if (img.empty()) {
            cerr << "Failed to load image!" << endl; //无法加载图像
            return cv::Mat();
        }
        // 从图像创建blob并将其设置为网络的输入
        /*  将图像大小调整为 416x416。
            将像素值除以 255.0 进行归一化。
            使用 Scalar() 表示没有均值减法。
            true 表示交换 BGR 和 RGB 通道顺序。
            false 表示不裁剪图像。
        */
        Mat inputBlob = dnn::blobFromImage(img, 1 / 255.0, Size(416, 416), Scalar(), true, false);
        net.setInput(inputBlob);
        // 在网络中执行前向传递
        vector<Mat> outs;
        net.forward(outs, getOutputsNames(net));
        // 定义类标签列表(这应该与您的YOLO配置文件相匹配)
        vector<string> classes;
        ifstream ifs("./coco.names"); //或等效名称的路径
        string line;
        while (getline(ifs, line)) 
            classes.push_back(line);
        // 对输出进行后处理以绘制边界框
        postprocess(img, outs, classes); //使用非最大值抑制删除低置信度边界框的功能
        return img;
        
    } catch (const cv::Exception& e) {
        cerr << "Error: " << e.what() << endl;
        return cv::Mat();
    }
}

四、需要解决的问题:
1、如何在GPU执行?
2、如何跟踪识别的车辆,并赋予唯一ID?并根据唯一ID计数?
3、如何做到实时显示过车数并且视频不卡顿?
请各位同仁完善代码!
五、需求环境:
Qt Creater 4.11.1
Qt 5.14.1
opencv 4.1.2
c++11

秋风写于淄博,技术交流与业务合作:Q375172665

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值