如何正确使用OpenCV VideoWriter在Python中使用float32源数据类型编写单色视频?

mwecs4sa  于 8个月前  发布在  Python
关注(0)|答案(3)|浏览(87)

我试图从Kinect传感器存储多个来源(颜色,深度和红外线)的视频文件。
我使用cv2.imshow命令可视化的This is the image,使用以下代码:

cv2.imshow("ir", ir / 65535.)
cv2.imshow("depth", depth / 4500.)
cv2.imshow("color", color)

IR和depth都是大小为(height, width)float32的数组。Color是大小为(height, width, 3)的数组,其中3是RGB通道,uint8的类型为0-255。由于IR和depth的值很大,我们需要使用上面的代码对其进行归一化。此代码给出了上面的数字。
现在我想把一系列图像数组存储为视频文件。我使用以下代码:

ir_video = cv2.VideoWriter('ir.mp4', cv2.VideoWriter_fourcc(*'MP42'), fps, (height, width), False)
depth_video = cv2.VideoWriter('depth.mp4', cv2.VideoWriter_fourcc(*'MP42'), fps, (height, width), False)
color_video = cv2.VideoWriter('color.mp4', cv2.VideoWriter_fourcc(*'MP42'), fps, (height, width), True)

for ir, depth, color in zip(ir_frames, depth_frames, color_frames):
    ir_video.write(ir / 65535.)
    depth_video.write(depth / 4500.)
    color_video.write(color)

ir_video.release()
depth_video.release()
color_video.release()

彩色视频工作得很好,看起来非常类似于cv2.imshow命令。然而,红外和深度视频被损坏。所有0 kb。我试图将fourcc代码更改为cv2.VideoWriter_fourcc(*'mp4v')。这次红外保存了一个我可以播放的视频。但它与cv2.imshow结果非常不同。它显示为here
我想知道我如何才能正确地保存的结果与cv2.imshow命令。什么fourcc代码应该使用?谢谢!

niknxzdl

niknxzdl1#

从OpenCV 4.7.0开始,可以编写16位深度的视频,请参阅pull request which added support for it
对于VideoWriter,您必须:

  • 指定CAP_FFMPEG,因为目前似乎只支持FFmpeg
  • 使用FFV1编解码器
  • {VIDEOWRITER_PROP_DEPTH, CV_16U, VIDEOWRITER_PROP_IS_COLOR, false}指定为 params

对于VideoCapture(阅读),您必须:

  • 指定CAP_FFMPEG
  • {CAP_PROP_CONVERT_RGB, false}指定为 params

请注意,这将在控制台上打印类似“VIDEOIO/FFMPEG:BGR转换已关闭...”的警告。
不过,这似乎有一些限制,请参阅拉取请求的描述。
该pull请求还添加了一个包含VideoWriterVideoCapture往返的单元测试。

62o28rlo

62o28rlo2#

问题注解中提供的解决方案将图像数据从float32转换为uint8,这足以正确保存视频。然而,由于uint8只能表示256个值,因此丢失了大量信息。这也是源数据(IR和深度)是float32,而不是彩色图像的uint8-当保存为uint8时会丢失大量信息。因此,我提出了一个解决方案,将视频保存为uint16,并使用问题作者使用的VideoWriter
首先,需要将值从float32转换为uint16(范围0- 65,535)。根据作者的代码,IR图像似乎已经落在该范围内,因此仅需要转换为uint16。然而,深度图像必须从其原始范围0-4进行归一化,500到uint16范围。这段代码应该放在作者提供的for循环中,在write方法之前。

ir = ir.astype(np.uint16)
depth = (depth * (65_535.0 / 4500.0)).astype(np.uint16)

@Marcono1234 provided an idea如何用OpenCV VideoWriter保存视频(从4.7.0版开始)但没有提供Python代码。我发现正确编程并不容易,所以我提供了一个从网络摄像头阅读图像的完整工作示例,将其转换为16位深度的单色图像并保存为这样。运行录制视频并使用键盘字母q停止录制。最重要的部分是显然是VideoWriter的定义。

import cv2
import numpy as np

video_capture = cv2.VideoCapture(0)

if not video_capture.isOpened():
    print("Error reading video file")

video_width = int(video_capture.get(cv2.CAP_PROP_FRAME_WIDTH))
video_height = int(video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT))

video_writer = cv2.VideoWriter(
    filename="video.mkv",
    apiPreference=cv2.CAP_FFMPEG,
    fourcc=cv2.VideoWriter_fourcc(*"FFV1"),
    fps=10.0,
    frameSize=(video_width, video_height),
    params=[
        cv2.VIDEOWRITER_PROP_DEPTH,
        cv2.CV_16U,
        cv2.VIDEOWRITER_PROP_IS_COLOR,
        0,  # false
    ],
)

while True:
    ret, frame = video_capture.read()
    if ret:
        # Convert the webcam image to mono 16-bit.
        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        frame = frame.astype(np.uint16)
        frame *= 2 ** 8

        video_writer.write(frame)

        cv2.imshow('Frame', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

video_capture.release()
video_writer.release()
cv2.destroyAllWindows()

为了使示例完整,您还需要以某种方式读取视频。这里再次显示了一个完整的OpenCV VideoCapture示例,其中包含单色16位深度视频。

import cv2

video_capture = cv2.VideoCapture(
    filename="video.mkv",
    apiPreference=cv2.CAP_FFMPEG,
    params=[
        cv2.CAP_PROP_CONVERT_RGB,
        0,  # false
    ],
)

if not video_capture.isOpened():
    print("Error reading video file")

while True:
    ret, frame = video_capture.read()
    if ret:
        cv2.imshow('Frame', frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

video_capture.release()
cv2.destroyAllWindows()

请注意,由于16位深度单声道视频的FFV1编码还不太常见,因此制作的视频可能无法在每个视频播放器上播放。VLC media player有这个discussed,并支持since version 3.0.18,当它发布时,一些改进也可能是come in version 4.0

yshpjwxd

yshpjwxd3#

我曾在一个类似的项目使用其他深度相机(Orbec,华硕Xtion)和afaik videowriter类的OpenCV不支持16位深度图像,这就是为什么在评论中建议你应该转换为8位.你可以看看这里我是用什么来保存这样的视频(这是关于使用OpenNI 2,但主要概念是存在的).

相关问题