文章目录
前言
本篇文章将带大家来学习使用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播放视频
VideoCapture
是 OpenCV 库中用于视频捕获和读取的类。它能够从视频文件、摄像头或其他视频流中捕获帧,并将其作为图像进行处理和显示。以下是关于 VideoCapture
的详细讲解。
VideoCapture
的基本用法
1. 创建 VideoCapture
对象
-
从摄像头捕获:
cv::VideoCapture cap(0); // 打开默认摄像头
- 参数
0
表示打开默认摄像头。如果有多个摄像头,可以使用1
、2
等来指定。
- 参数
-
从视频文件读取:
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)
: 设置视频属性,例如帧宽、高、帧率等。
常见用途
-
摄像头实时捕获:通过
VideoCapture
可以捕获摄像头实时视频流,并进行处理、显示或保存。 -
视频文件读取和处理:可以读取本地或远程的视频文件,逐帧处理,如视频剪辑、帧插值、目标跟踪等。
-
视频属性获取和设置:可以获取和设置视频流的属性,如帧率、分辨率、亮度、对比度等。
VideoCapture
打开失败的原因
- 视频文件路径错误:检查视频文件路径是否正确,文件是否存在。
- 文件格式不支持:确保 OpenCV 支持所使用的视频文件格式。
- 缺少解码器:在某些系统上,缺少必要的视频解码器,尤其是对于某些编码格式如 H.264。
- 摄像头被占用:检查摄像头是否被其他程序占用,或者硬件是否有问题。
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打开摄像头
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
运行效果: