捕获图像而不保存

Capture image without saving

本文关键字:保存 图像      更新时间:2023-10-16

基于这个线程,是否有一种方法来处理图像从相机在QML不保存它?

从文档的例子开始,capture()函数将图像保存到Pictures位置。我想要实现的是使用onImageCaptured每秒处理相机图像,但我不想将其保存到驱动器。

我已经尝试使用onimagessaved信号实现清理操作,但它也影响onImageCaptured

您可以通过mediaObject连接c++和QML。这可以通过objectName(如链接的答案)或使用专用的Q_PROPERTY(稍后会详细介绍)来完成。在任何一种情况下,您都应该以这样的代码结束:

QObject * source  // QML camera pointer obtained as described above
QObject * cameraRef = qvariant_cast<QMediaObject*>(source->property("mediaObject"));  

一旦你得到了相机的钩子,使用它作为QVideoProbe对象的源,即

QVideoProbe *probe = new QVideoProbe;
probe->setSource(cameraRef);

videoFrameProbed信号连接到合适的槽位,即

connect(probe, SIGNAL(videoFrameProbed(QVideoFrame)), this, SLOT(processFrame(QVideoFrame)));

,就是这样:你现在可以在processFrame函数中处理你的帧。这样一个函数的实现如下所示:

void YourClass::processFrame(QVideoFrame frame)
{
    QVideoFrame cFrame(frame);
    cFrame.map(QAbstractVideoBuffer::ReadOnly);
    int w {cFrame.width()};
    int h {cFrame.height()};
    QImage::Format f;
    if((f = QVideoFrame::imageFormatFromPixelFormat(cFrame.pixelFormat())) == QImage::Format_Invalid)
    {
        QImage image(cFrame.size(), QImage::Format_ARGB32);
        // NV21toARGB32 convertion!!
        //
        // DECODING HAPPENS HERE on "image"
    }
    else
    {
        QImage image(cFrame.bits(), w, h, f);
        //
        // DECODING HAPPENS HERE on "image"
    }
    cFrame.unmap();
}

这里有两个重要的实现细节:

  1. Android设备使用YUV格式,目前QImage不支持,应该手工转换。我在这里做了一个强有力的假设,即所有无效格式都是YUV。在当前的操作系统上,通过ifdef的条件可以更好地管理。
  2. 解码可能相当昂贵,所以你可以跳过帧(只需在此方法中添加计数器)或将工作卸载到专用线程。这也取决于制定框架的速度。同时减少它们的大小,例如只占用QImage的一部分,可以大大提高性能。

对于这个问题,我将完全避免objectName方法来获取mediaObject,相反,我将注册一个新的类型,以便可以使用Q_PROPERTY方法。我在想类似这样的事情:
class FrameAnalyzer 
{
    Q_OBJECT
    Q_PROPERTY(QObject* source READ source WRITE setSource)
    QObject *m_source;  // added for the sake of READ function 
    QVideoProbe probe;
    // ...
public slots:
    void processFrame(QVideoFrame frame);
}

其中setSource只是:

bool FrameAnalyzer::setSource(QObject *source)
{
    m_source = source; 
    return probe.setSource(qvariant_cast<QMediaObject*>(source->property("mediaObject")));
}

一旦照常注册,即

qmlRegisterType<FrameAnalyzer>("FrameAnalyzer", 1, 0, "FrameAnalyzer");

可以在QML中直接设置source属性,如下所示:

// other imports
import FrameAnalyzer 1.0
Item {
    Camera {
        id: camera
        // camera stuff here
        Component.onCompleted: analyzer.source = camera
    }
    FrameAnalyzer {
        id: analyzer
    }
}

这种方法的一大优点是可读性和Camera代码与处理代码之间更好的耦合。这是以(稍微)更高的实现工作为代价的。