前言

本篇文章将带大家来学习使用opencv在QT中显示图片和视频等基础功能。

一、使用opencv显示图片

cv::Mat 类
cv::Mat 是 OpenCV 中用来表示图像的基本数据结构。它是一个矩阵类,可以存储图像数据、以及图像的相关信息。

主要特点
矩阵结构:cv::Mat 是一个通用的矩阵类,可以用于存储图像、特征点、深度图等数据。

数据存储:图像数据通常以矩阵的形式存储,每个像素的值可以是单通道(灰度图像)或多通道(彩色图像)。

内存管理:cv::Mat 提供了自动内存管理功能,当不再需要时会自动释放内存。

访问数据:可以通过指针、索引或迭代器来访问矩阵中的数据。

构造函数和成员函数
构造函数:cv::Mat 可以通过多种构造函数创建,如指定尺寸和数据类型的空矩阵、从图像文件加载等。

数据访问:
at<>():访问矩阵中特定位置的像素值。

data:获取矩阵数据的指针。

cv::imread 函数
cv::imread 是 OpenCV 中用来从文件读取图像并将其加载到 cv::Mat 对象中的函数。

主要参数
filename:要读取的图像文件的路径。

flags:读取图像的标志,决定图像的读取模式。

cv::IMREAD_COLOR(默认):以彩色图像的形式读取,忽略图像的透明度。
cv::IMREAD_GRAYSCALE:以灰度图像的形式读取。
cv::IMREAD_UNCHANGED:读取图像时包括图像的 alpha 通道(透明度)。

widget.cpp:

#include "widget.h"
#include "ui_widget.h"
#include <QImage>
#include <QPixmap>
#include <opencv2/opencv.hpp>

// 将 OpenCV 的 Mat 转换为 Qt 的 QImage
QImage matToQImage(const cv::Mat& mat)
{
    switch (mat.type())
    {
    case CV_8UC1:
        return QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8);
    case CV_8UC3:
        return QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888).rgbSwapped();
    default:
        qWarning("Unsupported image format");
        return QImage();
    }
}

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    // 创建 QLabel 和 QPushButton 实例
    button1 = new QPushButton("Button", this); // 创建并设置按钮的文本
    label.setFixedSize(640, 480); // 设置 label 的固定大小

    // 创建水平布局并将控件添加到布局中
    Hlayout = new QHBoxLayout(this);
    Hlayout->addWidget(&label); // 将 QLabel 添加到布局中
    Hlayout->addWidget(button1); // 将 QPushButton 添加到布局中

    setLayout(Hlayout); // 将布局设置为 Widget 的布局

    cv::Mat image = cv::imread("H:/QT opencv/code/myopencv/icon/1.jpg"); // 读取图像

    // 将 OpenCV 的 Mat 转换为 Qt 的 QImage
    QImage qImage = matToQImage(image);

    // 显示图像
    label.setPixmap(QPixmap::fromImage(qImage));
}

Widget::~Widget()
{
    delete ui;
}

widget.h:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QLabel>
#include <QHBoxLayout>
#include <QPushButton>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

    QLabel label;
    QHBoxLayout* Hlayout;
    QPushButton* button1;

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

private:
    Ui::Widget *ui;
};
#endif // WIDGET_H

代码思路总结
组件创建:在构造函数中,创建了 QPushButton 和 QLabel 实例,并设置了图像显示和按钮的文本。

布局管理:使用 QHBoxLayout 布局管理器将 QLabel 和 QPushButton 添加到布局中,确保它们在窗口中水平排列。

图像处理:读取图像文件,使用 matToQImage 函数将 OpenCV 的 Mat 对象转换为 Qt 的 QImage 对象,并设置为 QLabel 的显示内容。

显示效果:

QT opencv(显示图片和视频)-LMLPHP

二、QT opencv播放视频

VideoCapture 是 OpenCV 库中用于视频捕获和读取的类。它能够从视频文件、摄像头或其他视频流中捕获帧,并将其作为图像进行处理和显示。以下是关于 VideoCapture 的详细讲解。

VideoCapture 的基本用法

1. 创建 VideoCapture 对象
  • 从摄像头捕获:

    cv::VideoCapture cap(0); // 打开默认摄像头
    
    • 参数 0 表示打开默认摄像头。如果有多个摄像头,可以使用 12 等来指定。
  • 从视频文件读取:

    cv::VideoCapture cap("video.mp4"); // 打开视频文件
    
    • 参数是视频文件的路径。
2. 检查是否成功打开
  • 成功打开摄像头或视频文件后,应该检查是否成功打开:
    if (!cap.isOpened()) {
        std::cerr << "Error: Could not open video file or camera" << std::endl;
        return -1;
    }
    
    • cap.isOpened() 返回 true 表示成功打开,返回 false 表示打开失败。
3. 读取视频帧
  • 逐帧读取:
    cv::Mat frame;
    while (cap.read(frame)) {
        // 在这里处理帧,例如显示它
        cv::imshow("Frame", frame);
    
        // 等待 30 毫秒并检查是否按下了退出键
        if (cv::waitKey(30) >= 0) {
            break;
        }
    }
    
    • cap.read(frame) 读取一帧并存储到 frame 中。读取成功返回 true,否则返回 false
    • cv::imshow("Frame", frame) 显示当前帧。
    • cv::waitKey(30) 等待 30 毫秒,并检测是否按下键盘。如果按下键(例如 Esc),可以退出循环。
4. 释放资源
  • 当捕获或读取操作完成后,应释放资源:
    cap.release();
    cv::destroyAllWindows();
    

VideoCapture 的常用方法

  • bool open(int device): 打开摄像头设备,参数为设备索引。
  • bool open(const std::string &filename): 打开视频文件,参数为文件路径。
  • bool isOpened(): 检查视频源是否成功打开。
  • bool read(cv::Mat &image): 读取当前帧并存储在 image 中。
  • void release(): 释放视频捕获设备或文件。
  • double get(int propId): 获取视频属性,例如帧宽、高、帧率等。
    • 例如,cap.get(cv::CAP_PROP_FRAME_WIDTH) 返回帧的宽度。
  • bool set(int propId, double value): 设置视频属性,例如帧宽、高、帧率等。

常见用途

  1. 摄像头实时捕获:通过 VideoCapture 可以捕获摄像头实时视频流,并进行处理、显示或保存。

  2. 视频文件读取和处理:可以读取本地或远程的视频文件,逐帧处理,如视频剪辑、帧插值、目标跟踪等。

  3. 视频属性获取和设置:可以获取和设置视频流的属性,如帧率、分辨率、亮度、对比度等。

VideoCapture 打开失败的原因

  1. 视频文件路径错误:检查视频文件路径是否正确,文件是否存在。
  2. 文件格式不支持:确保 OpenCV 支持所使用的视频文件格式。
  3. 缺少解码器:在某些系统上,缺少必要的视频解码器,尤其是对于某些编码格式如 H.264。
  4. 摄像头被占用:检查摄像头是否被其他程序占用,或者硬件是否有问题。

widget.cpp:

#include "widget.h"
#include "ui_widget.h"
#include <QImage>
#include <QPixmap>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    , videoLabel(new QLabel(this))
    , timer(new QTimer(this))
{
    ui->setupUi(this);

    // 设置 videoLabel 的尺寸
    videoLabel->setFixedSize(1000, 1000);

    // 创建定时器并连接到槽函数
    connect(timer, &QTimer::timeout, this, &Widget::updateFrame);

    // 打开视频文件
    cap.open("H:/QT opencv/code/Test/1.mp4");

    if (!cap.isOpened()) {
        qWarning("Error: Could not open video file.");
        return;
    }

    // 启动定时器,每30毫秒更新一次视频帧
    timer->start(30);
}

Widget::~Widget()
{
    cap.release();
    delete ui;
}

QImage Widget::matToQImage(const cv::Mat& mat)
{
    switch (mat.type())
    {
    case CV_8UC1:
        return QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8);
    case CV_8UC3:
        return QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888).rgbSwapped();
    default:
        qWarning("Unsupported image format");
        return QImage();
    }
}

void Widget::updateFrame()
{
    cv::Mat frame;
    if (cap.read(frame)) {
        // 将 OpenCV 的 Mat 转换为 Qt 的 QImage
        QImage qImage = matToQImage(frame);

        // 更新 videoLabel 显示
        videoLabel->setPixmap(QPixmap::fromImage(qImage));
    }
}

widget.h:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QLabel>
#include <QTimer>
#include <opencv2/opencv.hpp>

QT_BEGIN_NAMESPACE
namespace Ui {
class Widget;
}
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void updateFrame(); // 更新视频帧的槽函数

private:
    Ui::Widget *ui;
    QLabel *videoLabel; // 显示视频的标签
    QTimer *timer; // 定时器用于刷新视频帧
    cv::VideoCapture cap; // OpenCV 视频捕获对象

    QImage matToQImage(const cv::Mat& mat); // 将 cv::Mat 转换为 QImage
};

#endif // WIDGET_H

运行效果:

QT opencv(显示图片和视频)-LMLPHP

三、QT opencv打开摄像头

widget.cpp:

#include "widget.h"
#include "ui_widget.h"
#include <QImage>
#include <QPixmap>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
    , cap(1) // 打开摄像头
{
    ui->setupUi(this);

    cameraLabel = new QLabel(this); // 用于显示摄像头画面的 QLabel
    cameraLabel->setFixedSize(640, 480); // 设置显示区域的大小

    if (!cap.isOpened()) {
        qWarning("Error: Could not open camera");
        return;
    }

    timer = new QTimer(this);
    connect(timer, &QTimer::timeout, this, &Widget::updateFrame);
    timer->start(30); // 每 30 毫秒更新一次画面
}

Widget::~Widget()
{
    cap.release(); // 释放摄像头
    delete ui;
}

void Widget::updateFrame()
{
    cv::Mat frame;
    cap >> frame; // 读取摄像头当前帧
    if (frame.empty()) {
        return;
    }

    QImage qImage = matToQImage(frame); // 将 OpenCV 的 Mat 转换为 QImage
    cameraLabel->setPixmap(QPixmap::fromImage(qImage)); // 显示图像
}

QImage Widget::matToQImage(const cv::Mat &mat)
{
    switch (mat.type()) {
    case CV_8UC1:
        return QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Grayscale8);
    case CV_8UC3:
        return QImage(mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888).rgbSwapped();
    default:
        qWarning("Unsupported image format");
        return QImage();
    }
}

widget.h:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QLabel>
#include <QTimer>
#include <opencv2/opencv.hpp>

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void updateFrame();

private:
    Ui::Widget *ui;
    QLabel *cameraLabel;
    QTimer *timer;
    cv::VideoCapture cap;

    QImage matToQImage(const cv::Mat& mat);
};

#endif // WIDGET_H

运行效果:
QT opencv(显示图片和视频)-LMLPHP

08-25 10:31