3

I just installed OpenCV 2.4 from source on Ubuntu 12.04. I'm trying to use a Python script to write the first frame of a video to a PNG image, but I'm getting some bizarre results. Here's the 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)

Problem is, the image comes out looking like this:

half complete something or other

These are AVI files and otherwise seem to be fine. Any ideas?

Edit #1: Apologies, here is the ffmpeg version information:

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

Edit #2: In my own troubleshooting, I upgraded ffmpeg from the default 12.04 ubuntu version to the one you see in Edit #1 above. This seems to have changed things a little bit: the video which generated the frame in this question now seems to work fine, but larger videos still present with corrupted bottom halves (or bottom thirds, or fourths). Even larger videos actually segfault entirely. I'm not really sure what to make of this, other than--yet again--faulty or missing codecs. It segfaults right on the QueryFrame step.

Edit #3: I changed the code to make exclusive use of the cv2 interface (as per a link in one of the comments below). Now, video.retrieve() always returns False and no image is written.

Edit #4: I ran the following command on the video before using the new cv2 interface to read the video frames:

ffmpeg -sameq -i normal.avi p_normal.avi

The output of the command looked ok except for this one line following the initialization of ffmpeg and its description of the input:

Incompatible pixel format 'pal8' for codec 'mpeg4', auto-selecting format 'yuv420p'

Here's the full output of the command:

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%

Most importantly, the Python OpenCV code to read the frame (using the cv2 interface) still returns False (same behavior as before).

Edit #5: I have so far followed the instructions found here for installing ffmpeg and its dependencies from source, and that went smoothly. Without reinstalling OpenCV from source, I am still encountering the same problem as before where video.retrieve() returns False. In attempting to recompile OpenCV 2.4 from source, I am getting the following error during compilation:

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

If I recompile x264, libvpx, and ffmpeg with the --enable-pic flag, OpenCV compilation still fails, this time with (kdbwin.o, .rodata) instead of (avpacket.o, av_destruct_packet) respectively in the snippet above.

Edit #6: Fixed the above error by adding --enable-shared to the configuration options of libvpx and ffmpeg. OpenCV recompiled and built successfully, and ffmpeg worked just fine. Sadly, after running the previous command (ffmpeg -sameq -i normal.avi p_normal.avi), my script still couldn't retrieve any frames; the flag returned was still False. Any further ideas?

Edit #7: Here's the latest script I'm using.

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)

Edit #8: Got it! Here's what the code should be:

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)
Magsol
  • 4,640
  • 11
  • 46
  • 68

1 Answers1

2

Most likely the problem is with ffmpeg and the used video codec. Could you share one of these videos? then we can check the codec and see what's wrong. Also we don't know what ffmpeg version you've got on your system.

Just side note, why are you mixing the cv and cv2 interfaces? the code would look better by using just the cv2 interface.

Edit: I forgot to mention, I tested the code, so certainly the problem isn't in the code.

Edit 2: It's likely the problem is with ffmpeg not being able to handle your videos. Without testing the videos in question it's hard to say. You can give the cv2 interface a try, cv2.VideoCapture is what you should use to grab frames from a video file.

Edit 3: I had a look at the video, it seems the way OpenCV uses ffmpeg has a problem with your video. A quick workaround is to process your videos with ffmpeg before opening by OpenCV. ffmpeg -sameq -i normal.avi p_norma.avi gives you a video, p_norma.avi, that you can process by OpenCV without problem. For normal.avi:

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

and for the generated video p_norma.avi:

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

Hence, the generated video is about 10 times smaller. Would that be a possible solution for you?

fireant
  • 14,080
  • 4
  • 39
  • 48
  • I'd be interested to know how to make this entirely cv2-based, as the cv2 interface doesn't seem to have methods like `QueryFrame`, `CaptureFromFile`, or all the others that I call with the plain cv interface in the code snippet. Do I just do `cv2.cv._method_` instead? Also, I'll post a video as soon as I can find one. – Magsol May 05 '12 at 19:23
  • In looking for a video to send you, I've had a new development. See edit #2 in the main question. – Magsol May 05 '12 at 19:40
  • I updated the answer, there is a working example [here](http://shambool.com/2012/05/06/retrieve-every-frame-from-a-video-by-python-and-opencv-24/) showing how to use the cv2 interface for processing video files. – fireant May 06 '12 at 10:06
  • Beautiful, thanks so much for the link. I used your code exactly with the cv2 interface, and now each time I invoke `video.retrieve()`, the `flag` return value is always `False`, so most likely an ffmpeg issue. Here's a link to the video that created the original image in the post: http://dl.dropbox.com/u/1377610/normal.avi – Magsol May 06 '12 at 20:39
  • Hmm, `video.retrieve()` is still returning `False`, though ffmpeg throws a warning when I issued the command you gave me. See edit #4 for my comments. – Magsol May 07 '12 at 16:15
  • That warning is ok, just informing you what has happened and that's fine as I get that too. Did you install ffmpeg from source? I have also ffmpeg 0.10.2 and am on Ubuntu, and compiled ffmpeg from source. I suspect --enable-nonfree is missing from your ffmpeg configuration, though I'm not dogmatic but that can be the reason. On my machine, OpenCV retrives frames from `normal.avi` but all are black and works fine with the converted one. – fireant May 07 '12 at 17:17
  • Ah no, I did not install from source, though it's not the default package: the main ffmpeg website directed me to this guy's repository https://launchpad.net/~jon-severinsson/+archive/ffmpeg , which I added to the apt-get list and installed that one. Do you think it'd be worthwhile to uninstall and re-install from source? If so, what options (of the plethora listed in my original question) should I use and not use? – Magsol May 07 '12 at 17:23
  • Installing from source isn't that difficult. There is a guide [here](https://ffmpeg.org/trac/ffmpeg/wiki/UbuntuCompilationGuide) and I wrote about my experience [here](http://shambool.com/2012/05/05/install-opencv-24-on-ubuntu-1204/). In the worst case you can install back the same packages you've got. Just in case you don't know, use `make -j3` or `make -j3` (depending on the number of the cpu's cores) where the guide says fire `make`, as compiling it takes a long time. – fireant May 07 '12 at 17:42
  • In installing ffmpeg from source, I no longer get the warning about pixel formats during the conversion. However, the OpenCV frame capture still fails. I also tried recompiling OpenCV 2.4 from source, and got a compilation error around 35%. See edit #5. (by the way, thank you so much for all your help so far) – Magsol May 07 '12 at 18:10
  • Fixed the problem, but back now to the original one (my Edit #3). – Magsol May 07 '12 at 19:52
  • No problem. Can you test this [video](http://img339.imageshack.us/img339/4697/68531951.mp4)? – fireant May 07 '12 at 21:33
  • Tested it, still returned a False flag (both as the video that you gave me and after running `ffmpeg -sameq -i` on it). – Magsol May 07 '12 at 21:36
  • One more try, can you use this to convert the video `ffmpeg -i normal.avi -vcodec mjpeg p_normal.avi` and then see if OpenCV likes the output video. – fireant May 07 '12 at 21:42
  • Still no dice :( Same False return value as before. – Magsol May 07 '12 at 21:46
  • Does the script with any other video? – fireant May 07 '12 at 21:47
  • No, tried it on a bunch of other raw videos and on a few using the command in your last comment; neither worked. – Magsol May 07 '12 at 21:51
  • Can you please share the script? – fireant May 07 '12 at 21:53
  • mh... if the script is sane, you might have forgotten to remove the old so files from `/usr/lib/`. – fireant May 07 '12 at 21:59
  • See my edit #7 for the latest version of the script I'm using. I'm not sure I understand your comment; what shared libraries are in `/usr/lib` that shouldn't be there? – Magsol May 07 '12 at 22:34
  • 2
    :-) you have forgotten to call `video.grab()` before `video.retrieve()`. That should fix it. Please let me know how it goes. – fireant May 07 '12 at 22:41
  • Ahhhhhhh crap, that did it! I thought it was just a boolean check, really sorry about that. It still segfaults if I run it on a video that's too big, but the preprocessing step `ffmpeg -sameq` always seems to keep it at a size that will work. For now I'm considering this issue closed, thank you SO very much!!! – Magsol May 07 '12 at 23:36