【问题标题】:Qt QML Camera to C++ QImage on AndroidAndroid上的Qt QML相机到C++ QImage
【发布时间】:2015-03-18 11:14:47
【问题描述】:

我有一个基于 Qt5.4 的程序,带有一些图像处理功能。我使用QCamera 和我的videoSurface(源自QAbstractVideoSurface)来获取VideoFrames。它在 Windows 上运行良好。

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

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

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();
}

此代码允许访问属性。但我无法以这种方式访问​​ videoSurface(使用 QCamera 我可以做到)。我想知道 QML 相机是如何工作的?是基于QCamera吗?我看到QCamera *m_cameraQDeclarativeCamera...

所以我有两个问题:

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

【问题讨论】:

标签: android qt camera qml


【解决方案1】:

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

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

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

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

    Camera {
    id: camera

    objectName: "qrCameraQML"
}

然后你从 C++ 端获取这个实例,类似于:

QObject *qmlCamera = engine.rootObjects().at(0).findChild<QObject*>("qrCameraQML");

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

camera_ = qvariant_cast<QCamera*>(qmlCamera->property("mediaObject"));

然后您所要做的就是将探针连接到实际处理 QVideoFrames 的插槽,然后将探针的源设置为 QCamera* 之前的投射:

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

probe_.setSource(camera_);

在我的示例中,camera_ 和 probe_ 很简单:

    QCamera *camera_;

QVideoProbe probe_;

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

如果您确实需要将处理后的图像发送回 qml,我建议您尝试第一种方法,看看会发生什么。

2) 不使用 Qt AFAIK,可能使用 OpenCv 或其他一些库。

【讨论】:

【解决方案2】:
  1. 我认为上面的答案充分解释了 QML 相机的处理
  2. 是的,还有其他可能性我发现这个项目对我帮助很大: https://github.com/rferrazz/CvCamView 将插件注册到 QML,它可以像这样使用:
import QtQuick 2.3
import QtQuick.Window 2.2
import CVComponents 1.0

Window {
    visible: true
    CVCAM{
        id: camera
        width: 640
        height: 480
        deviceId: "0"
        imageHeight: 640
        imageWidth: 480
    }

}

处理图像非常简单。该类仅绘制项目,因此它可以在 QML 上使用,所有其他处理都在后端进行,因此可以使用相机使用的 Mat 图像进行处理。

【讨论】:

    【解决方案3】:

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

    Camera {
        id: camera
    }
    
    VideoOutput {
        id: videoOutput
        source: camera
        filters: [ videoFilter ]
        autoOrientation: true
    }
    
    MyVideoFilter {
        id: videoFilter
        // orientation: videoOutput.orientation
    }
    

    在 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;
        }
    };
    

    ```

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

    为使事情变得更简单,考虑使用 Qt 内部函数 qt_imageFromVideoFrameQVideoFrame 转换为 QImage。此代码适用于 NoHandle 案例,适用于大多数平台。不幸的是,它不适用于许多 Android 设备,因为QVideoFrame::map() 将返回false

    extern QImage qt_imageFromVideoFrame(const QVideoFrame& f);
    

    对于 Android,您需要处理使用 OpenGL 填充 QImageGLTextureHandle 情况。

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

    #ifdef Q_OS_ANDROID
        bool flip = true;
    #else
        bool flip = surfaceFormat.scanLineDirection() == QVideoSurfaceFormat::BottomToTop;
    #endif
    

    在某些设备上,图像也可以旋转。处理旋转的最佳方式是在VideoOutput 组件中设置autoOrientation: true。然后,您的组件可以只获取videoOutput.orientation 的副本。

    了解图像如何翻转和旋转将有助于视频识别应用(例如人脸识别)。

    我还在https://github.com/stephenquan/MyVideoFilterApp上创建了一个最低工作示例

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-16
      • 2023-03-14
      • 1970-01-01
      相关资源
      最近更新 更多