Подтвердить что ты не робот

Qt QML-камера для С++ QImage на Android

У меня есть программа на основе Qt5.4 с некоторой обработкой изображений. Я использую QCamera с моим videoSurface (полученным из QAbstractVideoSurface), чтобы получить VideoFrames. Он отлично работает в Windows.

Но теперь мне нужна версия Android для Android. Я узнал, что QCamera не работает на Android. Но я вижу, что пример камеры QML работает на Android без проблем.

Итак, я решил переписать свое приложение в QML. Основная проблема: я не могу получить доступ к поверхности 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();
}

Этот код предоставляет доступ к свойствам. Но я не могу получить доступ к видеоповерхности таким образом (используя QCamera, я мог бы это сделать). Интересно, как работает камера QML? Основано ли оно на QCamera? Я вижу QCamera *m_camera в QDeclarativeCamera...

У меня есть 2 вопроса:

  • Можно ли использовать QML-камеру для изображений постпроцесса в С++? Рабочий пример был бы очень ценным.
  • Знаете ли вы другие способы захвата видео с камеры Android в Qt?
4b9b3361

Ответ 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

Недостатком этого подхода является то, что, как было сказано здесь, это то, что на устройствах Android указатель QVideoFrame не имеет необработанных пиксельных данных, он имеет текстуру OpenGL, которая должна быть прочитана (второй пример, который я опубликовал, имеет обходное решение, разрешающее это), поэтому этот подход не очень хорош для целей реального времени IMHO.

То, что я решил использовать для решения этой проблемы, было QVideoProbe.

Сначала вы должны назвать экземпляр вашей камеры QML:

    Camera {
    id: camera

    objectName: "qrCameraQML"
}

Затем вы получите этот экземпляр со стороны С++, что-то вроде:

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

Экземпляр камеры QML фактически имеет элемент QVariant, доступный только через С++, который может быть отброшен в QCamera *:

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

Затем все, что вам нужно сделать, - это подключить зонд к слоту, который будет фактически обрабатывать QVideoFrames, а затем установить источник зонда как QCamera * previouslly cast:

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

probe_.setSource(camera_);

В моем примере camera_ и probe_ просто:

    QCamera *camera_;

QVideoProbe probe_;

Этот подход по моему опыту был намного быстрее (для платформ для Android), чем использование классов фильтра видео qt, но у него есть недостаток, заключающийся в том, что вы в основном только читаете видеовыход из qml, и AFAIK вы не сможете отправлять постобработки videoframes обратно в qml.

Если вам действительно нужно отправить обработанные изображения обратно в qml, я бы посоветовал вам попробовать первый подход и посмотреть, что произойдет.

2) Не с Qt AFAIK, может быть, с OpenCv или какой-либо другой lib.

Ответ 2

Мне нравится выделить @waldez-junior первый ответ. В QML вы добавляете свой компонент QAbstractVideoFilter к VideoOutput.

Camera {
    id: camera
}

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

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

В С++ вы реализуете компонент 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 исходном коде Qt показан пример QAbstractVideoFilter: http://code.qt.io/cgit/qt/qtmultimedia.git/tree/examples/multimedia/video/qmlvideofilter_opencl.

Чтобы упростить задачу, рассмотрите возможность использования внутренней функции Qt qt_imageFromVideoFrame для преобразования QVideoFrame в QImage. Этот код работает для случая NoHandle и работает на большинстве платформ. К сожалению, он не работает на многих устройствах Android, потому что QVideoFrame::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

На некоторых устройствах изображение может также поворачиваться. Наилучший способ обращения с вращением устанавливается autoOrientation: true в компоненте VideoOutput. Затем ваш компонент может просто взять копию videoOutput.orientation.

Знание того, как изображение перевернуто и повернуто, поможет в распознавании видеосигналов (например, распознавание лиц).

Я также создал минимальный рабочий образец на https://github.com/stephenquan/MyVideoFilterApp

Ответ 3

  • Я думаю, что ответ выше достаточно объяснил обработку с QML-камеры
  • Да, есть другие возможности, которые я нашел, этот проект мне очень помог: 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, используемое камерой, может использоваться для обработки.