【项目】yolov8+qt+onnx

写在前面

python太慢,搞C

Qt配置onnx_runtime

首先,onnx_runtime官方也给编译好的release版本,下载即可。但是在qt中配置有一个坑。
在这里插入图片描述
在Qt Creator中正常添加外部库,但是你会发现构建会找不到onnxruntime.lib,这是如果你替换成全路径,即把注释的部分换成下面的lib路径,直接指明onnxruntime.lib。这时构建成功,可以include <onnxruntime_cxx_api.h>,但是在运行你会遇到应用程序无法启动。
在这里插入图片描述
根据百度把onnxruntime.dll复制到.exe目录下。
在这里插入图片描述
OK,启动成功。

opencv读取视频流

居中显示,随意拉伸。
在这里插入图片描述
在这里插入图片描述
实现居中的逻辑:

// 调整QImage的大小以匹配QLabel的大小
QPixmap scaledPixmap = QPixmap::fromImage(qimg).scaled(ui->Origin_Video->size(), Qt::KeepAspectRatio, Qt::FastTransformation);

而在界面当中需要对窗口随意拉伸,这是就需要界面允许缩放。修改QLabel的属性:
在这里插入图片描述
修改成minimum,并给定最小宽度和高度。(还不知道原因,等有空学习一下)

最后opencv读取视频流并拉取每一帧显示在QLabel中,这里采用的是用一个Qtimer,定时去获取视频帧。

// 创建定时器,每隔一定时间显示下一帧
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &MainWindow::showNextFrame);
timer->start(33);  // 设置帧率为30FPS,即每隔33毫秒显示一帧

完整代码如下:

// 在槽函数中处理视频的加载和显示
void MainWindow::on_actionvideo_triggered()
{
    camera->stop();
    viewfinder->close();
    QString curPath = QDir::homePath();
    QString dlgTitle = "选择视频文件";
    QString filter = "视频文件(*.wmv *.mp4);;所有文件(*.*)";
    QString aFile = QFileDialog::getOpenFileName(this, dlgTitle, curPath, filter);

    if (aFile.isEmpty()) {
        return;
    }

    ui->dir_Edit->setText(aFile);

    currentSource = File;  // 更新当前视频源为视频文件
    displayVideo();  // 显示视频

}

// 根据当前视频源显示视频的函数
void MainWindow::displayVideo()
{
    if (currentSource == File) {
        std::string video_path = ui->dir_Edit->text().toLocal8Bit().constData();
        cap.open(video_path);
        if (!cap.isOpened()) {
            qDebug() << "Error: Unable to open the video file";
            return;
        }

        // 创建定时器,每隔一定时间显示下一帧
        timer = new QTimer(this);
        connect(timer, &QTimer::timeout, this, &MainWindow::showNextFrame);
        timer->start(33);  // 设置帧率为30FPS,即每隔33毫秒显示一帧
    } else if (currentSource == Camera) {

        // 创建定时器,每隔一定时间显示下一帧
        timer = new QTimer(this);
        connect(timer, &QTimer::timeout, this, &MainWindow::viewfinderchange);
        timer->start(33);  // 设置帧率为30FPS,即每隔33毫秒显示一帧
//        cameras = QCameraInfo::availableCameras();   //获取所有相机的列表
//        camera = new QCamera(cameras[0]);                //camera指向指定的摄像头
        camera->setCaptureMode(QCamera::CaptureStillImage);  //设定捕获模式
        camera->setViewfinder(viewfinder);                   //设置取景器
        camera->start();

    }
}

// 显示下一帧的槽函数
void MainWindow::showNextFrame()
{
    cv::Mat frame;
    cap >> frame; // 从视频流中获取一帧

    if (frame.empty()) {
        cap.set(cv::CAP_PROP_POS_FRAMES, 0); // 如果视频结束,重新开始播放
        cap >> frame;
    }

    currentFrame = frame;  // 保存当前帧
    displayCurrentFrame();  // 显示当前帧
}

void MainWindow::displayCurrentFrame() {
    // 将OpenCV帧转换为QImage
    QImage qimg(currentFrame.data, currentFrame.cols, currentFrame.rows, currentFrame.step, QImage::Format_RGB888);
    qimg = qimg.rgbSwapped(); // 将格式从BGR转换为RGB


    // 调整QImage的大小以匹配QLabel的大小
    QPixmap scaledPixmap = QPixmap::fromImage(qimg).scaled(ui->Origin_Video->size(), Qt::KeepAspectRatio, Qt::FastTransformation);

    // 将调整大小后的图像居中显示在QLabel中
    centerImageInLabel(ui->Origin_Video, scaledPixmap);
}

QCamra

居中显示,随意拉伸
在这里插入图片描述
QCamera其实同理,中间拉伸也用了一个QTimer定时获取QLabel的size。
QCamera的使用包括初始化一个camera和设置取景器viewfinder,viewfinder的作用就是控制图像在空间中的展示。

void MainWindow::on_actioncamera_triggered()
{

    cameras = QCameraInfo::availableCameras();   //获取所有相机的列表
    //qDebug() << "this is camera: ";
    if (cameras.count() > 0) {
        for(const QCameraInfo &cameraInfo:cameras) {
            qDebug() << cameraInfo.description();
        }
        camera = new QCamera(cameras.at(0));     //初始化实例化一个相机对象
    }
    //设置取景器
    viewfinder = new QCameraViewfinder(ui->Origin_Video);
    camera->setViewfinder(viewfinder);
    centerCameraViewfinderInLabel(viewfinder, ui->Origin_Video);

    camera->start();                             //开启相机

    //设置默认摄像头参数
    QCameraViewfinderSettings set;
    //    set.setResolution(640, 480);                 //设置显示分辨率
    set.setMaximumFrameRate(30);                 //设置帧率
    camera->setViewfinderSettings(set);

    stopVideo();
    ui->Origin_Video->setPixmap(QPixmap(""));
    currentSource = Camera;  // 更新当前视频源为摄像头
    viewfinder->show();
    displayVideo();  // 显示视频


}

yolov8 onnx 推理

void MainWindow::on_actionTest_triggered()
{

    //    std::string projectBasePath = "./"; // Set your ultralytics base path
    QString qs = QCoreApplication::applicationDirPath();
    std::string projectBasePath = qs.toLocal8Bit().constData();

    bool runOnGPU = false;

    // Note that in this example the classes are hard-coded and 'classes.txt' is a place holder.
    Inference inf(projectBasePath + "/moust_best.onnx", cv::Size(640, 640), "mouse.txt", runOnGPU);


    std::string video_path = ui->dir_Edit->text().toLocal8Bit().constData();
    // 读取视频文件
    //    cv::VideoCapture cap(projectBasePath + "/video/video.mp4");
    cv::VideoCapture cap(video_path);

    if (!cap.isOpened()) {
        std::cout << "Error opening video file" << std::endl;
        return ;
    }

    cv::Mat frame;

    while (cap.read(frame)) {
        // 推断开始...
        std::vector<Detection> output = inf.runInference(frame);

        int detections = output.size();
        std::cout << "Number of detections:" << detections << std::endl;

        for (int i = 0; i < detections; ++i)
        {
            Detection detection = output[i];

            cv::Rect box = detection.box;
            cv::Scalar color = detection.color;

            // Detection box
            cv::rectangle(frame, box, color, 2);

            // Detection box text
            std::string classString = detection.className + ' ' + std::to_string(detection.confidence).substr(0, 4);
            cv::Size textSize = cv::getTextSize(classString, cv::FONT_HERSHEY_DUPLEX, 1, 2, 0);
            cv::Rect textBox(box.x, box.y - 40, textSize.width + 10, textSize.height + 20);

            cv::rectangle(frame, textBox, color, cv::FILLED);
            cv::putText(frame, classString, cv::Point(box.x + 5, box.y - 10), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 0), 2, 0);
        }
        // 推断结束...

        // 仅用于预览
        float scale = 0.8;
        cv::resize(frame, frame, cv::Size(frame.cols*scale, frame.rows*scale));
        cv::imshow("Inference", frame);

        if (cv::waitKey(1) == 27) {
            break;
        }
    }

    cap.release();
    cv::destroyAllWindows();

}

多线程(onnx推理线程和界面主线程)

在这里插入图片描述
摄像头与onnx互不干扰,说明主界面线程与onnx推理是分开线程进行的,ok!

######################### 2024 05 09 更新 ##############################################
在这里插入图片描述

  • 8
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值