簡體   English   中英

Android上的Qt QML相機到C++ QImage

[英]Qt QML Camera to C++ QImage on Android

我有一個基於 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嗎? 我在QDeclarativeCamera中看到QCamera *m_camera ...

所以我有兩個問題:

  1. 是否可以在 C++ 中使用 QML Camera 進行后處理圖像? 工作示例將非常有價值。
  2. 您知道在 Qt 中從 Android 相機捕獲視頻的其他方法嗎?

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紋理(我發布的第二個示例具有解決此問題的解決方法),因此這種方法對於實時IMHO而言並不是很好。

我最終用來解決此問題的是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"));

然后,您要做的就是將探針連接到實際將處理QVideoFrame的插槽,然后將探針的源設置為先前投射的QCamera *:

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

probe_.setSource(camera_);

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

    QCamera *camera_;

QVideoProbe probe_;

根據我的經驗,這種方法(對於android平台)比使用qt視頻過濾器類要快得多,但是它的缺點是您基本上只能讀取qml的視頻輸出,而AFAIK則無法將后處理的視頻幀發送回qml。

如果您確實需要將經過處理的圖像發送回qml,我建議您嘗試第一種方法,看看會發生什么。

2)不支持Qt AFAIK,可能不支持OpenCv或其他一些lib。

我喜歡強調@ 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填充QImage情況下處理GLTextureHandle情況。

在某些設備上,圖像內部位緩沖器將被翻轉。

#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創建了一個最小的工作示例

  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圖像進行處理。

import GTServer
import QtQuick
import QtQuick.Controls.Material
import QtMultimedia

Item {
    id: preview
    GT {
        id: gt
    }

    CaptureSession {
        id: captureSession
        camera: Camera {
            id: camera
        }
        imageCapture: ImageCapture {
            id: imageCapture
            onImageCaptured: {
                gt.capture(videoOutput.videoSink)
            }
        }
        videoOutput: videoOutput
    }

    VideoOutput {
        id: videoOutput
        anchors.fill: parent
    }
    ...
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM