У меня есть очень простое приложение, написанное на QT, в котором я хочу показать фильм с помощью QMediaPlayer
, но прежде чем отобразить какой-либо кадр, я хотел бы обнаружить на нем некоторые объекты и пометить их, нарисовав над ним прямоугольник.
Я прочитал в http://doc.qt.io/qt-5/videooverview.html что я могу получить доступ к каждому кадру по подклассам 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;
}
}
...
}
Теперь я получаю в этом фрейме функции-члена, который я хочу изменить, рисуя на нем прямоугольники в местах, где я обнаружил объекты, и затем я хотел бы отобразить их на экране (предпочтительно на каком-то виджете).
Как я могу это сделать?
Если мой VideoSurface
класс содержит QWidget
как член? или я должен подкласс QWidget
который будет содержать VideoSurface
?
В обоих случаях, как я могу отобразить этот кадр? Должен ли я сначала преобразовать его в QImage
и затем показать (это было бы удобно для меня, потому что моя система обнаружения работает с QImage
, но будет ли это эффективно)? Я знаю, что я не могу рисовать снаружи события рисования, поэтому я не могу рисовать в present
функция, так где именно должна быть эта функция рисования и как я могу ее вызвать?
Где я должен обнаружить эти объекты и изменить кадр? В present
функция, или в функции рисования?
Это зависит от вас и зависит от того, как вы предпочитаете структурировать свои занятия. Я бы предпочел иметь отдельный виджет, который содержит указатель на ваш VideoSurface и рисует данные, которые возвращаются некоторой функцией-членом VideoSurface (зависит от вашего решения в 2.)
a) QImage достаточно эффективен для некоторых целей, и если вы уже используете его в своем коде обнаружения, то у вас уже есть все в памяти и вы можете работать над этим. Как и в случае всех проблем, связанных с производительностью: проверьте и убедитесь, что производительность достаточно хороша для вас. Если это не так, вы, вероятно, также должны рассмотреть возможность обнаружения другим способом. Я работал над проектом, в котором мы обрабатывали изображения QI, преобразованные из аналогичного объекта VideoSurface в видеопотока камеры на мобильных устройствах (для изображений с относительно низким разрешением), и производительность была достаточно высокой, поэтому мы пока не удосужились использовать другие методы. Исходный код для класса VideoSurface в этом проекте (Neuronify) размещен здесь.
б) Ваш present()
Функция может излучать сигнал, к которому вы можете подключиться, из других объектов, которые извлекают последние данные из VideoSurface и сохраняют их до тех пор, пока не будет вызвана их функция рисования. Или вы можете применить данные непосредственно к некоторому виджету, который принимает данные изображения. Увидеть Использование QAbstractVideoSurface для примера этого.
Опять же, это зависит от вас 🙂 Однако, если вам нужно повысить производительность в какой-то момент, вы можете выполнить эту работу в другом потоке, чтобы избежать блокировки графического интерфейса пользователя во время обработки данных. И если вы это сделаете, вам нужно решить, нужно ли обрабатывать каждый кадр или некоторые кадры могут пропустить обработку, чтобы улучшить FPS воспроизведения. В последнем случае вам, вероятно, не следует делать это в present()
функция, так как это, скорее всего, не даст медиаплееру возможности подавать вам больше кадров, пока вы обрабатываете старые кадры.
Других решений пока нет …