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

六、效果

相关推荐
melonbo2 天前
Jetson Nano 平台YOLO目标检测优化详细设计方案
yolo·目标检测·目标跟踪
fzb5QsS1p2 天前
告别重复造轮子,Qt 快速开发脚手架
开发语言·qt·php
森G2 天前
58、最佳实践与注意事项---------多线程、竟态条件和同步
c++·qt
Linux猿2 天前
植物病害图像数据集 YOLO 目标检测 | 可下载
人工智能·yolo·目标检测·yolo数据集·yolo目标检测·yolo目标检测数据集·植物病害图像数据集
小樱花的樱花2 天前
1 项目概述
开发语言·c++·qt·ui
Daydream.V2 天前
基于Opencv和Dlib的人脸换脸实现
人工智能·opencv·计算机视觉·仿射变换·换脸·视频换脸·图片换脸
MinterFusion2 天前
如何在openKylin 2.0 SP2中安装Qt(v0.2.2)(上)
开发语言·qt·软件开发·系统维护·明德融创·openkylin
特立独行的猫a2 天前
HarmonyOS鸿蒙PC的QT应用开发:(一、开发环境搭建及第一个HelloWorld)
qt·华为·harmonyos·鸿蒙pc
青花瓷2 天前
采用QT下MingW编译opencv4.8.1
开发语言·qt
Westward-sun.2 天前
背景建模详解与OpenCV实现:从原理到代码实战
人工智能·opencv·计算机视觉