2015-01-20 7 views
13

Mam program oparty na Qt5.4 z pewnym przetwarzaniem obrazu. Używam QCamera z moją videoSurface (pochodzącą z QAbstractVideoSurface), aby uzyskać VideoFrames. Działa dobrze w systemie Windows.Qt QML Camera do C++ QImage na Androida

Ale teraz potrzebuję wersji Androida mojej aplikacji. Dowiedziałem się, że QCamera nie działają na Androidzie. Ale widzę, że przykład QML Camera działa na Androidzie bez żadnych problemów.

Postanowiłem więc przerobić moją aplikację w QML. Główny problem: Nie mogę uzyskać dostępu do powierzchni kamery QML w 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(); 
} 

Kod ten daje dostęp do właściwości. Ale nie mogę uzyskać dostępu do videoSurface w ten sposób (używając QCamera mogę to zrobić). Zastanawiam się, jak działa QML Camera? Czy jest oparty na QCamera? Widzę QCamera *m_camera w QDeclarativeCamera ...

Więc mam 2 pytania:

  1. jest to możliwe do wykorzystania QML aparatu do postprocesu obrazów w C++? Przykład roboczy byłby bardzo cenny.
  2. Czy znasz inne sposoby przechwytywania wideo z aparatu Android w Qt?

Odpowiedz

9

1) Tak, jest to możliwe. Mam na to dwa sposoby.

Używanie QAbstractVideoFilter wraz z klasami QVideoFilterRunnable (tylko QT 5.5!), Które są naprawdę świetne. Zostały opracowane specjalnie dla tego scenariusza i są dość łatwe w użyciu.

Istnieje kilka dobrych przykładów w sieci używając go:

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

Wadą tego podejścia jest, jak zostało powiedziane here to, że na urządzeniach z Androidem wskaźnik QVideoFrame doesnt ma surowe dane pikselowe, zamiast tego ma teksturę OpenGL, którą należy odczytywać wstecz (drugi przykład, który zamieściłem, ma obejście tego rozwiązania), dzięki czemu podejście to nie jest naprawdę dobre dla celów IMHO w czasie rzeczywistym.

To, czego użyłem do rozwiązania tego problemu, to klasa QVideoProbe.

Najpierw trzeba wymienić wystąpienie aparatu QML:

Camera { 
    id: camera 

    objectName: "qrCameraQML" 
} 

następnie dostać to wystąpienie z C++ boku, coś jak:

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

Instancja kamera QML faktycznie ma QVariant element dostępny tylko przez C++, który można przesłać do QCamera *:

Następnie ll trzeba zrobić, to podłączyć sondę do gniazda, które będą faktycznie obsługiwać te QVideoFrames a następnie ustawić źródło sondy jako QCamera * previouslly Obsada:

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

probe_.setSource(camera_); 

Na moim przykładzie camera_ i probe_ są po prostu:

QCamera *camera_; 

QVideoProbe probe_; 

podejście na moim doświadczeniu był o wiele szybciej (do android platform) niż przy użyciu qt klas filtrów wideo, ale ma tę wadę, że w zasadzie tylko do odczytu wyjścia wideo z QML i AFAIK nie będziecie w stanie wysłać postprocessed videoframes z powrotem do qml.

Jeśli naprawdę potrzebujesz wysłać przetworzone obrazy z powrotem do qml, radzę wypróbować pierwsze podejście i zobaczyć, co się stanie.

2) Nie z Qt AFAIK, może z OpenCv lub inną biblioteką.

+0

Używanie '' QAbstractVideoFilter' z klas QVideoFilterRunnable' działa świetnie. Chciałbym podkreślić obsługę kodu OpenGL GLTextureHandle pokazaną w http://code.qt.io/cgit/qt/qtmultimedia.git/tree/examples/multimedia/video/qmlvideofilter_opencl/rgbframehelper.h –

+0

@WaldezJunior Pierwsze rozwiązanie nie działa na Qt5.9.1, setSource zawsze zwraca false – StereoMatching

3
  1. Myślę, że odpowiedź powyżej dostatecznie wyjaśnione przetwarzanie z aparatu QML
  2. Tak, istnieją inne możliwości Znalazłem ten projekt bardzo mi pomogło: https://github.com/rferrazz/CvCamView zarejestrować wtyczkę do QML i może być używany jak to:
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 
    } 

} 

przetwarzania obrazu jest bardzo proste. Klasa tylko maluje element, dzięki czemu można go używać w QML, wszystkie inne przetwarzanie odbywa się z tyłu, więc obraz Mat używany przez kamerę może być używany do przetwarzania.

5

Lubię wyróżnić pierwszą odpowiedź @ waldez-junior. W QML dodajesz komponent QAbstractVideoFilter do VideoOutput.

Camera { 
    id: camera 
} 

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

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

W C++ zaimplementować QAbstractVideoFilter komponent, oto przykład minimalny:

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

`` `

Jest przykładem QAbstractVideoFilter w kodzie źródłowym Qt: http://code.qt.io/cgit/qt/qtmultimedia.git/tree/examples/multimedia/video/qmlvideofilter_opencl.

Aby ułatwić sobie pracę, należy rozważyć użycie wewnętrznej funkcji Qt qt_imageFromVideoFrame do konwersji QVideoFrame na . Ten kod działa dla przypadku NoHandle i działa na większości platform. Niestety, nie działa na wielu urządzeniach z systemem Android, ponieważ QVideoFrame::map() zwróci false.

extern QImage qt_imageFromVideoFrame(const QVideoFrame& f); 

Na Androidzie, trzeba obsłużyć sprawę GLTextureHandle gdzie użyć OpenGL do wypełnienia QImage.

Na niektórych urządzeniach obrazowe bufory bitów zostaną obrócone.

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

Na niektórych urządzeniach obraz można również obracać. Najlepszym sposobem radzenia sobie z rotacją jest autoOrientation: true w komponencie VideoOutput. Następnie Twój komponent może po prostu wziąć kopię videoOutput.orientation.

Wiedza na temat odwracania i obracania obrazu pomoże w rozpoznawaniu wideo (np. Rozpoznawanie twarzy).

Ja również stworzył minimalną próbkę roboczą o https://github.com/stephenquan/MyVideoFilterApp