如何从相机读取缓冲区信息?

时间:2016-06-20 23:43:48

标签: c++ qt camera qr-code

我有一个Qt应用程序的一个特定部分应该从相机拍摄照片并使用qzxing库解码QR码。但是,我无法从缓冲区中取出照片!我知道解码工作得很好,因为如果我将照片保存到文件中然后立即将其重新加载为QImage,一切正常(当然,除了图像完全保存之前程序没有阻止,所以它会尝试解码一个半图像,然后在第二次尝试时解码第一个图像。)!

有很多人在问这个问题,但似乎没有人有完整的答案。我在过去的六个小时里一直在研究和猜测和测试。 QCameraImageCapture的Qt文档存在,但根本没有谈论在QImage中传递缓冲区或转换。有几个答案在SO上有几个猜测将图像转换成QImage,还有几个谈论找到缓冲区,但没有人有完整的答案。 Qt示例文档甚至还没有完成,他们的示例项目(遍布整个网络的断开链接)并没有讨论它在做什么。

这里是一些测试代码的示例,它使用一个名为" pushButton"的按钮运行并使用mainwindow.ui进行编译。和一个名为" verticalLayout的垂直布局。"我做错了什么?

的main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QImage>
#include <QCamera>
#include <QCameraInfo>
#include <QCameraViewfinder>
#include <QCameraImageCapture>
#include <qzxing/QZXing.h>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void cameraReceiver(int f,QVideoFrame u);
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    QCameraViewfinder   *viewfinder;
    QCamera             *invCam;
    QCameraImageCapture *rawImage;
    QZXing              *decoder;
};

#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

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

    //build camera
    QList<QCameraInfo> cameras = QCameraInfo::availableCameras();
    foreach (const QCameraInfo &cameraInfo, cameras) {
        if (cameraInfo.deviceName() == "/dev/video0")
            invCam = new QCamera(cameraInfo);

    }

    //build decoder
    decoder = new QZXing;
    decoder->setDecoder(QZXing::DecoderFormat_QR_CODE);

    //build viewfinder and link to camera
    viewfinder = new QCameraViewfinder(this);
    viewfinder->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    ui->verticalLayout->addWidget(viewfinder);
    invCam->setViewfinder(viewfinder);

    //build image buffer, set camera mode to capture
    rawImage = new QCameraImageCapture(invCam);
    invCam->setCaptureMode(QCamera::CaptureStillImage);
    invCam->start();
    viewfinder->show();

    connect(rawImage,SIGNAL(imageAvailable(int,QVideoFrame)),this,SLOT(cameraReceiver(int,QVideoFrame)));
}

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

void MainWindow::cameraReceiver(int f,QVideoFrame u) {

    QImage currentImage(u.bits(), u.width(), u.height(), u.bytesPerLine(), QVideoFrame::imageFormatFromPixelFormat(u.pixelFormat()));
    QString output = decoder->decodeImage(currentImage);
    qDebug() << output;

}

void MainWindow::on_pushButton_clicked()
{
    rawImage->setCaptureDestination(QCameraImageCapture::CaptureToBuffer);
    rawImage->capture();
}

编辑:目前在Linux环境中,嵌入了摄像头。取景器显示得很好,就像我说的那样,我可以将图像捕捉到FILE没问题 - 相机工作得很好

编辑2:我在发布SO时就找到了答案:

&#34; connect&#34;电话应该使用&#34; imageCaptured&#34;信号:

connect(rawImage,SIGNAL(imageCaptured(int,QImage)),this,SLOT(cameraReceiver(int,QImage)));

然后,缓冲区中就有一个QImage。

void MainWindow::cameraReceiver(int f,QImage u) {

    QString output = decoder->decodeImage(u);
    qDebug() << output;
}

1 个答案:

答案 0 :(得分:2)

我看到你为自己找到了一个解决方案,但万一有人坚持使用它,如果有人需要使用QVideoFrame,这是一个重要提示:

问题是QVideoFrame的错误用法。必须先映射帧才能访问它:

void MainWindow::cameraReceiver(int f,QVideoFrame u) {
    if (u.isValid()) {
        if(u.map(QAbstractVideoBuffer::ReadOnly)) {//map the frame
            uchar * data = new uchar[u.mappedBytes()];//copy the buffer for QImage
            memcpy(data, u.bits(), u.mappedBytes());
            QImage image(data,
                         u.width(),
                         u.height(),
                         u.bytesPerLine(),
                         QVideoFrame::imageFormatFromPixelFormat(u.pixelFormat()),
                         simpleCleanupHandler,//handles the buffer cleanup
                         data);//required for the cleanup
            u.unmap();//unmap the frame

            QString output = decoder->decodeImage(currentImage);
            qDebug() << output;
        }
    }
}

由于QImage不会复制缓冲区,因此您必须自行完成。 simpleImageCleanupHandler看起来像这样:

static void simpleCleanupHandler(void *info)
{
    delete[] (uchar*)info;
}