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

六、效果

相关推荐
极智视界1 天前
目标检测数据集 - 空中固定翼无人机检测数据集下载
yolo·目标检测·数据集·无人机·voc·coco·算法训练
从此不归路1 天前
Qt5 进阶【11】图形视图框架:用 QGraphicsView 搭一个流程图编辑器
开发语言·c++·qt
凯子坚持 c1 天前
Qt常用控件指南(7)
服务器·数据库·qt
qwy7152292581631 天前
9-数字水印的嵌入和提取
人工智能·opencv·计算机视觉
ASD123asfadxv1 天前
YOLOv10n-RepVit实现螺钉螺母智能检测与计数系统
yolo
wkd_0071 天前
【Qt | QTableWidget】QTableWidget 类的详细解析与代码实践
开发语言·qt·qtablewidget·qt5.12.12·qt表格
残梦53141 天前
Qt6.9.1起一个图片服务器(支持前端跨域请求,不支持上传,可扩展)
运维·服务器·开发语言·c++·qt
你再说一遍?3641 天前
计算机视觉实训作业记录:基于 YOLOv12 的水下目标检测模型优化与实现
yolo·目标检测·计算机视觉
mengzhi啊1 天前
QT的语言家使用方法示范
qt
Henry Zhu1231 天前
Qt网络编程详解(下):项目实战
网络·qt