Python OpenCV 2.4 пишет наполовину полные видеокадры PNG

Я только что установил OpenCV 2.4 из исходного кода на Ubuntu 12.04. Я пытаюсь использовать сценарий Python для записи первого кадра видео в изображение PNG, но получаю странные результаты. Вот код:

import numpy as np
import cv
import cv2
import sys

video = cv.CaptureFromFile(sys.argv[1])
frame = cv.QueryFrame(video)
proxy = cv.CreateImage(cv.GetSize(frame), 8, 1)
cv.CvtColor(frame, proxy, cv.CV_BGR2GRAY)
a = np.asarray(cv.GetMat(proxy))
cv2.imwrite('image.png', a)

Проблема в том, что изображение выглядит так:

что-то наполовину завершили

Это файлы AVI, и в остальном все в порядке. Любые идеи?

Редактировать №1: Извините, вот информация о версии ffmpeg:

ffmpeg version 0.10.2-4:0.10.2-0ubuntu0jon1
built on Mar 18 2012 09:59:38 with gcc 4.6.3
configuration: --extra-version='4:0.10.2-0ubuntu0jon1' --arch=amd64 --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu --disable-stripping --enable-vdpau --enable-bzlib --enable-libgsm --enable-libschroedinger --enable-libspeex --enable-libtheora --enable-libvorbis --enable-pthreads --enable-zlib --enable-libvpx --enable-runtime-cpudetect --enable-libfreetype --enable-vaapi --enable-frei0r --enable-gpl --enable-postproc --enable-x11grab --enable-librtmp --enable-libvo-aacenc --enable-version3 --enable-libvo-amrwbenc --enable-version3 --enable-libdc1394 --shlibdir=/usr/lib/x86_64-linux-gnu --enable-shared --disable-static
libavutil      51. 35.100 / 51. 35.100
libavcodec     53. 61.100 / 53. 61.100
libavformat    53. 32.100 / 53. 32.100
libavdevice    53.  4.100 / 53.  4.100
libavfilter     2. 61.100 /  2. 61.100
libswscale      2.  1.100 /  2.  1.100
libswresample   0.  6.100 /  0.  6.100
libpostproc    52.  0.100 / 52.  0.100

Редактировать №2: В моем собственном устранении неполадок я обновил ffmpeg с версии по умолчанию 12.04 ubuntu до той, которую вы видите в Правке №1 выше. Похоже, это немного изменило ситуацию: видео, сгенерировавшее кадр в этом вопросе, теперь, похоже, работает нормально, но большие видео все еще присутствуют с поврежденными нижними половинами (или нижними третями или четвертями). Даже большие видео на самом деле полностью перестают работать. Я не совсем уверен, что с этим делать, кроме - опять же - неисправных или отсутствующих кодеков. Он выходит из строя прямо на QueryFrame шаге.

Изменить № 3: я изменил код, чтобы использовать исключительно интерфейс cv2 (согласно ссылке в одном из комментариев ниже). Теперь video.retrieve() всегда возвращает False, и изображение не записывается.

Редактировать №4: Я выполнил следующую команду для видео перед использованием нового интерфейса cv2 для чтения видеокадров:

ffmpeg -sameq -i normal.avi p_normal.avi

Вывод команды выглядел нормально, за исключением этой строки после инициализации ffmpeg и ее описания ввода:

Несовместимый формат пикселей pal8 для кодека mpeg4, автоматический выбор формата yuv420p

Вот полный вывод команды:

Input #0, avi, from 'normal.avi':
  Duration: 00:01:37.60, start: 0.000000, bitrate: 1312 kb/s
    Stream #0:0: Video: rawvideo, pal8, 128x256, 5 tbr, 5 tbn, 5 tbc
Incompatible pixel format 'pal8' for codec 'mpeg4', auto-selecting format 'yuv420p'
[buffer @ 0x11a0f80] w:128 h:256 pixfmt:pal8 tb:1/1000000 sar:0/1 sws_param:
[buffersink @ 0x11a1380] auto-inserting filter 'auto-inserted scale 0' between the filter 'src' and the filter 'out'
[scale @ 0x1197da0] w:128 h:256 fmt:pal8 -> w:128 h:256 fmt:yuv420p flags:0x4
Output #0, avi, to 'p_normal.avi':
  Metadata:
    ISFT            : Lavf53.32.100
    Stream #0:0: Video: mpeg4 (FMP4 / 0x34504D46), yuv420p, 128x256, q=2-31, 200 kb/s, 5 tbn, 5 tbc
Stream mapping:
  Stream #0:0 -> #0:0 (rawvideo -> mpeg4)
Press [q] to stop, [?] for help
frame=  488 fps=  0 q=0.0 Lsize=    1497kB time=00:01:37.60 bitrate= 125.6kbits/s    
video:1480kB audio:0kB global headers:0kB muxing overhead 1.165352%

Что наиболее важно, код Python OpenCV для чтения кадра (с использованием интерфейса cv2) по-прежнему возвращает False (такое же поведение, как и раньше).

Изменить № 5: Я до сих пор следовал инструкциям, здесь для установки ffmpeg и его зависимостей из исходного кода, и все прошло гладко. Без переустановки OpenCV из исходного кода я все еще сталкиваюсь с той же проблемой, что и раньше, когда video.retrieve() возвращает False. Пытаясь перекомпилировать OpenCV 2.4 из исходного кода, я получаю следующую ошибку во время компиляции:

Linking CXX shared library ../../lib/libopencv_highgui.so
/usr/bin/ld: /usr/local/lib/libavcodec.a(avpacket.o): relocation R_X86_64_32S against `av_destruct_packet' can not be used when making a shared object; recompile with -fPIC
/usr/local/lib/libavcodec.a: could not read symbols: Bad value

Если я перекомпилирую x264, libvpx и ffmpeg с флагом --enable-pic, компиляция OpenCV все равно не удастся, на этот раз с (kdbwin.o, .rodata) вместо (avpacket.o, av_destruct_packet) соответственно в фрагменте выше.

Редактировать №6: Исправлена ​​указанная выше ошибка, добавив --enable-shared к параметрам конфигурации libvpx и ffmpeg. OpenCV успешно перекомпилирован и собран, и ffmpeg работал нормально. К сожалению, после выполнения предыдущей команды (ffmpeg -sameq -i normal.avi p_normal.avi) мой скрипт still не смог получить ни одного фрейма; возвращенный флаг все еще был ложным. Есть еще идеи?

Изменить № 7: Вот последний сценарий, который я использую.

import numpy as np
import cv2
import sys

video = cv2.VideoCapture(sys.argv[1])
flag, frame = video.retrieve()
if not flag:
  print 'Error'
  quit()
proxy = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
cv2.imwrite('image.png', proxy)

Изменить № 8: Понятно! Вот каким должен быть код:

import numpy as np
import cv2
import sys

video = cv2.VideoCapture(sys.argv[1])
if video.grab():
  flag, frame = video.retrieve()
  if not flag:
    print 'Error'
    quit()
  proxy = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  cv2.imwrite('image.png', proxy)

person Community    schedule 04.05.2012    source источник


Ответы (1)


Скорее всего проблема в ffmpeg и используемом видеокодеке. Не могли бы вы поделиться одним из этих видео? тогда мы можем проверить кодек и посмотреть, что не так. Также мы не знаем, какая версия ffmpeg установлена ​​в вашей системе.

Сразу замечание, почему вы смешиваете интерфейсы cv и cv2? код выглядел бы лучше, если бы использовался только интерфейс cv2.

Изменить: я забыл упомянуть, что я тестировал код, так что проблема определенно не в коде.

Изменить 2: вероятно, проблема в том, что ffmpeg не может обрабатывать ваши видео. Без тестирования рассматриваемых видео сложно сказать. Вы можете попробовать интерфейс cv2, cv2.VideoCapture - это то, что вы должны использовать для захвата кадров из видеофайла.

Редактировать 3: Я смотрел видео, похоже, что способ, которым OpenCV использует ffmpeg, имеет проблему с вашим видео. Быстрый обходной путь - обработать ваши видео с помощью ffmpeg перед открытием OpenCV. ffmpeg -sameq -i normal.avi p_norma.avi дает вам видео, p_norma.avi, которое вы можете без проблем обработать с помощью OpenCV. Для normal.avi:

Selected video codec: [rawbgr8flip] vfm: raw (RAW BGR8)

и для созданного видео p_norma.avi:

Selected video codec: [ffodivx] vfm: ffmpeg (FFmpeg MPEG-4)

Следовательно, сгенерированное видео примерно в 10 раз меньше. Было бы это возможным решением для вас?

person fireant    schedule 05.05.2012
comment
Мне было бы интересно узнать, как сделать это полностью на основе cv2, поскольку интерфейс cv2, похоже, не имеет таких методов, как QueryFrame, CaptureFromFile или всех других, которые я вызываю с помощью простого интерфейса cv во фрагменте кода. Я просто сделаю cv2.cv._method_ вместо этого? Кроме того, я выложу видео, как только найду его. - person Magsol; 05.05.2012
comment
В поисках видео, которое я хотел бы отправить вам, у меня была новая разработка. См. Правку №2 в основном вопросе. - person Magsol; 05.05.2012
comment
Обновил ответ, есть рабочий пример здесь, где показано, как использовать интерфейс cv2 для обработки видеофайлов. - person fireant; 06.05.2012
comment
Красиво, большое спасибо за ссылку. Я использовал ваш код именно с интерфейсом cv2, и теперь каждый раз, когда я вызываю video.retrieve(), возвращаемое значение flag всегда равно False, так что, скорее всего, проблема с ffmpeg. Вот ссылка на видео, в котором было создано исходное изображение в сообщении: dl.dropbox.com /u/1377610/normal.avi - person Magsol; 07.05.2012
comment
Хм, video.retrieve() все еще возвращает False, хотя ffmpeg выдает предупреждение, когда я дал команду, которую вы мне дали. См. Редактирование №4 для моих комментариев. - person Magsol; 07.05.2012
comment
Это предупреждение нормально, просто информирует вас о том, что произошло, и это нормально, поскольку я это тоже понимаю. Вы установили ffmpeg из исходников? У меня также есть ffmpeg 0.10.2, я использую Ubuntu и скомпилировал ffmpeg из исходников. Я подозреваю, что --enable-nonfree отсутствует в вашей конфигурации ffmpeg, хотя я не догматичен, но это может быть причиной. На моей машине OpenCV извлекает кадры из normal.avi, но все они черные и отлично работают с преобразованным. - person fireant; 07.05.2012
comment
Ах нет, я не устанавливал из исходников, хотя это не пакет по умолчанию: основной веб-сайт ffmpeg направил меня в репозиторий этого парня launchpad.net/~jon-severinsson/+archive/ffmpeg, который я добавил в список apt-get и установил его. Как вы думаете, стоит ли удалить и переустановить из исходников? Если да, то какие варианты (из множества, перечисленных в моем первоначальном вопросе) я должен использовать, а не использовать? - person Magsol; 07.05.2012
comment
Установка из исходников не так уж и сложна. Есть руководство здесь, и я написал о своем опыте здесь. В худшем случае вы можете установить те же пакеты, что и у вас. На всякий случай, если вы не знаете, используйте make -j3 или make -j3 (в зависимости от количества ядер процессора), где в руководстве указано fire make, так как компиляция занимает много времени. - person fireant; 07.05.2012
comment
При установке ffmpeg из исходного кода я больше не получаю предупреждения о форматах пикселей во время преобразования. Однако захват кадра OpenCV по-прежнему не работает. Я также попытался перекомпилировать OpenCV 2.4 из исходников и получил ошибку компиляции около 35%. См. Редактирование №5. (кстати, большое спасибо за вашу помощь) - person Magsol; 07.05.2012
comment
Исправлена ​​проблема, но теперь вернемся к исходной (мой Edit # 3). - person Magsol; 07.05.2012
comment
Без проблем. Можете ли вы протестировать это видео? - person fireant; 08.05.2012
comment
Протестировал, по-прежнему вернул флаг False (как в видео, которое вы мне дали, так и после запуска ffmpeg -sameq -i). - person Magsol; 08.05.2012
comment
Еще одна попытка, можете ли вы использовать это для преобразования видео ffmpeg -i normal.avi -vcodec mjpeg p_normal.avi, а затем посмотреть, нравится ли OpenCV выходное видео. - person fireant; 08.05.2012
comment
По-прежнему нет кубиков :( То же возвращаемое значение False, что и раньше. - person Magsol; 08.05.2012
comment
Есть ли сценарий с каким-нибудь другим видео? - person fireant; 08.05.2012
comment
Нет, попробовал это на кучу других сырых видео и на нескольких, используя команду из вашего последнего комментария; ни один не работал. - person Magsol; 08.05.2012
comment
Не могли бы вы поделиться сценарием? - person fireant; 08.05.2012
comment
м-м ... если сценарий нормальный, возможно, вы забыли удалить старые файлы so из /usr/lib/. - person fireant; 08.05.2012
comment
См. Мою правку №7 для получения последней версии сценария, который я использую. Я не уверен, что понимаю ваш комментарий; какие разделяемые библиотеки есть в /usr/lib, чего там быть не должно? - person Magsol; 08.05.2012
comment
:-) вы забыли позвонить video.grab() перед video.retrieve(). Это должно исправить это. Пожалуйста, дайте мне знать, как это происходит. - person fireant; 08.05.2012
comment
Ааааааааааааааааааааааааааааикала))) Вот и все! Я думал, что это просто логическая проверка, очень сожалею об этом. По-прежнему происходит сбой, если я запускаю его на слишком большом видео, но на этапе предварительной обработки ffmpeg -sameq кажется, что он всегда имеет размер, который будет работать. На данный момент я считаю этот вопрос закрытым, большое спасибо !!! - person Magsol; 08.05.2012