在Android上Qt QML Camera to C++ QImage

Nic*_*ick 14 qt camera android qml

我有一个基于Qt5.4的程序和一些图像处理.我使用QCameramy videoSurface(派生自QAbstractVideoSurface)来获取VideoFrames.它在Windows上运行良好.

但现在我需要我的应用程序的Android版本.我发现QCamera在Android上不起作用.但我看到QML Camera示例在Android上运行没有任何问题.

所以我决定用QML重写我的应用程序.主要问题:我无法在C++中访问QML Camera表面.

void myVideoOutput::setSource(QObject *source)
{
    qDebug() << Q_FUNC_INFO << source;

    if (source == m_source.data())
        return;
    m_source = source;
    if (m_source) {
        const QMetaObject *metaObject = m_source.data()->metaObject();

        QStringList properties;
        for(int i = metaObject->propertyOffset(); i < metaObject >propertyCount(); ++i)
            properties << QString::fromLatin1(metaObject->property(i).name());
        qDebug() << properties;

    }
    .....
    emit sourceChanged();
}
Run Code Online (Sandbox Code Playgroud)

此代码提供对属性的访问.但我无法以这种方式访问​​videoSurface(使用QCamera我可以做到).我想知道QML Camera是如何工作的?它是基于QCamera?我看QCamera *m_cameraQDeclarativeCamera...

所以我有两个问题:

  1. 是否可以在C++中使用QML Camera进行后期处理图像?工作实例非常有价值.
  2. 你知道在Qt中从Android摄像头捕获视频的其他方法吗?

小智 9

1)是的,这是可能的.我有两种方法可以做到这一点.

使用QAbstractVideoFilter和QVideoFilterRunnable类(仅限QT 5.5),这些都非常棒.它们是专门针对这种情况开发的,并且非常易于使用.

网上有一些很好的例子:

https://blog.qt.io/blog/2015/03/20/introducing-video-filters-in-qt-multimedia/

http://code.qt.io/cgit/qt/qtmultimedia.git/tree/examples/multimedia/video/qmlvideofilter_opencl

这种方法的缺点是,就像这里所说的那样,在Android设备上,QVideoFrame指针不具有原始像素数据,相反,它具有需要回读的OpenGL纹理(我发布的第二个示例有解决此问题的解决方法) ),因此使这种方法不是真正的实时目的恕我直言.

我最终用来解决这个问题的是QVideoProbe类.

首先,您必须命名QML相机的实例:

    Camera {
    id: camera

    objectName: "qrCameraQML"
}
Run Code Online (Sandbox Code Playgroud)

然后你从C++端获得这个实例,例如:

QObject *qmlCamera = engine.rootObjects().at(0).findChild<QObject*>("qrCameraQML");
Run Code Online (Sandbox Code Playgroud)

QML相机实例实际上有一个QVariant元素,只能通过C++访问,可以转换为QCamera*:

camera_ = qvariant_cast<QCamera*>(qmlCamera->property("mediaObject"));
Run Code Online (Sandbox Code Playgroud)

然后你要做的就是将探针连接到一个实际处理QVideoFrames的插槽,然后将探针源设置为QCamera*previouslly cast:

    connect(&probe_,SIGNAL(videoFrameProbed(QVideoFrame)),this,SLOT(handleFrame(QVideoFrame)));

probe_.setSource(camera_);
Run Code Online (Sandbox Code Playgroud)

在我的示例中,camera_和probe_只是:

    QCamera *camera_;

QVideoProbe probe_;
Run Code Online (Sandbox Code Playgroud)

根据我的经验,这种方法比使用qt视频过滤器类要快得多(对于Android平台),但它的缺点是你基本上只读取qml的视频输出,而AFAIK你不能将后处理的视频帧发送回QML.

如果你真的需要将处理过的图像发送回qml,我建议你尝试第一种方法,看看会发生什么.

2)不使用Qt AFAIK,可能使用OpenCv或其他lib.


Ste*_*uan 5

我想强调@ waldez-junior的第一个答案.在QML中,您将QAbstractVideoFilter组件添加到VideoOutput.

Camera {
    id: camera
}

VideoOutput {
    id: videoOutput
    source: camera
    filters: [ videoFilter ]
    autoOrientation: true
}

MyVideoFilter {
    id: videoFilter
    // orientation: videoOutput.orientation
}
Run Code Online (Sandbox Code Playgroud)

在C++中,您实现了QAbstractVideoFilter组件,这是一个最小的例子:

class MyVideoFilter : public QAbstractVideoFilter
{
    Q_OBJECT

public:
    QVideoFilterRunnable *createFilterRunnable() Q_DECL_OVERRIDE
    {
        return new CustomFilterRunnable(this);
    }
};

class MyVideoFilterRunnable : public QVideoFilterRunnable
{
public:
    QVideoFrame run(QVideoFrame* input, const QVideoSurfaceFormat& surfaceFormat, RunFlags flags)
    {
        if (!input->isValid())
        {
            return *input;
        }

        // do stuff with input
        return *input;
    }
};
Run Code Online (Sandbox Code Playgroud)

```

Qt源代码中有一个QAbstractVideoFilter示例:http://code.qt.io/cgit/qt/qtmultimedia.git/tree/examples/multimedia/video/qmlvideofilter_opencl.

为了简化操作,请考虑使用Qt内部函数qt_imageFromVideoFrame将a转换QVideoFrame为a QImage.此代码适用于NoHandle大小写并适用于大多数平台.不幸的是,它不适用于很多Android设备因为QVideoFrame::map()会返回false.

extern QImage qt_imageFromVideoFrame(const QVideoFrame& f);
Run Code Online (Sandbox Code Playgroud)

对于Android,您需要处理GLTextureHandle使用OpenGL填充a的情况QImage.

在某些设备上,图像内部位缓冲区将出现翻转.

#ifdef Q_OS_ANDROID
    bool flip = true;
#else
    bool flip = surfaceFormat.scanLineDirection() == QVideoSurfaceFormat::BottomToTop;
#endif
Run Code Online (Sandbox Code Playgroud)

在某些设备上,图像也可以旋转.处理旋转的最佳方法是autoOrientation: trueVideoOutput组件中设置.然后,您的组件可以只复制一份videoOutput.orientation.

知道如何翻转和旋转图像将有助于视频识别应用(例如,面部识别).

我还在https://github.com/stephenquan/MyVideoFilterApp上创建了一个最小工作样本