从视频/图像中提取元数据

5 投票
5 回答
20663 浏览
提问于 2025-04-17 22:15

我正在从一个IP摄像头获取MJPEG视频流,并在我的电脑上查看和保存这个视频流。关于我怎么做的代码可以在这里找到。答案里解释了如何从这个视频流中提取图像并保存它们。

为了提取图像,我使用了答案中提到的方法,而保存图像时,我只是用OpenCV把图像放进一个avi格式的容器里。下面是代码。

writer=cv.CreateVideoWriter("video1.avi", cv.CV_FOURCC('X', '2', '6', '4'), fps, (320,240))
cv_image = cv2.imdecode(np.fromstring(jpg, dtype=np.uint8),cv2.CV_LOAD_IMAGE_COLOR)bitmap=cv.CreateImageHeader((cv_image.shape[1], cv_image.shape[0]), cv.IPL_DEPTH_8U, 3)
cv.SetData(bitmap, cv_image.tostring(), cv_image.dtype.itemsize * 3 * cv_image.shape[1])
cv.WriteFrame(writer, bitmap)

这里的bitmap就是我正在显示并放入avi容器中的图像。

因为这个图像是来自IP摄像头,所以它应该有一些元数据,比如时间戳,这是摄像头自动插入的。

问题:我该如何提取这些元数据呢?

我想到了两种方法:

  1. 从视频中提取帧,然后访问这些帧来获取时间戳。
  2. 直接从视频中提取时间戳。

我该怎么做呢?我应该用哪种方法?我正在使用Python和OpenCV,并且是在Windows 7上工作。

我还读过这个,它和我想做的事情有关,但没有解决我的问题。

5 个回答

-1

我也需要从视频中获取一些元数据,但OpenCV就是无法做到这一点。

我找到了这个这个,它们似乎可以获取元数据。

不过我还没有测试过。

0

对于视频的元数据,可以使用 ffmpeg,正如马丁·德罗曼所说的那样。

对于图片的元数据(叫做“EXIF”):

OpenCV 会忽略图片的元数据;比如说,使用 cv2.imread('bear.jpg') 这个命令会得到一个三维的 numpy 数组,里面存的是像素的亮度值(第三维是红、绿、蓝三个颜色通道)。

所以,如果你想提取 EXIF 数据,可以使用一个非常流行的 Python 图像处理库,叫做 pillow

首先,在命令行中安装 pillow: pip install pillow

然后你就可以从 bear.jpg 中提取 EXIF 数据:

import PIL.Image
from PIL.ExifTags import TAGS
from pprint import pprint

image = PIL.Image.open('bear.jpg')

# Get the exif data and map to the correct tags
exif_data = {
                PIL.ExifTags.TAGS[k]: v
                for k,v in image._getexif().items()
                if k in PIL.ExifTags.TAGS
            }

pprint(exif_data)

这将显示 EXIF 数据:

{'ExposureBiasValue': (0, 3),
 'ExposureTime': (1, 40),
 'FNumber': (280, 100),
 'ISOSpeedRatings': 100,
 ...
}

想要了解完整的 EXIF 信息,可以查看 https://exiv2.org/tags.html

1

我发现用 ffmpeg 来获取视频的元数据效果最好。

比如,

ffmpeg -i video_file.mp4

会打印出类似这样的信息:

  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: isommp42
    creation_time   : 2019-02-25T00:00:07.000000Z
    location        : +XX.XXXX+XXX.XXXX/
    location-eng    : +XX.XXXX+XXX.XXXX/
  Duration: 00:16:28.86, start: 0.000000, bitrate: 7331 kb/s
    Stream #0:0(eng): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 1920x1080, 7236 kb/s, SAR 1:1 DAR 16:9, 10.91 fps, 30 tbr, 90k tbn, 180k tbc (default)
    Metadata:
      creation_time   : 2019-02-25T00:00:07.000000Z
      handler_name    : VideoHandle
    Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, mono, fltp, 96 kb/s (default)
    Metadata:
      creation_time   : 2019-02-25T00:00:07.000000Z
      handler_name    : SoundHandle

还有一些可以在 Python 中使用的 ffmpeg 封装,比如 ffmpeg-python。我个人是通过一个 shell 脚本提取我需要的信息(creation_time),当然这个脚本可以通过 subprocess 模块来调用。

2

对于Java,你可以使用Metadata Extractor这个库。除此之外,你还可以使用ImageMagick和Exiflib,这两个都是非常棒的库(这里的“棒”是指它们非常稳定、可靠,并且还在不断更新)。不过,这两个工具都是命令行工具。如果你想用ImageMagick,也可以找到其他语言的接口来使用它。

8

如果这个单独的图片文件上有任何元数据,opencv会把它丢掉,这真是太遗憾了。

另外,mjpeg协议本身没有时间戳(它只是一个包含图片的http多部分格式,跟电子邮件附件有点像),所以你只能得到内容类型和内容长度(前提是你使用的是http1.1)。

抱歉给你带来这样的回答,但你可能需要寻找一些其他的图像处理工具,而不是依赖opencv。

撰写回答