Модификация и отображение QVideoFrames, полученных в QAbstractVideoSurface

У меня есть очень простое приложение, написанное на QT, в котором я хочу отобразить фильм с помощью QMediaPlayer, но прежде чем я буду отображать какой-либо кадр, я хотел бы обнаружить на нем некоторые объекты и пометить их, нарисовав прямоугольник над ним.

Я прочитал в http://Working%20with%20Low%20Level%20Video%20Frames что я могу получить доступ к каждому фрейму, создав подкласс QAbstractVideoSurface, и поэтому я его редактирую.

class VideoSurface : public QAbstractVideoSurface {
    Q_OBJECT

    bool present(const QVideoFrame &frame) override {
        if (surfaceFormat().pixelFormat() != frame.pixelFormat()
                || surfaceFormat().frameSize() != frame.size()) {
            setError(IncorrectFormatError);
            stop();

            return false;
        } else {
            currentFrame = frame;

            return true;
        }
    }

    ...
}

Теперь я получаю в этой функции-члене кадры, которые я хочу изменить, рисуя на них прямоугольники в местах, где я обнаружил объекты, а затем я хотел бы отобразить их на экране (желательно на каком-то виджете).

Как я могу это сделать?

  1. Должен ли мой класс VideoSurface содержать QWidget в качестве члена? или я должен подкласс QWidget, который будет содержать VideoSurface?

  2. В обоих случаях, как я могу отобразить этот кадр? Должен ли я сначала преобразовать его в QImage, а затем отобразить (это было бы удобно для меня, потому что моя система обнаружения работает с QImage, но будет ли это эффективно)? Я знаю, что я не могу рисовать вне события рисования, поэтому я не могу рисовать в функции present, так где же именно должна быть эта функция рисования и как я могу ее вызвать?

  3. Где я должен обнаружить этот объект и изменить кадр? В функции present или в функции рисования?


person notfound404    schedule 09.10.2017    source источник


Ответы (1)


  1. Это зависит от вас и от того, как вы предпочитаете структурировать свои занятия. Я бы предпочел иметь отдельный виджет, который содержит указатель на ваш VideoSurface и рисует данные, возвращаемые некоторой функцией-членом VideoSurface (зависит от вашего решения в 2.)

  2. а) QImage достаточно эффективен для некоторых целей, и если вы уже используете его в своем коде обнаружения, то у вас уже есть все в памяти и вы можете работать над этим. Как и в случае со всеми заботами, связанными с производительностью: протестируйте и посмотрите, достаточно ли хороша для вас производительность. Если это не так, вам, вероятно, также придется рассмотреть возможность обнаружения по-другому. Я работал над проектом, в котором мы обрабатывали изображения QImage, преобразованные из аналогичного VideoSurface в поток камеры на мобильных устройствах (для изображений с относительно низким разрешением), и производительность была достаточно хорошей, поэтому мы еще не удосужились использовать другие методы. Исходный код класса VideoSurface в этом проекте (Neuronify) : размещено здесь. б) Ваша функция present() может генерировать сигнал, к которому вы можете подключиться от других объектов, которые извлекают последние данные из VideoSurface и сохраняют их до тех пор, пока не будет вызвана их функция рисования. Или вы можете применить данные непосредственно к некоторому виджету, который принимает данные изображения. В качестве примера см. Использование QAbstractVideoSurface.

  3. Опять же, это зависит от вас :) Однако, если вам нужно повысить производительность в какой-то момент, вы можете выполнить эту работу в другом потоке, чтобы ваш графический интерфейс не блокировался во время обработки данных. И если вы это сделаете, вам нужно решить, нужно ли вам обрабатывать каждый кадр или некоторые кадры можно пропустить, чтобы улучшить FPS при воспроизведении. В последнем случае вам, вероятно, не следует делать это в функции present(), так как это, вероятно, помешает медиаплееру передать вам больше кадров, пока вы обрабатываете старые кадры.

person dragly    schedule 09.10.2017