Qt QML摄像头至C++;Android上的QImage

Qt QML摄像头至C++;Android上的QImage,android,qt,camera,qml,Android,Qt,Camera,Qml,我有一个基于Qt5.4的带有一些图像处理的程序。我使用QCamera和我的videoSurface(源自QAbstractVideoSurface)来获取视频帧。它在Windows上运行良好 但现在我需要Android版本的应用程序。我发现QCamera在Android上不起作用。但我看到QML摄像头示例在Android上运行时没有任何问题 所以我决定用QML重写我的应用程序。 主要问题:在C++中,我不能访问QML相机的表面。 void myVideoOutput::setSource(QOb

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

但现在我需要Android版本的应用程序。我发现
QCamera
在Android上不起作用。但我看到QML摄像头示例在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();
}
void myVideoOutput::setSource(QObject*source)
{
qDebug()propertyOffset();ipropertyCount();++i)
属性(i.name());
是的,这是可能的。我想到了两种方法

使用QBStractVideoFilter和QVideoFilterRunnable类(仅限Qt5.5!)非常好。它们是专门为这种情况开发的,非常容易使用

网络上有几个使用它的好例子:

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

我最后用来解决这个问题的是课堂

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

    Camera {
    id: camera

    objectName: "qrCameraQML"
}

然后从C++方面得到这个实例,类似于:

QObject *qmlCamera = engine.rootObjects().at(0).findChild<QObject*>("qrCameraQML");
在我的示例中,摄像头和探头只是:

    QCamera *camera_;

QVideoProbe probe_;
根据我的经验,这种方法(对于android平台)比使用qt视频过滤器类快得多,但它的缺点是基本上只读取来自qml的视频输出,并且可能无法将后处理视频帧发送回qml

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

2) Qtafaik没有,可能是OpenCv或其他库

  • 我认为上面的答案充分解释了QML摄像机的处理过程
  • 是的,我发现这个项目对我有很多帮助: 将插件注册到QML,可以这样使用:

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

    我想突出显示@waldez junior first answer。在QML中,您将
    QAbstractVideoFilter
    组件添加到视频输出中

    Camera {
        id: camera
    }
    
    VideoOutput {
        id: videoOutput
        source: camera
        filters: [ videoFilter ]
        autoOrientation: true
    }
    
    MyVideoFilter {
        id: videoFilter
        // orientation: videoOutput.orientation
    }
    
    在C++中,你实现了QueXToFieldFulter 组件,这里有一个极小的例子:

    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示例:

    为了使事情更容易,考虑使用Qt内部函数<代码> QtyIMAGIVIOVFROWRAME/<代码>将<代码> qVoFrRAME> <代码>转换为<代码> QImage <代码>。该代码适用于<代码> NoHandle Case>>并在大多数平台上运行。不幸的是,它不适用于很多Android设备,因为<代码> QVIEFFRAM::MAP()

    将返回
    false

    extern QImage qt_imageFromVideoFrame(const QVideoFrame& f);
    
    对于Android,您需要处理
    GLTextureHandle
    的情况,即使用OpenGL填充
    QImage

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

    #ifdef Q_OS_ANDROID
        bool flip = true;
    #else
        bool flip = surfaceFormat.scanLineDirection() == QVideoSurfaceFormat::BottomToTop;
    #endif
    
    在某些设备上,图像也可能会旋转。处理旋转的最佳方法是在
    VideoOutput
    组件中设置
    autoOrientation:true
    。然后,您的组件就可以复制
    VideoOutput.orientation

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


    我还使用
    qbstractvideofilter
    QVideoFilterRunnable
    类在

    上创建了一个最小的工作示例。我想强调一下@WaldezJunior First solution中显示的OpenGL代码处理GLTextureHandle在Qt5.9.1上不工作,setSource始终返回False对于所有其他具有类似问题的人问题:看,我希望这能帮上一点忙
    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;
        }
    };
    
    extern QImage qt_imageFromVideoFrame(const QVideoFrame& f);
    
    #ifdef Q_OS_ANDROID
        bool flip = true;
    #else
        bool flip = surfaceFormat.scanLineDirection() == QVideoSurfaceFormat::BottomToTop;
    #endif