Python OpenCV 2.4 schreibt halbfertige PNG-Videobilder

Ich habe gerade OpenCV 2.4 von der Quelle auf Ubuntu 12.04 installiert. Ich versuche, mit einem Python-Skript das erste Bild eines Videos in ein PNG-Bild zu schreiben, aber ich erhalte einige bizarre Ergebnisse. Hier ist der Code:

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)

Das Problem ist, dass das Bild so aussieht:

Dies sind AVI-Dateien und scheinen ansonsten in Ordnung zu sein. Irgendwelche Ideen?

Bearbeiten Sie # 1: Entschuldigung, hier ist die Versionsinformation zu 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

Bearbeiten Sie # 2: In meiner eigenen Fehlerbehebung habe ich ffmpeg von der standardmäßigen Ubuntu-Version 12.04 auf die Version aktualisiert, die Sie in der obigen Bearbeitung Nr. 1 sehen. Dies scheint die Dinge ein wenig verändert zu haben: Das Video, das den Frame in dieser Frage erzeugt hat, scheint nun gut zu funktionieren, aber größere Videos mit beschädigten unteren Hälften (oder unteren Dritteln oder Vierteln) sind noch vorhanden. Sogar größere Videos sind völlig fehlerfrei. Ich bin mir nicht sicher, was ich davon halten soll, abgesehen von - noch einmal - fehlerhaften oder fehlenden Codecs. Es segfaults direkt amQueryFrame Schritt.

Bearbeiten Sie # 3: Ich habe den Code geändert, um ausschließlich die cv2-Benutzeroberfläche zu verwenden (siehe Link in einem der folgenden Kommentare). Jetzt,video.retrieve() kehrt immer zurückFalse und es wird kein Bild geschrieben.

Bearbeiten Sie # 4: Ich habe den folgenden Befehl für das Video ausgeführt, bevor ich die neue cv2-Schnittstelle zum Lesen der Videoframes verwendet habe:

ffmpeg -sameq -i normal.avi p_normal.avi

Die Ausgabe des Befehls sah bis auf diese eine Zeile nach der Initialisierung von ffmpeg und der Beschreibung der Eingabe in Ordnung aus:

Inkompatibles Pixelformat 'pal8' für Codec 'mpeg4', Format 'yuv420p' wird automatisch ausgewählt

Hier ist die vollständige Ausgabe des Befehls:

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%

Am wichtigsten ist jedoch, dass der Python OpenCV-Code zum Lesen des Frames (über die cv2-Schnittstelle) weiterhin False zurückgibt (dasselbe Verhalten wie zuvor).

Edit # 5: Ich habe bisher die Anweisungen befolgthier gefunden für die Installation von ffmpeg und seinen Abhängigkeiten von der Quelle, und das verlief reibungslos. Ohne die Neuinstallation von OpenCV aus dem Quellcode stoße ich immer noch auf dasselbe Problem wie zuvorvideo.retrieve() gibt False zurück. Beim Versuch, OpenCV 2.4 aus dem Quellcode neu zu kompilieren, wird beim Kompilieren der folgende Fehler angezeigt:

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

Wenn ich x264, libvpx und ffmpeg mit dem rekompiliere--enable-pic flag, OpenCV-Kompilierung schlägt immer noch fehl, diesmal mit (kdbwin.o, .rodata) anstatt (avpacket.o, av_destruct_packet) bzw. im obigen Snippet.

Bearbeiten # 6: Behebung des obigen Fehlers durch Hinzufügen--enable-shared zu den Konfigurationsoptionen von libvpx und ffmpeg. OpenCV wurde neu kompiliert und erfolgreich erstellt, und ffmpeg funktionierte einwandfrei. Leider nach dem Ausführen des vorherigen Befehls (ffmpeg -sameq -i normal.avi p_normal.avi), mein Drehbuchimmer noch konnte keine Frames abrufen; Die Flagge war immer noch falsch. Weitere Ideen?

Bearbeiten Sie # 7: Hier ist das neueste Skript, das ich verwende.

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)

Bearbeiten Sie # 8: Ich habs! Der Code sollte wie folgt lauten:

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)

Antworten auf die Frage(1)

Ihre Antwort auf die Frage