【Qt】用QWidget显示opencv采集的摄像头图像

这篇具有很好参考价值的文章主要介绍了【Qt】用QWidget显示opencv采集的摄像头图像。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

写在前面

本案例用QWidget容器重写paintEvent函数来显示OpenCv采集的摄像头画面,图像还可以自适应QWidget的大小,还可以检测相机断开失联的情况(可能是掉电、线被拔了等待)。在改变窗口大小时暂停显示图像,防止莫名其妙的卡顿奔溃错误!(显示图像的方式有很多种,可以用QLabel显示图像,虽然简单但是对于这种视频画面不建议用QLabel;还可以用QGraphicsView显示,下一篇文章更新)

qt+opencv采集摄像头,Qt,OpenCV,qt

一、新建工程

1、新建一个Qt工程,在UI中添加一个Widget容器和两个按钮,并添加合适的布局。把Widget的ObjectName设置为CameraWidget,两个按钮分别是“打开相机openCamera”、“关闭相机closeCamera
qt+opencv采集摄像头,Qt,OpenCV,qt
2、新建一个任务类,用于Opencv采集摄像头图像并发送信号。用moveToThread将该任务类添加到子线程中。
3、在Qt中新建一个类CameraWidget继承QWidget,并将UI中的Widget控件提升为该类。

二、采集图像

1、在Qt项目中配置OpenCv环境(本文默认您已经配置完成,否则看我另一篇文章:QT配置opencv346环境(MinGw编译器)。
2、新建一个任务类,该类主要的任务是:采集图像、发送信号,关闭相机退出线程。
3、代码如下

Camera.h

#ifndef CAMERA_H
#define CAMERA_H

#include <QObject>
#include <QTimer>
#include <QPixmap>

#include <opencv2/opencv.hpp>
using namespace cv;

class Camera : public QObject
{
    Q_OBJECT
public:
    explicit Camera(QObject *parent = nullptr);

    void openCamera();      // 打开相机
    void closeCamera();     // 关闭相机

private:
    VideoCapture *cap;     // 相机
    QTimer *capTimer;       // 采集图像定时器
    bool cameraIsOpened = false;        // 相机打开标志位

signals:
    void cameraShowImage(QPixmap);      // 发送图像信号
    void cameraIsOpen(bool);            // 相机打开信号
};

#endif // CAMERA_H

Camera.cpp

#pragma execution_character_set("utf-8")
#include "camera.h"
#include <QDebug>
#include <QThread>

Camera::Camera(QObject *parent) : QObject(parent)
{

}

void Camera::openCamera()
{
    qDebug() << "子线程:" << QThread::currentThreadId();
    // 打开相机
    int cameraDevId = 0;
    this->cap = new VideoCapture;
    this->cap->open(cameraDevId, cv::CAP_DSHOW);     // 必须带上 CAP_DSHOW ,否则会报错 [ WARN:1] terminating async callback,然后再次打开就打不开了
    if(!this->cap->isOpened()){
        this->cap->release();		// 释放相机
        qDebug() << "相机打开失败!";
        return;
    }
    this->cameraIsOpened = true;
    emit this->cameraIsOpen(true);     // 相机打开

    qDebug() << QString("相机参数: (%1, %2), %3 FPS").arg(cap->get(3)).arg(cap->get(4)).arg(cap->get(5));

    this->capTimer = new QTimer;
    connect(this->capTimer, &QTimer::timeout, [=]() {
//        qDebug() << "子线程:" << QThread::currentThreadId();
        Mat frame;
        // 采集图像
        this->cap->read(frame);
        if(frame.empty()){
            qDebug() << "相机可能断开";
            this->closeCamera();        // 关闭相机
            return ;
        }
        // 将OpenCv的BGR图像转换成正常的RGB图像
        cvtColor(frame, frame, cv::COLOR_BGR2RGB);
        // 将OpenCv的图像转换成Qt的QImage
        QPixmap showImage = QPixmap::fromImage(QImage((const uchar*)(frame.data),
                                                      frame.cols,
                                                      frame.rows,
                                                      frame.step,
                                                      QImage::Format_RGB888));
        // 将QPixmap图像通过信号发送出去
        emit this->cameraShowImage(showImage);
    });
    // 采样时间可以根据相机的FPS修改
    this->capTimer->start(40);
}

void Camera::closeCamera()
{
    qDebug() << "子线程:" << QThread::currentThreadId();
    if(!this->cameraIsOpened) return;

    if(this->capTimer->isActive()){
        this->capTimer->stop();
        this->capTimer->deleteLater();

        this->cameraIsOpened = false;
        emit this->cameraIsOpen(false);     // 相机关闭

        this->cap->release();		// 释放相机
        cv::destroyAllWindows();	// 销毁OpenCv的窗口
    }
}

三、显示图像

1、新建一个类继承QWidget,并将UI中的Widget控件提升为该类。
qt+opencv采集摄像头,Qt,OpenCV,qt

2、重写paintEvent函数,根据widget的大小对图像进行缩放并绘制;设计一个变量showCameraImage,如果为true时才显示绘制图像。
3、新建一个定时器,重写resizeEvent函数;在窗口大小变化将showCameraImage设置为false,然后不断刷定时器。当窗口大小不再变化,定时器不刷新,时间到了之后将showCameraImage设置为true重新绘制图像。
4、创建几个成员函数用来更新图像。
5、代码如下:

CameraWidget.h

#ifndef CAMERAWIDGET_H
#define CAMERAWIDGET_H

#include <QWidget>
#include <QTimer>
#include <QPixmap>

class CameraWidget : public QWidget
{
    Q_OBJECT
public:
    explicit CameraWidget(QWidget *parent = nullptr);

    void showImage(bool b);      // 显示图像
    void setImage(QPixmap img);     // 更新图像

protected:
    void resizeEvent(QResizeEvent *event) override;
    void paintEvent(QPaintEvent *event) override;

private:
    QPixmap cvImage;                // 相机图像
    QTimer *noShowCameraImage;      // 不显示图像定时器
    bool showCameraImage = true;    // 显示图像
    
    bool camerIsOpened = false;     // 相机打开

signals:

};

#endif // CAMERAWIDGET_H

CameraWidget.cpp

#pragma execution_character_set("utf-8")
#include "camerawidget.h"
#include <QDebug>
#include <QPainter>

#define CAMERA_IMAGE_WIDTH 640
#define CAMERA_IMAGE_HEIGHT 480

CameraWidget::CameraWidget(QWidget *parent) : QWidget(parent)
{
    this->noShowCameraImage = new QTimer;
    connect(this->noShowCameraImage, &QTimer::timeout, this, [=](){
        this->showCameraImage = true;
        this->noShowCameraImage->stop();
        this->update();
    }); 

    this->update();
}

void CameraWidget::showImage(bool b)
{
    this->camerIsOpened = b;
    update();
}

void CameraWidget::setImage(QPixmap img)
{
    this->cvImage = img;
    update();
}

/**********************************************************
 * @brief label大小变化事件
**********************************************************/
void CameraWidget::resizeEvent(QResizeEvent *event)
{
    this->showCameraImage = false;
    // 定时器刷新时间,当窗口大小不变后多长时间恢复图像
    // 这涉及到用户体验,设置适当的值即可
    this->noShowCameraImage->setInterval(200);
    this->noShowCameraImage->start();

    QWidget::resizeEvent(event);
}

void CameraWidget::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);

    // 背景颜色
    painter.setPen(QColor(192, 192, 192));
    painter.setBrush(QColor(192, 192, 192));
    painter.drawRect(0, 0, this->width(), this->height());

    // 等比缩放,绘制图像
    if(this->showCameraImage && this->camerIsOpened){
        // 寻找图像大小和widget大小的缩放关系
        QRectF imgRect = this->cvImage.rect();
        QRectF widgetRect = this->rect();
        double factor = qMin(widgetRect.width() / imgRect.width(), widgetRect.height() / imgRect.height());
        // 计算新的Rect
        int imgWidth = imgRect.width() * factor;
        int imgHeight = imgRect.height() * factor;
        int startX = (this->width() - imgWidth) / 2;
        int startY = (this->height() - imgHeight) / 2;
        // 显示图像
        painter.drawPixmap(startX, startY, imgWidth, imgHeight, this->cvImage);
    }

    QWidget::paintEvent(event);
}

四、主窗口

在主线程里面主要是创建子线程已经信号槽绑定。文章来源地址https://www.toymoban.com/news/detail-538244.html

#pragma execution_character_set("utf-8")
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QDebug>

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

    qDebug() << "主线程:" << QThread::currentThreadId();

    // 相机子线程
    this->camera = new Camera;
    this->cameraThread = new QThread;
    this->camera->moveToThread(this->cameraThread);
    connect(this->cameraThread, &QThread::finished, this->cameraThread, &QThread::deleteLater);
    connect(this->cameraThread, &QThread::finished, this->camera, &Camera::deleteLater);
    connect(this->camera, &Camera::cameraShowImage, ui->cameraWidget, &CameraWidget::setImage);		// 更新图像
    this->cameraThread->start();

    connect(ui->openCamera, &QPushButton::clicked, this->camera, &Camera::openCamera);      // 打开相机
    connect(ui->closeCamera, &QPushButton::clicked, this->camera, &Camera::closeCamera);    // 关闭相机

    connect(this->camera, &Camera::cameraIsOpen, ui->cameraWidget, &CameraWidget::showImage);
}

MainWindow::~MainWindow()
{
    if(this->cameraThread->isRunning()){
        this->cameraThread->quit();
        this->cameraThread->wait();
    }
    delete ui;
}

到了这里,关于【Qt】用QWidget显示opencv采集的摄像头图像的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Pyqt5+Opencv实现摄像头图像的实时读取并显示

    QTimer在界面中不可见,在UI设计器中也找不到它,只能通过纯代码实现,主要作用是定时特定的时间。 想要掌握QTimer只需掌握setInterval(设置定时时间,单位ms)、start(启动定时器),和定时时间到时所发出的信号timeout()即可。程序设计的思路: 1.先设定定时周期 2.绑定timeout()信号

    2024年02月04日
    浏览(58)
  • VC++中使用OpenCV读取图像、读取本地视频、读取摄像头并实时显示

    最近闲着跟着油管博主murtazahassan,学习了一下LEARN OPENCV C++ in 4 HOURS | Including 3x Projects | Computer Vision,对应的Github源代码地址为:Learn-OpenCV-cpp-in-4-Hours OpenCV是一个开源的计算机视觉库,其官网地址为:https://opencv.org/,对应Github源码地址为:https://github.com/opencv/opencv,目前来说

    2024年01月17日
    浏览(60)
  • 4. QT环境下使用OPenCV(视频或摄像头读取显示在QLabel控件上)

    1. 说明 在用opencv处理图像时,图像的来源大部分情况下是从视频中读取过来的,视频可以是本地保存的视频,也可以是本地摄像头或者网络摄像头实时拍摄的视频。 效果展示: opencv读取视频 2. 具体操作 关于视频的读取,实际上也是从视频中将每一帧图像加载后,显示到Q

    2024年02月04日
    浏览(54)
  • 5. QT环境下使用OPenCV(基于TCP实现摄像头图像数据的多线程传输)

    1. 说明 通常情况下对于图像数据的采集可以放在后端进行,采集到的图像数据如果有需要可以通过通信将数据传输到前端进行显示,这其中需要使用到TCP数据传输协议和QT下的多线程开发技术。 QT当中主线程一般是界面层次的,在主线程中执行耗时较长的数据操作,会引起界

    2024年02月11日
    浏览(62)
  • [Python] pyqt6+opencv实现摄像头图像的实时读取并显示(完整源代码)

    本文将会介绍如何通过opencv来实时捕获摄像头的图像,并通过pyqt6进行图像视频呈现。 1. 通过opencv的VideoCapture类读取摄像头的每一帧图像,通过pyqt6的QLabel来显示图像 2. 根据获取的图像的宽和高大小以及QLabel的大小来动态调整最后输出的图像的宽和高 3. 调整窗体大小,动态调

    2024年01月24日
    浏览(74)
  • 4.通过Opencv采集摄像头视频数据

    VideoCapture() 虚拟采集器,一般设备号从0开始 cap.read() 读取视频帧 返回值有两个,第一个为状态值,读到帧为true 第二个值为视频帧 cap.release() 释放资源 示例程序: 运行结果: 从视频文件中读取视频帧 只处理视频,不处理音频,所以读取到的视频没有声音 播放速度设置 Vi

    2023年04月22日
    浏览(46)
  • OpenCv:采集摄像头视频、读取视频帧与视频录制

    目录 一、涉及OpenCv函数 二、什么是帧、帧的大小代表什么 三、摄像头获取视频数据 四、录制视频并保存 从设备,可以是摄像头可以是本地视频, 获取视频的函数 cv.VideoCapture()。 本函数作用在于创建一个VideoCapture或者VideoWriter对象,真正的读取和写入是通过创建的对象进行

    2024年02月16日
    浏览(49)
  • qt cpp结合VideoOutput显示摄像头数据

    运行效果如下:

    2024年02月11日
    浏览(35)
  • FPGA 20个例程篇:19.OV7725摄像头实时采集送HDMI显示(三)

           在详细介绍过OV7725 CMOS Sensor的相关背景知识和如何初始化其内部寄存器达到输出预期视频流的目的后,就到了该例程的核心内容即把OV7725输出的视频流预先缓存到外部DDR3颗粒,接着按照HDMI的视频格式把DDR3颗粒内存储的一帧一帧图像数据送显到屏幕上显示,如图1所示

    2024年01月17日
    浏览(57)
  • FPGA 20个例程篇:19.OV7725摄像头实时采集送HDMI显示(一)

           在例程“OV7725摄像头实时采集送HDMI显示”中,我们将走近FPGA图像处理的世界,图像处理、数字信号、高速接口也一直被业界公认为FPGA应用的三大主流领域,这个例程主要基于OV7725摄像头的视频图像采集项目,进行了详细地需求分析,从顶层到底层,从框架到功能,

    2024年02月02日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包