Qt-YOLO-OpenCV

一、绪论

从零开始配置Qt-YOLO-OpenCV。

二、配置OpenCV

网址:

https://opencv.org/releases/

三、配置YOLO

网址:

https://github.com/ultralytics/ultralytics

模型和推理的关系

维度 模型 (Model) 推理 (Inference)
本质 静态的知识库(数据文件) 动态的计算过程(程序运行)
类比 菜谱 按菜谱烹饪
存在形式 .pt, .onnx, .bin 等文件 一段代码或一个正在运行的程序
内容 网络结构、权重参数 加载、计算、输出等逻辑
作用 定义"做什么"和"怎么做"的规则 执行规则,完成具体任务
依赖关系 推理的基础和依据 模型的使用者和实现者

3.1下载模型

点击YOLO11s,下载好就这样

将pt格式转换为onnx

维度 PyTorch (.pt) 格式 ONNX (.onnx) 格式
性质与目的 研发框架专用格式,用于保存完整的训练状态。 跨平台交换标准,用于在不同框架和硬件间部署。
主要用途 模型训练、微调、继续训练和PyTorch环境内推理。 模型跨平台部署、性能优化(如TensorRT/OpenVINO转换)。
包含内容 完整状态:网络结构、权重、优化器状态、epoch等。 精简计算图:网络结构、权重、固定输入输出节点。
平台依赖 强依赖PyTorch及其Python生态。 弱依赖,任何支持ONNX标准的运行时均可加载。
可编辑性 ,可直接加载并修改结构、继续训练。 极低,通常视为只读的推理模型,难以直接修改或训练。
性能优化 依赖PyTorch自身优化和TorchScript。 作为中间格式,可被专用推理引擎(如ONNX Runtime、TensorRT)深度优化。
标准化程度 由PyTorch定义,是事实标准 由开放联盟定义,是行业开放标准

具体步骤:

新建python文件复制下面的代码

cpp 复制代码
from ultralytics import YOLO

model = YOLO("yolo11n.pt")  

export_path = model.export(format="onnx")  

运行后会生成onnx格式文件

3.2下载推理代码

将整个项目下载后找到这个路径

四、配置cmake,将OpenCV和YOLO集成到qt

OpenCV(注意这个对应的编译器是mscv2019)

cpp 复制代码
# 替换为你实际的OpenCV lib目录(包含OpenCVConfig.cmake的路径)
set(OpenCV_DIR "D:/opencv/build/x64/vc16/lib")

# 查找OpenCV库(基于上面设置的绝对路径)
find_package(OpenCV REQUIRED)

# 链接OpenCV库
target_link_libraries(demo PRIVATE
    ${OpenCV_LIBS}
)

# 添加OpenCV头文件路径
target_include_directories(demo PRIVATE
    ${OpenCV_INCLUDE_DIRS}
)

五、ui设计

添加inference文件

将这两个文件添加到你上面创建的项目中

mainwindow.h

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include"inference.h"
#include<QFileDialog>
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    void on_open_clicked();

private:
    Ui::MainWindow *ui;
      Inference *inf{nullptr};
};
#endif // MAINWINDOW_H

mainwindow.cpp

cpp 复制代码
#include "mainwindow.h"
#include "./ui_mainwindow.h"
using namespace std;
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
    if (inf) {
        delete inf;
        inf = nullptr;
    }

}
cv::Mat QImageToCvMat(const QImage &qimage)
{
    switch(qimage.format()) {
    case QImage::Format_RGB32:    // 最常见格式(ARGB,忽略Alpha)
    case QImage::Format_ARGB32:
    case QImage::Format_ARGB32_Premultiplied: {
        cv::Mat mat(qimage.height(), qimage.width(), CV_8UC4,
                    (void*)qimage.constBits(), qimage.bytesPerLine());

        // 移除Alpha通道,将ARGB转为BGR
        cv::Mat mat_rgb;
        cv::cvtColor(mat, mat_rgb, cv::COLOR_BGRA2BGR);
        return mat_rgb;
    }

    case QImage::Format_RGB888: { // 24位RGB
        cv::Mat mat(qimage.height(), qimage.width(), CV_8UC3,
                    (void*)qimage.constBits(), qimage.bytesPerLine());

        // RGB转BGR
        cv::Mat mat_bgr;
        cv::cvtColor(mat, mat_bgr, cv::COLOR_RGB2BGR);
        return mat_bgr;
    }

    case QImage::Format_Grayscale8: { // 灰度图
        cv::Mat mat(qimage.height(), qimage.width(), CV_8UC1,
                    (void*)qimage.constBits(), qimage.bytesPerLine());
        return mat.clone(); // 需要clone以确保数据连续
    }

    default:
        // 转换为24位RGB再处理
        QImage converted = qimage.convertToFormat(QImage::Format_RGB888);
        return QImageToCvMat(converted);
    }
}
// 在 QImageToCvMat 函数后面添加这个函数
QImage cvMatToQImage(const cv::Mat &mat)
{
    switch(mat.type()) {
    // 8-bit, 4 channel
    case CV_8UC4: {
        QImage image(mat.data, mat.cols, mat.rows,
                     static_cast<int>(mat.step), QImage::Format_ARGB32);
        return image.copy();
    }
    // 8-bit, 3 channel
    case CV_8UC3: {
        QImage image(mat.data, mat.cols, mat.rows,
                     static_cast<int>(mat.step), QImage::Format_RGB888);
        return image.rgbSwapped();  // BGR to RGB
    }
    // 8-bit, 1 channel
    case CV_8UC1: {
        QImage image(mat.data, mat.cols, mat.rows,
                     static_cast<int>(mat.step), QImage::Format_Grayscale8);
        return image.copy();
    }
    default: {
        qWarning() << "cv::Mat image type not handled in switch:" << mat.type();
        return QImage();
    }
    }
}
void MainWindow::on_open_clicked()
{
    qDebug() << "按钮被点击";

    QString filePath = QFileDialog::getOpenFileName(
        this,
        "选择图片",
        "",
        "图片文件 (*.jpg *.jpeg *.png *.bmp *.gif)"
        );

    if (filePath.isEmpty()) return;

    QImage image(filePath);
    if (image.isNull()) {

        return;
    }

    // 先显示原始图片
    QPixmap originalPixmap = QPixmap::fromImage(image);

    // 计算合适的尺寸,保持图片比例,同时确保按钮可见
    QSize labelSize = ui->show->size();
    QPixmap scaledPixmap = originalPixmap.scaled(
        labelSize.width() - 20,  // 留出边距
        labelSize.height() - 60,  // 留出按钮空间
        Qt::KeepAspectRatio,
        Qt::SmoothTransformation
        );

    // 显示原始图片
    ui->show->setPixmap(scaledPixmap);
    ui->show->setAlignment(Qt::AlignCenter);

    // 设置按钮文本
    ui->open->setText("推理中...");
    ui->open->setEnabled(false);

    // 立即更新界面显示
    QCoreApplication::processEvents();

    // 进行推理
    string onnxPath = "D:/qtdemo/Fire/YOLO/yolo11s.onnx";
    string classesPath = "D:/qtdemo/Fire/YOLO/classes.txt";
    bool runOnGPU = false;

    // 如果之前有推理器,先删除
    if (inf) {
        delete inf;
        inf = nullptr;
    }

    try {
        inf = new Inference(onnxPath, cv::Size(640, 640), classesPath, runOnGPU);

        cv::Mat frame = QImageToCvMat(image);

        // 如果图像有 alpha 通道,转换为 BGR
        if (frame.channels() == 4) {
            cv::cvtColor(frame, frame, cv::COLOR_BGRA2BGR);
        }

        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;

            // 绘制检测框
            cv::rectangle(frame, box, color, 2);

            // 绘制检测框文本
            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);
        }

        // 将处理后的 OpenCV Mat 转换为 QImage
        QImage resultImage = cvMatToQImage(frame);

        // 计算合适的尺寸显示结果图片
        QPixmap resultPixmap = QPixmap::fromImage(resultImage);
        QSize labelSize = ui->show->size();
        QPixmap scaledResult = resultPixmap.scaled(
            labelSize.width() - 20,
            labelSize.height() - 60,  // 为按钮留出空间
            Qt::KeepAspectRatio,
            Qt::SmoothTransformation
            );

        // 在 QLabel 中显示结果图片
        ui->show->setPixmap(scaledResult);
        ui->show->setAlignment(Qt::AlignCenter);

        // 恢复按钮状态
        ui->open->setText("重新选择图片");
        ui->open->setEnabled(true);

        // 显示检测结果统计
        if (detections > 0) {
            QString message = QString("检测到 %1 个目标").arg(detections);

        }

    } catch (const std::exception& e) {
        qDebug() << "推理错误:" << e.what();


        // 恢复按钮状态
        ui->open->setText("选择图片并识别");
        ui->open->setEnabled(true);
    }
}

六、效果

相关推荐
前端摸鱼匠18 小时前
YOLOv8 环境配置全攻略:Python、PyTorch 与 CUDA 的和谐共生
人工智能·pytorch·python·yolo·目标检测
明月醉窗台20 小时前
qt使用笔记六之 Qt Creator、Qt Widgets、Qt Quick 详细解析
开发语言·笔记·qt
2501_9413297220 小时前
改进YOLOv8-seg-act__鸡只计数检测实战
yolo
一招定胜负21 小时前
基于dlib和OpenCV的人脸替换技术详解
opencv·计算机视觉
weixin_3954489121 小时前
mult_yolov5_post_copy.c_cursor_0205
c语言·python·yolo
R_.L1 天前
【QT】常用控件(按钮类控件、显示类控件、输入类控件、多元素控件、容器类控件、布局管理器)
开发语言·qt
无小道1 天前
Qt——常用控件
开发语言·qt
初次见面我叫泰隆1 天前
Qt——5、Qt系统相关
开发语言·qt·客户端开发
王锋(oxwangfeng)1 天前
YOLOWorld 实现开集障碍物检测
yolo
喵叔哟1 天前
02-YOLO-v8-v9-v10工程差异对比
人工智能·yolo·机器学习