2015-01-20 10 views
13

Ho un programma basato su Qt5.4 con un po 'di elaborazione delle immagini. Io uso QCamera con il mio videoSurface (derivato da QAbstractVideoSurface) per ottenere VideoFrames. Funziona bene su Windows.Qt QML da QML a C++ QImage su Android

Ma ora ho bisogno della versione Android della mia app. Ho scoperto che QCamera non funziona su Android. Ma vedo che l'esempio di fotocamera QML funziona su Android senza problemi.

Così ho deciso di riscrivere la mia applicazione in QML. Il problema principale: non riesco ad accedere alla superficie della fotocamera QML in C++.

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

Questo codice consente di accedere alle proprietà. Ma non posso accedere a videoSurface in questo modo (usando QCamera potrei farlo). Mi chiedo come funziona la fotocamera QML? Si basa su QCamera? Vedo QCamera *m_camera in QDeclarativeCamera ...

Così ho 2 domande:

  1. è possibile utilizzare Camera QML per le immagini di post elaborazione in C++? L'esempio di lavoro sarebbe molto prezioso.
  2. Conosci altri modi per acquisire video dalla videocamera Android in Qt?

risposta

9

1) Sì, è possibile. Sono venuto in giro in due modi per farlo.

Utilizzo di QAbstractVideoFilter insieme alle classi QVideoFilterRunnable (solo QT 5.5!) Che sono semplicemente eccezionali. Sono stati sviluppati appositamente per questo scenario e sono abbastanza facili da usare.

Ci sono alcuni buoni esempi sul web che lo utilizzano:

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

Lo svantaggio di questo approccio è, come è stato detto here, è che su dispositivi Android il puntatore QVideoFrame non ha dati di pixel grezzi, invece ha una trama OpenGL che deve essere riletta (il secondo esempio che ho postato ha una soluzione che risolve questo problema), rendendo così questo approccio non proprio buono per scopi in tempo reale.

Quello che ho dovuto usare per risolvere questo problema era la classe QVideoProbe.

Prima di tutto bisogna nome all'istanza della fotocamera QML:

Camera { 
    id: camera 

    objectName: "qrCameraQML" 
} 

quindi si ottiene questo caso da un lato C++, qualcosa di simile:

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

L'istanza fotocamera QML ha in realtà un QVariant elemento accessibile solo attraverso C++ che può essere gettato in un QCamera *:

Poi un ll quello che dovete fare è quello di collegare la sonda ad uno slot che effettivamente gestire le QVideoFrames e quindi impostare la sorgente della sonda come QCamera * previouslly espressi:

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

probe_.setSource(camera_); 

Sul mio esempio camera_ e probe_ sono semplicemente:

QCamera *camera_; 

QVideoProbe probe_; 

Questo approccio sulla mia esperienza è stata molto più veloce (per le piattaforme Android) che usare le classi di filtrazione video QT, ma ha lo svantaggio che è fondamentalmente leggere solo l'uscita video da QML, e per quanto ne so è solito essere in grado di inviare videoframes postelaborati a qml.

Se hai davvero bisogno di inviare le immagini elaborate a qml ti consiglio di provare il primo approccio e vedere cosa succede.

2) Non con Qt AFAIK, forse con OpenCv, o qualche altro lib.

+0

uso di '' QAbstractVideoFilter' con classi QVideoFilterRunnable' grandi opere. Vorrei evidenziare il codice OpenGL che gestisce GLTextureHandle mostrato in http://code.qt.io/cgit/qt/qtmultimedia.git/tree/examples/multimedia/video/qmlvideofilter_opencl/rgbframehelper.h –

+0

@WaldezJunior La prima soluzione non funziona su Qt5.9.1, setSource restituisce sempre false – StereoMatching

3
  1. Penso che la risposta di cui sopra sufficientemente spiegato elaborazione dalla fotocamera QML
  2. Sì, ci sono altre possibilità che ho trovato questo progetto mi ha aiutato molto: https://github.com/rferrazz/CvCamView registrare il plugin per QML e può essere usato come questo:
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 
    } 

} 

elaborando l'immagine è così molto semplice. La classe dipinge solo l'oggetto in modo che possa essere utilizzato su QML mentre tutte le altre elaborazioni vengono eseguite nel back-end, quindi l'immagine Mat utilizzata dalla fotocamera può essere utilizzata per l'elaborazione.

5

Mi piace sottolineare @ waldez-junior prima risposta. In QML, aggiungi il tuo componente QAbstractVideoFilter a VideoOutput.

Camera { 
    id: camera 
} 

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

MyVideoFilter { 
    id: videoFilter 
    // orientation: videoOutput.orientation 
} 

In C++, si implementa QAbstractVideoFilter componente, ecco un esempio minimo:

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

`` `

C'è un esempio QAbstractVideoFilter nel codice sorgente Qt: http://code.qt.io/cgit/qt/qtmultimedia.git/tree/examples/multimedia/video/qmlvideofilter_opencl.

Per rendere le cose più facili, è consigliabile utilizzare la funzione interna Qt qt_imageFromVideoFrame per la conversione di un QVideoFrame ad un QImage. Questo codice funziona per il caso NoHandle e funziona sulla maggior parte delle piattaforme. Sfortunatamente, non funziona per molti dispositivi Android perché QVideoFrame::map() restituirà false.

extern QImage qt_imageFromVideoFrame(const QVideoFrame& f); 

per Android, è necessario per gestire il caso GLTextureHandle in cui si utilizza OpenGL per popolare un QImage.

Su alcuni dispositivi, i buffer dei bit interni dell'immagine appariranno capovolti.

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

Su alcuni dispositivi, l'immagine può anche essere ruotata. Il modo migliore per gestire la rotazione è impostato su autoOrientation: true nel componente VideoOutput. Quindi, il tuo componente può solo prendere una copia di videoOutput.orientation.

Conoscere come un'immagine viene ruotata e ruotata aiuterà nelle applicazioni di riconoscimento video (ad esempio riconoscimento facciale).

Ho anche creato un campione minimo di lavoro sulla https://github.com/stephenquan/MyVideoFilterApp