1

В контейнер докер запускаю свой скрипт а он выдаёт ошибку

cv2.waitKey(1)     
cv2.error: /opencv-3.3.0/modules/highgui/src/window.cpp:676: error: (-2) The 
function is not implemented. Rebuild the library with Windows, GTK+ 2.x or 
arbon support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-
config, then re-run cmake or configure script in function cvWaitKey

Я не хочу ставить gtk внутрь контейнера. Но без этой функции не записывает видео. Чем её можно заменить?

gil9red
  • 77,085
Andru
  • 1,284

1 Answers1

2

Согласно исходникам (C++/OpenCV), функция waitKey(), а также её специализации для Qt, Gtk и Win32 напрямую никак не связаны с видеозахватом или записью видео в файл. Единственное, в чём заключается её предназначение, это ожидание нажатия одной из клавиш на время в миллисекундах, указанное в качестве аргумента для этой самой функции.

Ожидание производится при помощи C++ функции sleep(), а также запуском соответствующего специализации диспетчера системных событий. Последний как раз и предназначен для определения факта нажатия какой-либо клавиши. Соответственно в случае с Python необходимо воспользоваться таймером или аналогом sleep() из C++.

Но без этой функции не записывает видео.

Если источником видео выступает устройство видеозахвата (камера) или поток данных из сети, то необходимо иметь в виду, что на формирование каждого последующего кадра требуется определённое время. Время это необязательно константное, однако в примерах OpenCV, так или иначе затрагивающих тему работы с видеозахватом, присутствует такой вызов waitKey():

waitKey(40);

Число 40 получается по нехитрой формуле:

1000 миллисекунд / 25 кадров в секунду = 40 миллисекунд

В данном примере 40 миллисекунд - это время, которое необходимо подождать, прежде чем обращаться за следующим кадром. Если же попытаться обратиться к устройству видеозахвата раньше установленного срока, то получим пустой (повреждённый) кадр, который, если отправить его на запись, приведёт к порче уже всего видеофайла.

  • то есть, если хочется каждые interval секунд действие выполнять, то можно что-то вроде time.sleep(interval - time.monotonic() % interval) вызвать. Как правильно сделать временный цикл? – jfs Sep 13 '17 at 08:05
  • @jfs, внесите, пожалуйста, правку в ответ, чтобы добавить специфику для питона, которой я, к сожалению, не владею. –  Sep 13 '17 at 08:56
  • я не знаю что за контейнер автор запускает и не знаю как видео захватывается в этом случае (почему при отсутствие явной паузы, не блокирует вызов пока данные не поступят). Также time.sleep() не ждёт чтения с клавиатуры, поэтому в общем случае её нельзя рассматривать заменой waitKey(). Автор может попробовать time.sleep() и если в их случае это помогает, то достаточно упомянуть о time.sleep() существовании в вашем ответе. – jfs Sep 13 '17 at 09:06
  • @jfs, "почему при отсутствие явной паузы, не блокирует вызов пока данные не поступят". Если бы вызов блокировался, то в однопоточном GUI-приложении наблюдались бы фризы. Но вообще эта проблема имеет место быть лишь потому, что бекэнды видеозахвата (в OpenCV их используется несколько) не умеют выдавать события по факту готовности кадра. –  Sep 13 '17 at 09:45
  • паузу менее 40 миллисекунд, я бы не стал "фризом" называть. А если пауза может быть больше, значит waitKey(40) также не поможет. В любом случае, это не должно быть оправданием, чтобы молча данные портить по умолчанию. Вопрос о Питоне -- код для людей пишется в первую очередь. – jfs Sep 13 '17 at 10:30
  • @jfs, waitKey() запускает диспетчер событий, поэтому "фризов" не будет при любой длительности ожидания. Никто не оправдывает "порчу данных", просто в OpenCV видеозахват - это всего лишь дополнительный и не целевой инструмент для того, чтобы особо не заморачиваться и просто получить доступ к кадрам. –  Sep 13 '17 at 12:24
  • Тогда ни C++ sleep() ни time.sleep() никак не помогут. Эти вызовы о цикле событий opencv ничего не знают. – jfs Sep 13 '17 at 13:10
  • @jfs, должны помочь. Насколько мне известно, формирование данных кадра в памяти производится на уровне ядра ОС (во всяком случае это именно так с video4linux), а уже перенос этого кадра в память процесса осуществляется по запросу из самого приложения. Таким образом, даже если программа на некоторое время "заснёт", работа по обработке кадра всё равно будет произведена. –  Sep 13 '17 at 13:39
  • вы всё таки определитесь будет у вас "фриз" без waitKey() или не будет? time.sleep() это блокирующий вызов, который ничего не делает, если он может исправить ошибку по вашему, то изначальный метод следовало блокирующим делать (как sleep но только с полезной работой и по возможности, если реализация позволяет, вернуться раньше, когда готов результат: как event.wait(timeout)) – jfs Sep 13 '17 at 13:48
  • @jfs, а что тут определяться: sleep() будет "фризить" GUI (С++/однопоток, за аналог для Python не знаю), но при этом не будет "фризить" сам захват кадров. Поэтому, если не используется GUI, то всё будет работать и со sleep(), поскольку задача сводится к тому, чтобы буквально ничего не делать и просто немного подождать. Что касаемо того, следовало ли сделать изначальный метод блокирующим или нет, тут можно согласиться, а можно и нет. Например, если использовать OpenCV совместно с Qt, то вызывать просто sleep() - плохое решение по понятным причинам. Аналогично, наверное, с Gtk и с WinApi. –  Sep 13 '17 at 15:28