【问题标题】:Qt: Capturing images continuously from camera fills the memoryQt:从相机连续捕获图像会填满内存
【发布时间】:2019-05-17 03:21:54
【问题描述】:

我正在尝试连续捕获图像,以便可以使用 UDP 发送它们。我这样做是为了实现一个实时视频流程序。

下面的代码连续捕获图像并将图像分配给 QGraphicsScene,以便我可以测试图像是否像视频一样播放。但是当我运行程序时,即使我删除了指针,我的计算机也会在几秒钟后冻结。我该如何解决这个问题?

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
scene = new QGraphicsScene(this);
ui->graphicsView->setScene(scene);
cam = new QCamera;
cam->setCaptureMode(QCamera::CaptureStillImage);

viewfinder = new QCameraViewfinder;
viewfinder->show();
QCameraImageCapture *cap = new QCameraImageCapture(cam);
cap->setCaptureDestination(QCameraImageCapture::CaptureToBuffer);

cam->setViewfinder(viewfinder);


QObject::connect(cap, &QCameraImageCapture::imageCaptured, [=] (int id, QImage img) {

     while(true){
        QByteArray *buf = new QByteArray;
        QBuffer *buffer=new QBuffer(buf);
        buffer->open(QIODevice::WriteOnly);
        img.save(buffer, "BMP");
        QPixmap *pixmap = new QPixmap();
        pixmap->loadFromData(buffer->buffer());
        scene->addPixmap(*pixmap);
        delete buf;
        delete buffer;
        delete pixmap;

        QThread::sleep(0.0416);
        cap->capture();

     }

});

QObject::connect(cap, &QCameraImageCapture::readyForCaptureChanged, [=] (bool state) {
   if(state == true) {
       cam->searchAndLock();
       cap->capture();
       cam->unlock();
   }
});
cam->start();
}

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

【问题讨论】:

  • 请告诉我你为什么不赞成我的问题。我是这个网站的新手,但在您的帮助下,我可以相应地编辑我的问题。
  • 不要担心投反对票,担心你的问题,如果你认为你的问题是最好的,你可以把它留在那里,如果你认为它可能更好,那就继续努力吧。 SO中的投票是并且应该是匿名的,所以不要要求解释,这被认为是噪音。
  • 我建议您阅读How to Ask 并改进您的问题,目前它是XY problem,因为您的目标是将图像写入缓冲区并通过套接字发送但是您要求一个可能的解决方案:但是当我运行程序时,我的计算机会在几秒钟后冻结,即使我删除了指针,您不确定它是否是正确的。

标签: c++ qt qt5 qpixmap qcamera


【解决方案1】:

您应该使用 imageAvailable() 而不是 imageCaptured 信号。

这是一个例子:

connect(cap, &QCameraImageCapture::imageAvailable, [=] (int id, QVideoFrame v ) {

    if (v.isValid()) {
        if(v.map(QAbstractVideoBuffer::ReadOnly)) {

            QByteArray bitsVideo( (char *) v.bits(), v.mappedBytes() );

            //call to your send raw data function (over UDP) : 
            //datagram will contain frame details e.g : [ width, hight, byteperline, format, rawdata ]

            sendDataOverUDP( v.width(), v.height(), 
                             v.bytesperLine(), 
                             QVideoFrame::imageFormatFromPixelFormat(v.pixelFormat()), 
                             bitsVideo );


        }
    }
});

另一方,服务器或其他客户端将根据接收到的原始数据创建图像,如下所示:

    void onDataImageReceived( int width, int height, 
                          int bytePerLine, 
                          QImage::Format fmt, 
                          QByteArray bitsVideo )
{

    QImage img ((uchar *)bitsVideo.data(), width, height, bytesPerLine, fmt);
    //do something with img ...

}

【讨论】:

    【解决方案2】:

    我不熟悉QCamera 和相关类,但是您将QCameraImageCapture::imageCaptured 信号连接到的lambda 看起来不正确。当单个帧准备好预览时发出该信号。但是,在您的 lambda 中,您有...

    while(true){
        QByteArray *buf = new QByteArray;
        QBuffer *buffer=new QBuffer(buf);
        buffer->open(QIODevice::WriteOnly);
        img.save(buffer, "BMP");
        QPixmap *pixmap = new QPixmap();
        pixmap->loadFromData(buffer->buffer());
        scene->addPixmap(*pixmap);
        delete buf;
        delete buffer;
        delete pixmap;
    
        QThread::sleep(0.0416);
        cap->capture();
    }
    

    while 循环永远不会退出并且会阻塞Qt 事件处理循环。另请注意,代码块...

    QByteArray *buf = new QByteArray;
    QBuffer *buffer=new QBuffer(buf);
    buffer->open(QIODevice::WriteOnly);
    img.save(buffer, "BMP");
    QPixmap *pixmap = new QPixmap();
    pixmap->loadFromData(buffer->buffer());
    scene->addPixmap(*pixmap);
    delete buf;
    delete buffer;
    delete pixmap;
    

    是矫枉过正并且(除非我弄错了)基本上相当于......

    scene->addPixmap(QPixmap::fromImage(img));
    

    所以我认为你的lambda 应该更像(未经测试)...

    [=](int id, QImage img)
    {
        scene->addPixmap(QPixmap::fromImage(img));
    }
    

    【讨论】:

    • 就像我在问题中所说的那样,所有这些代码行都是出于测试目的。我不只是试图在 QGraphicsScene 上显示图像,我正在尝试在缓冲区上读/写图像,以便之后我可以将这些缓冲区读/写到套接字以实现 UDP 流程序。我不能在服务器端使用scene-&gt;addPixmap(QPixmap::fromImage(img));,因为它没有图像。很遗憾,您在这里的回答对我没有帮助。对不起我的英语不好。
    • 我回答的要点是摆脱lambda 中的while (true) { ... } 循环——它阻塞了Qt 事件循环,使您的程序无响应。
    • 谢谢,但使用您的代码,我将无法将图像写入缓冲区并通过套接字发送。
    • @onurcevik 作为@G.M.提到,他试图向您展示 while 循环永远不会退出,这就是您的应用程序冻结的原因
    猜你喜欢
    • 1970-01-01
    • 2020-02-11
    • 2015-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-26
    相关资源
    最近更新 更多