欢迎光临
我们一直在努力

Qt快速入门:OpenCV + Qt QML 视频播放器项目

一、项目整体设计

1.1 我们要做什么?

创建一个视频播放器:

  • 界面:用 QML 做(好看)
  • 视频处理:用 OpenCV 做(强大)
  • 连接桥梁:用 C++ 做(高效)

1.2 技术选型

技术作用优点
Qt QML 用户界面 界面漂亮,开发快
OpenCV 视频处理 功能强大,跨平台
C++ 核心逻辑 性能好,连接 QML 和 OpenCV
CMake 项目构建 跨平台,管理依赖

二、项目环境搭建

2.1 安装必要的软件

  • Qt(版本 6.x):下载安装
  • OpenCV:下载预编译版本
  • CMake:Qt 自带,无需单独安装
  • 编译器:
    • Windows:MinGW 或 Visual Studio
    • macOS:Xcode Command Line Tools
    • Linux:GCC
  • 2.2 目录结构准备

    video_player/
    ├── src/ # 源代码
    │ ├── main.cpp # 程序入口
    │ ├── main.qml # QML界面
    │ ├── XVideo.cpp # 视频组件
    │ ├── XVideo.h # 视频组件头文件
    │ └── CMakeLists.txt # 项目配置
    ├── lib/ # 第三方库
    │ └── opencv/
    │ ├── mingw/ # MinGW版本
    │ └── msvc/ # VS版本
    └── bin/ # 输出目录


    三、第一步:创建基础项目

    3.1 创建 CMakeLists.txt

    # CMakeLists.txt
    # 1. 告诉CMake我们需要的最低版本
    cmake_minimum_required(VERSION 3.20)

    # 2. 给项目起名字
    project(video_player)

    # 3. 查找并加载 Qt
    find_package(Qt6 COMPONENTS Quick REQUIRED)

    # 4. 自动处理Qt的特殊功能
    set(CMAKE_AUTOMOC ON) # 自动处理信号槽
    set(CMAKE_AUTORCC ON) # 自动处理资源文件

    # 5. 创建可执行文件
    add_executable(${PROJECT_NAME} main.cpp)

    # 6. 链接Qt库
    target_link_libraries(${PROJECT_NAME} PRIVATE Qt6::Quick)

    3.2 创建 main.cpp

    // main.cpp – 程序入口
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>

    int main(int argc, char *argv[])
    {
    // 1. 创建Qt应用程序
    QGuiApplication app(argc, argv);

    // 2. 创建QML引擎
    QQmlApplicationEngine engine;

    // 3. 加载QML文件
    engine.load(QUrl("qrc:/main.qml"));

    // 4. 检查是否加载成功
    if (engine.rootObjects().isEmpty())
    return 1; // 失败

    // 5. 运行程序
    return app.exec();
    }

    3.3 创建 main.qml

    // main.qml – 界面文件
    import QtQuick

    // 创建一个窗口
    Window {
    // 窗口大小
    width: 800
    height: 600

    // 窗口标题
    title: "视频播放器"

    // 让窗口可见(重要!)
    visible: true

    // 在窗口中添加文字
    Text {
    text: "Hello, Video Player!"
    font.pixelSize: 30
    anchors.centerIn: parent
    }
    }

    3.4 创建资源文件(qml.qrc)

  • 在 Qt Creator 中:右键项目 → 添加新文件
  • 选择 “Qt Resource File”
  • 命名为 “qml”
  • 点击 “Add”,选择 main.qml

  • 四、第二步:添加 OpenCV 支持

    4.1 修改 CMakeLists.txt

    # CMakeLists.txt – 完整版

    # 基础配置
    cmake_minimum_required(VERSION 3.20)
    project(video_player)

    # 1. 判断当前编译器类型
    if(MINGW)
    message("使用 MinGW 编译器")
    set(TOOL "mingw") # 用于区分输出目录
    set(OPENCVPATH "${CMAKE_CURRENT_LIST_DIR}/../lib/opencv/mingw")
    elseif(MSVC)
    message("使用 MSVC 编译器")
    set(TOOL "msvc")
    set(OPENCVPATH "${CMAKE_CURRENT_LIST_DIR}/../lib/opencv/msvc")
    else()
    message(FATAL_ERROR "不支持的编译器")
    endif()

    # 2. 加载 Qt
    find_package(Qt6 COMPONENTS Quick REQUIRED)
    set(CMAKE_AUTOMOC ON)
    set(CMAKE_AUTORCC ON)

    # 3. 加载 OpenCV
    find_package(OpenCV REQUIRED PATHS ${OPENCVPATH})

    # 4. 设置输出目录
    set(RUNTIME "${CMAKE_CURRENT_LIST_DIR}/../bin/${TOOL}")
    set_target_properties(${PROJECT_NAME}
    PROPERTIES
    RUNTIME_OUTPUT_DIRECTORY "${RUNTIME}"
    RUNTIME_OUTPUT_DIRECTORY_DEBUG "${RUNTIME}"
    RUNTIME_OUTPUT_DIRECTORY_RELEASE "${RUNTIME}"
    )

    # 5. 添加源文件
    add_executable(${PROJECT_NAME}
    main.cpp
    XVideo.cpp
    qml.qrc
    )

    # 6. 链接库
    target_link_libraries(${PROJECT_NAME} PRIVATE
    Qt6::Quick
    ${OpenCV_LIBS}
    )

    # 7. 添加头文件路径
    include_directories(${OpenCV_INCLUDE_DIRS})


    五、第三步:创建视频组件 XVideo

    5.1 创建 XVideo.h

    // XVideo.h – 视频组件头文件
    #ifndef XVIDEO_H
    #define XVIDEO_H

    // 包含必要的头文件
    #include <QQuickPaintedItem> // QML绘制组件基类
    #include <QImage> // Qt图像类
    #include <QTimer> // 定时器
    #include <opencv2/opencv.hpp> // OpenCV

    // 创建视频组件类
    class XVideo : public QQuickPaintedItem
    {
    Q_OBJECT // 必须添加这个宏!
    QML_ELEMENT // 让QML能识别这个类

    // 定义属性(QML可以访问)
    Q_PROPERTY(QString source READ source WRITE setSource NOTIFY sourceChanged)
    Q_PROPERTY(bool playing READ playing WRITE setPlaying NOTIFY playingChanged)

    public:
    // 构造函数
    XVideo(QQuickItem *parent = nullptr);

    // 析构函数
    ~XVideo();

    // 重写绘制函数(必须实现)
    void paint(QPainter *painter) override;

    // 属性访问函数
    QString source() const; // 获取视频路径
    void setSource(const QString &source); // 设置视频路径

    bool playing() const; // 是否正在播放
    void setPlaying(bool playing); // 设置播放状态

    // QML可以调用的函数
    Q_INVOKABLE void play(); // 播放
    Q_INVOKABLE void pause(); // 暂停
    Q_INVOKABLE void stop(); // 停止

    signals:
    // 信号(事件)
    void sourceChanged(); // 视频路径改变
    void playingChanged(); // 播放状态改变
    void errorOccurred(const QString &message); // 错误发生
    void readEnd(); // 视频播放结束

    private slots:
    // 槽函数(响应事件)
    void updateFrame(); // 更新视频帧

    private:
    // 私有成员变量
    cv::VideoCapture m_capture; // OpenCV视频捕获对象
    cv::Mat m_frame; // 当前视频帧
    QImage m_image; // Qt图像(用于显示)
    QTimer m_timer; // 定时器(控制播放速度)
    QString m_source; // 视频文件路径
    bool m_playing = false; // 播放状态
    int m_fps = 30; // 视频帧率
    };

    #endif // XVIDEO_H

    5.2 创建 XVideo.cpp

    // XVideo.cpp – 视频组件实现
    #include "XVideo.h"
    #include <QDebug> // 调试输出
    #include <QPainter> // 绘制

    // 构造函数
    XVideo::XVideo(QQuickItem *parent)
    : QQuickPaintedItem(parent) // 调用父类构造函数
    {
    qDebug() << "XVideo 组件被创建";

    // 连接定时器和更新函数
    // 当定时器超时时,调用 updateFrame
    connect(&m_timer, &QTimer::timeout, this, &XVideo::updateFrame);
    }

    // 析构函数
    XVideo::~XVideo()
    {
    // 释放视频捕获资源
    if (m_capture.isOpened()) {
    m_capture.release();
    }
    }

    // 绘制函数 – 在界面上显示视频
    void XVideo::paint(QPainter *painter)
    {
    // 如果没有图像,就不绘制
    if (m_image.isNull()) {
    return;
    }

    // 绘制图像
    // 参数:位置和大小,图像
    QRect rect(0, 0, width(), height());
    painter->drawImage(rect, m_image);
    }

    // 获取视频路径
    QString XVideo::source() const
    {
    return m_source;
    }

    // 设置视频路径
    void XVideo::setSource(const QString &source)
    {
    // 如果新路径和旧路径一样,就不做任何事
    if (m_source == source) {
    return;
    }

    // 停止当前视频
    stop();

    // 更新路径
    m_source = source;

    // 如果路径不为空,尝试打开视频
    if (!source.isEmpty()) {
    // 使用OpenCV打开视频
    m_capture.open(source.toStdString());

    // 检查是否打开成功
    if (!m_capture.isOpened()) {
    emit errorOccurred("无法打开视频: " + source);
    return;
    }

    // 获取视频帧率
    m_fps = m_capture.get(cv::CAP_PROP_FPS);
    if (m_fps <= 0) {
    m_fps = 30; // 默认30帧
    }

    qDebug() << "打开视频成功:" << source << ",帧率:" << m_fps;

    // 发出信号,告诉QML视频路径改变了
    emit sourceChanged();
    }
    }

    // 是否正在播放
    bool XVideo::playing() const
    {
    return m_playing;
    }

    // 设置播放状态
    void XVideo::setPlaying(bool playing)
    {
    // 如果状态没变,就不做任何事
    if (m_playing == playing) {
    return;
    }

    // 更新状态
    m_playing = playing;

    // 根据状态执行操作
    if (playing) {
    play(); // 播放
    } else {
    pause(); // 暂停
    }

    // 发出信号
    emit playingChanged();
    }

    // 播放视频
    void XVideo::play()
    {
    // 检查视频是否已打开
    if (!m_capture.isOpened()) {
    emit errorOccurred("请先打开视频文件");
    return;
    }

    // 设置播放状态
    m_playing = true;

    // 启动定时器
    // 1000ms / 帧率 = 每帧间隔时间
    m_timer.start(1000 / m_fps);

    qDebug() << "开始播放视频";
    }

    // 暂停视频
    void XVideo::pause()
    {
    m_playing = false;
    m_timer.stop(); // 停止定时器
    qDebug() << "暂停播放";
    }

    // 停止视频
    void XVideo::stop()
    {
    // 先暂停
    pause();

    // 回到视频开头
    if (m_capture.isOpened()) {
    m_capture.set(cv::CAP_PROP_POS_FRAMES, 0);
    }

    // 清空图像
    m_image = QImage();

    // 通知界面重绘
    update();

    qDebug() << "停止播放";
    }

    // 更新视频帧
    void XVideo::updateFrame()
    {
    // 检查视频是否已打开
    if (!m_capture.isOpened()) {
    return;
    }

    // 读取下一帧
    if (!m_capture.read(m_frame) || m_frame.empty()) {
    // 视频播放完了,回到开头
    m_capture.set(cv::CAP_PROP_POS_FRAMES, 0);

    // 重新读取第一帧
    if (!m_capture.read(m_frame)) {
    // 读取失败,发出结束信号
    emit readEnd();
    return;
    }
    }

    // 将OpenCV的BGR格式转换为RGB格式
    // OpenCV默认是BGR,Qt需要RGB
    cv::Mat rgbFrame;
    cv::cvtColor(m_frame, rgbFrame, cv::COLOR_BGR2RGB);

    // 创建QImage
    // 参数:数据指针,宽度,高度,每行字节数,格式
    m_image = QImage(rgbFrame.data,
    rgbFrame.cols,
    rgbFrame.rows,
    rgbFrame.step,
    QImage::Format_RGB888);

    // 通知界面重绘
    update();
    }


    六、第四步:修改 main.cpp 注册组件

    // main.cpp – 完整版
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include "XVideo.h" // 包含我们的视频组件

    int main(int argc, char *argv[])
    {
    // 1. 创建Qt应用程序
    QGuiApplication app(argc, argv);

    // 2. 创建QML引擎
    QQmlApplicationEngine engine;

    // 3. 注册自定义组件到QML
    // 参数说明:
    // – "XVideo":模块名(在QML中import的名字)
    // – 1, 0:版本号(主版本.次版本)
    // – "XVideo":QML中的类型名
    qmlRegisterType<XVideo>("XVideo", 1, 0, "XVideo");

    // 4. 加载QML文件
    engine.load(QUrl("qrc:/main.qml"));

    // 5. 检查是否加载成功
    if (engine.rootObjects().isEmpty()) {
    return 1;
    }

    // 6. 运行程序
    return app.exec();
    }


    七、第五步:完善 QML 界面

    // main.qml – 完整界面
    import QtQuick
    import QtQuick.Controls // 按钮等控件
    import XVideo 1.0 // 导入我们的视频组件

    // 主窗口
    Window {
    id: window
    width: 1280
    height: 720
    visible: true
    title: "视频播放器 – OpenCV + QML"

    // 背景颜色
    color: "#333333"

    // 视频播放组件
    XVideo {
    id: videoPlayer
    anchors.fill: parent // 填满整个窗口

    // 当发生错误时
    onErrorOccurred: function(message) {
    errorDialog.text = message
    errorDialog.open()
    }

    // 当视频播放结束时
    onReadEnd: {
    console.log("视频播放结束")
    videoPlayer.playing = false
    }
    }

    // 控制面板
    Rectangle {
    id: controlPanel
    width: parent.width
    height: 100
    color: "#80000000" // 半透明黑色
    anchors.bottom: parent.bottom

    Row {
    spacing: 20
    anchors.centerIn: parent

    // 播放/暂停按钮
    Button {
    text: videoPlayer.playing ? "⏸ 暂停" : "▶ 播放"
    onClicked: {
    videoPlayer.playing = !videoPlayer.playing
    }
    background: Rectangle {
    color: "#4CAF50"
    radius: 5
    }
    font.pixelSize: 16
    implicitWidth: 100
    implicitHeight: 40
    }

    // 停止按钮
    Button {
    text: "⏹ 停止"
    onClicked: videoPlayer.stop()
    background: Rectangle {
    color: "#F44336"
    radius: 5
    }
    font.pixelSize: 16
    implicitWidth: 100
    implicitHeight: 40
    }

    // 打开文件按钮
    Button {
    text: "📁 打开视频"
    onClicked: fileDialog.open()
    background: Rectangle {
    color: "#2196F3"
    radius: 5
    }
    font.pixelSize: 16
    implicitWidth: 120
    implicitHeight: 40
    }

    // 当前状态显示
    Text {
    text: videoPlayer.playing ? "正在播放…" : "已暂停"
    color: "white"
    font.pixelSize: 16
    anchors.verticalCenter: parent.verticalCenter
    }
    }
    }

    // 文件选择对话框
    FileDialog {
    id: fileDialog
    title: "选择视频文件"
    nameFilters: [
    "视频文件 (*.mp4 *.avi *.mov *.mkv)",
    "所有文件 (*.*)"
    ]

    onAccepted: {
    // 设置视频路径并播放
    videoPlayer.source = selectedFile
    videoPlayer.play()
    }
    }

    // 错误提示对话框
    Dialog {
    id: errorDialog
    title: "错误"
    modal: true
    standardButtons: Dialog.Ok

    property alias text: errorText.text

    Text {
    id: errorText
    wrapMode: Text.WordWrap
    }
    }
    }


    八、第六步:编译和运行

    8.1 使用 Qt Creator

  • 打开项目:File → Open File or Project → 选择 CMakeLists.txt
  • 选择构建套件:MinGW 或 MSVC
  • 配置项目:点击 “Configure Project”
  • 构建项目:点击左下角的锤子图标
  • 运行项目:点击左下角的绿色三角图标
  • 8.2 使用命令行

    # 进入项目目录
    cd video_player/src

    # 创建构建目录
    mkdir build
    cd build

    # 配置项目(MinGW)
    cmake .. -G "MinGW Makefiles"

    # 或配置项目(MSVC)
    cmake .. -G "Visual Studio 17 2022"

    # 编译项目
    cmake –build .

    # 运行程序
    cd ../../bin/mingw # 或 msvc
    ./video_player


    九、第七步:项目发布

    9.1 为什么要发布?

    • 用户没有 Qt 和 OpenCV 环境
    • 需要把程序发给别人使用
    • 制作安装包

    9.2 Windows 发布步骤

    方法一:手动复制
  • 复制可执行文件:bin/mingw/video_player.exe
  • 复制 Qt 库文件:从 Qt 安装目录复制必要的 DLL
  • 复制 OpenCV 库文件:lib/opencv/mingw/bin/*.dll
  • 创建运行目录:把所有文件放在同一个文件夹
  • 方法二:使用 windeployqt(推荐)

    创建批处理文件 deploy.bat:

    @echo off
    echo 开始发布程序…

    REM 设置路径
    set QT_PATH=F:\\Qt\\6.6.2\\mingw_64
    set OPENCV_PATH=..\\lib\\opencv\\mingw\\bin
    set OUTPUT=..\\dist

    REM 创建输出目录
    if not exist %OUTPUT% mkdir %OUTPUT%

    REM 复制可执行文件
    copy .\\bin\\mingw\\video_player.exe %OUTPUT%

    REM 复制 OpenCV DLL
    copy %OPENCV_PATH%\\*.dll %OUTPUT%

    REM 使用 windeployqt 复制 Qt 依赖
    %QT_PATH%\\bin\\windeployqt.exe %OUTPUT%\\video_player.exe –qmldir .

    echo 发布完成!
    pause

    9.3 macOS 发布

    # 使用 macdeployqt
    macdeployqt video_player.app -qmldir=.

    9.4 Linux 发布

    # 使用 linuxdeployqt
    linuxdeployqt video_player -qmldir=.


    十、常见问题解决

    问题1:找不到 OpenCV

    错误信息:Could NOT find OpenCV 解决方法:

    # 1. 检查路径是否正确
    message("OpenCV路径: ${OPENCVPATH}")

    # 2. 确保 OpenCVConfig.cmake 文件存在
    # 3. 清理 build 目录重新编译

    问题2:QML 导入失败

    错误信息:module "XVideo" is not installed 解决方法:

  • 检查 qmlRegisterType 是否调用
  • 确保 XVideo 类有 Q_OBJECT 宏
  • 清理项目重新编译
  • 问题3:视频无法播放

    可能原因:

  • 视频文件路径错误
  • OpenCV 不支持该格式
  • 缺少视频解码器 解决方法:
  • // 在 QML 中添加错误处理
    onErrorOccurred: function(message) {
    console.error("错误:", message)
    }

    问题4:画面卡顿

    优化方法:

  • 降低分辨率
  • 减少帧率
  • 使用硬件加速

  • 十一、扩展功能

    11.1 添加进度条

    // 在控制面板中添加
    Slider {
    width: 400
    value: 0
    onValueChanged: {
    // 跳转到指定位置
    }
    }

    11.2 添加音量控制

    Slider {
    width: 100
    value: 0.5
    onValueChanged: {
    // 设置音量
    }
    }

    11.3 添加全屏功能

    Button {
    text: "全屏"
    onClicked: {
    if (window.visibility === Window.FullScreen) {
    window.showNormal()
    } else {
    window.showFullScreen()
    }
    }
    }

    11.4 添加视频滤镜

    // 在 XVideo.cpp 中添加
    void XVideo::applyFilter(const QString &filterType)
    {
    if (filterType == "灰度") {
    cv::cvtColor(m_frame, m_frame, cv::COLOR_BGR2GRAY);
    } else if (filterType == "模糊") {
    cv::GaussianBlur(m_frame, m_frame, cv::Size(5, 5), 0);
    }
    }


    十二、总结

    12.1 学到的知识

  • Qt QML:创建现代化界面
  • OpenCV:处理视频和图像
  • C++扩展QML:连接界面和逻辑
  • CMake:管理复杂项目
  • 跨平台开发:Windows、macOS、Linux
  • 12.2 项目亮点

    • ✅ 界面美观,响应迅速
    • ✅ 代码结构清晰,易于维护
    • ✅ 跨平台支持
    • ✅ 易于扩展新功能

    12.3 下一步学习建议

  • 深入学习 OpenCV:图像处理、人脸识别
  • 学习 Qt 高级功能:动画、3D、网络
  • 优化性能:多线程、GPU加速
  • 添加新功能:字幕、截图、录制
  • 12.4 调试技巧

  • 多用 qDebug():在关键位置添加调试输出
  • 分模块测试:先测试 OpenCV,再测试 QML
  • 查看错误信息:仔细阅读控制台输出
  • 简化问题:先去掉复杂功能,逐步添加

  • 附录:完整文件列表

    必须的文件:

  • src/CMakeLists.txt – 项目配置文件
  • src/main.cpp – 程序入口
  • src/main.qml – QML界面文件
  • src/XVideo.h – 视频组件头文件
  • src/XVideo.cpp – 视频组件实现
  • src/qml.qrc – Qt资源文件
  • 第三方库:

  • lib/opencv/mingw/ – MinGW版OpenCV
  • lib/opencv/msvc/ – MSVC版OpenCV
  • 生成的文件:

  • bin/mingw/video_player.exe – MinGW可执行文件
  • bin/msvc/video_player.exe – MSVC可执行文件
  • 赞(0)
    未经允许不得转载:171主机测评 » Qt快速入门:OpenCV + Qt QML 视频播放器项目
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址