Qt获取摄像头画面的每一帧数据

继承自QAbstractVideoSurface,实现它的一些虚函数,可以在实现的虚函数 present 中获取到摄像头画面的一帧数据,拿到数据之后就可以转换处理了,这里拿到数据之后,绘制在主窗口上了。
主要代码:
首先在 .pro 中加入 multimedia 模块:

QT += core gui multimedia multimediawidgets

MainWindow.cpp

#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QtWidgets>
#include <QVideosurfaceFormat>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    camera_ = new QCamera;
    surface_ = new MyVideoSurface(this);
    camera_->setViewfinder(surface_);
    camera_->start();//这里启动
}

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

QSize MainWindow::sizeHint() const
{
    return surface_->surfaceFormat().sizeHint();
}

void MainWindow::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    if (surface_->isActive()) {
        const QRect videoRect = surface_->videoRect();
        if (!videoRect.contains(event->rect())) {
            QRegion region = event->region();
            region = region.subtracted(videoRect);
            QBrush brush = palette().background();
            for (const QRect &rect : region){
                painter.fillRect(rect, brush);
            }
        }
        surface_->paint(&painter);//在主窗口绘制
    } else {
        painter.fillRect(event->rect(), palette().background());
    }
}

void MainWindow::resizeEvent(QResizeEvent *event)
{
    QMainWindow::resizeEvent(event);
    surface_->updateVideoRect();
}

MyVideoSurface.h

#ifndef MYVIDEOSURFACE_H
#define MYVIDEOSURFACE_H

#include <QAbstractVideoSurface>
#include <QImage>
#include <QRect>
#include <QVideoFrame>

class MyVideoSurface : public QAbstractVideoSurface
{
    Q_OBJECT

public:
    MyVideoSurface(QWidget *widget, QObject *parent = 0);
    QList<QVideoFrame::PixelFormat> supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType = QAbstractVideoBuffer::NoHandle) const override;
    bool isFormatSupported(const QVideoSurfaceFormat &format) const override;
    bool start(const QVideoSurfaceFormat &format) override;
    bool present(const QVideoFrame &frame) override;
    void stop() override;
    QRect videoRect() const;
    void updateVideoRect();
    void paint(QPainter *painter);

private:
    QWidget * widget_;
    QImage::Format imageFormat_;
    QRect targetRect_;
    QSize imageSize_;
    QVideoFrame currentFrame_;
};

#endif

MyVideoSurface.cpp

#include "MyVideoSurface.h"

#include <QtWidgets>
#include <qabstractvideosurface.h>
#include <qvideosurfaceformat.h>
#include <QVideoSurfaceFormat>

MyVideoSurface::MyVideoSurface(QWidget *widget, QObject *parent)
    : QAbstractVideoSurface(parent)
    , widget_(widget)
    , imageFormat_(QImage::Format_Invalid)
{
}

QList<QVideoFrame::PixelFormat> MyVideoSurface::supportedPixelFormats(QAbstractVideoBuffer::HandleType handleType) const
{
    if (handleType == QAbstractVideoBuffer::NoHandle) {
        return QList<QVideoFrame::PixelFormat>()<< QVideoFrame::Format_RGB32<< QVideoFrame::Format_ARGB32<< QVideoFrame::Format_ARGB32_Premultiplied<< QVideoFrame::Format_RGB565<< QVideoFrame::Format_RGB555;
    } else {
        return QList<QVideoFrame::PixelFormat>();
    }
}

bool MyVideoSurface::isFormatSupported(const QVideoSurfaceFormat & format) const
{
    return QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat()) != QImage::Format_Invalid && !format.frameSize().isEmpty() && format.handleType() == QAbstractVideoBuffer::NoHandle;
}

bool MyVideoSurface::start(const QVideoSurfaceFormat &format)
{
    const QImage::Format imageFormat_ = QVideoFrame::imageFormatFromPixelFormat(format.pixelFormat());
    const QSize size = format.frameSize();
    if (imageFormat_ != QImage::Format_Invalid && !size.isEmpty()) {
        this->imageFormat_ = imageFormat_;
        widget_->resize(size);
        QAbstractVideoSurface::start(format);
        widget_->updateGeometry();
        updateVideoRect();
        return true;
    }
    return false;
}

void MyVideoSurface::stop()
{
    currentFrame_ = QVideoFrame();
    targetRect_ = QRect();
    QAbstractVideoSurface::stop();
    widget_->update();
}

bool MyVideoSurface::present(const QVideoFrame &frame) //每一帧摄像头的数据,都会经过这里
{
    if (surfaceFormat().pixelFormat() != frame.pixelFormat() || surfaceFormat().frameSize() != frame.size()) {
        setError(IncorrectFormatError);
        stop();
        return false;
    }
    currentFrame_ = frame;
    widget_->repaint(targetRect_);
    return true;
}

QRect MyVideoSurface::videoRect() const
{
    return targetRect_;
}

void MyVideoSurface::updateVideoRect()
{
    QSize size = surfaceFormat().sizeHint();
    size.scale(widget_->size().boundedTo(size), Qt::KeepAspectRatio);
    targetRect_ = QRect(QPoint(0, 0), size);
    targetRect_.moveCenter(widget_->rect().center());
}

void MyVideoSurface::paint(QPainter *painter)//这里绘制每一帧数据
{
    if (currentFrame_.map(QAbstractVideoBuffer::ReadOnly)) {
        //img就是转换的数据了
        QImage img = QImage(currentFrame_.bits(),currentFrame_.width(),currentFrame_.height(),currentFrame_.bytesPerLine(),imageFormat_).mirrored(true,false).scaled(widget_->size());
        painter->drawImage(targetRect_, img, QRect(QPoint(0,0),img.size()));
        currentFrame_.unmap();
    }
}

效果:
在这里插入图片描述

代码:https://github.com/yangyang0312/QtTestCode/tree/master/testCamera (Qt5.11)

  • 6
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
要在Qt中使用OpenCV读取和显示摄像头的视频流,你需要使用OpenCV库,并将其与Qt项目集成。 下面是一个简单的例子,展示了如何使用OpenCV和Qt来读取和显示摄像头的视频流: ```cpp #include <QApplication> #include <QMainWindow> #include <QLabel> #include <QImage> #include <opencv2/opencv.hpp> int main(int argc, char *argv[]) { QApplication a(argc, argv); // 创建一个主窗口 QMainWindow window; window.setGeometry(100, 100, 800, 600); window.setWindowTitle("Camera Viewer"); // 创建一个标签用于显示图像 QLabel* label = new QLabel(&window); label->setGeometry(0, 0, 800, 600); label->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored); // 打开默认摄像头 cv::VideoCapture cap(0); if (!cap.isOpened()) { qDebug() << "Failed to open camera!"; return -1; } // 读取并显示摄像头图像 cv::Mat frame; while (cap.read(frame)) { // 将OpenCV图像转换为Qt图像 QImage qimg(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888); // 在标签上显示图像 label->setPixmap(QPixmap::fromImage(qimg).scaled(label->size(), Qt::KeepAspectRatio, Qt::FastTransformation)); qApp->processEvents(); // 处理Qt事件,以便应用程序响应用户交互 } return a.exec(); } ``` 在上面的代码中,我们创建了一个主窗口和一个标签用于显示摄像头图像。我们使用OpenCV的VideoCapture类打开默认摄像头,然后在循环中读取每一帧图像,并将其转换为Qt图像。最后,我们将Qt图像显示在标签上。 注意,为了确保应用程序响应用户交互,我们在循环中调用了`qApp->processEvents()`。 以上就是一个简单的使用OpenCV和Qt读取和显示摄像头视频流的例子。
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值