3

我刚刚在 Ubuntu 12.04 上从源代码安装了 OpenCV 2.4。我正在尝试使用 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 初始化及其对输入的描述之后的这一行:

编解码器“mpeg4”的像素格式“pal8”不兼容,自动选择格式“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) 之后,我的脚本仍然无法检索任何帧;返回的标志仍然是 False。还有什么想法吗?

编辑#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)
4

1 回答 1

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?

于 2012-05-05T16:12:27.820 回答