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);
    }
}

六、效果

相关推荐
向哆哆3 天前
高精度织物缺陷检测数据集(适用YOLO系列/1000+标注)(已标注+划分/可直接训练)
yolo·目标检测
范特西.i3 天前
QT聊天项目(8)
开发语言·qt
前网易架构师-高司机3 天前
带标注的驾驶员安全带识别数据集,识别率99.5%,可识别有无系安全带,支持yolo,coco json,pascal voc xml格式
xml·yolo·数据集·交通·安全带
枫叶丹43 天前
【Qt开发】Qt界面优化(七)-> Qt样式表(QSS) 样式属性
c语言·开发语言·c++·qt
sali-tec3 天前
C# 基于OpenCv的视觉工作流-章27-图像分割
图像处理·人工智能·opencv·算法·计算机视觉
saoys3 天前
Opencv 学习笔记:腐蚀操作 + 轮廓标记 + 分水岭分割
笔记·opencv·学习
saoys3 天前
Opencv 学习笔记:距离变换(DIST_L1 算法实战 + 归一化)
笔记·opencv·学习
十五年专注C++开发3 天前
Qt deleteLater作用及源码分析
开发语言·c++·qt·qobject
kangzerun3 天前
SQLiteManager:一个优雅的Qt SQLite数据库操作类
数据库·qt·sqlite
金刚狼883 天前
qt和qt creator的下载安装
开发语言·qt