如何正确使用openCV videoWriter在Python中使用Float32源数据类型编写单色视频?

发布于 2025-01-22 21:37:22 字数 1506 浏览 2 评论 0 原文

我正在尝试从Kinect传感器中存储来自多个源(颜色,深度和红外线)的视频文件。

这是我使用cv2.imshow命令可视化的图像 使用以下代码:

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

ir和深度都是(高度,宽度) float32 的数组。颜色是一个大小(高度,宽度,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 命令非常相似。但是,IR和深度视频被损坏。所有0KB。 我试图将Fourcc代码更改为 cv2.videowriter_fourcc(*'mp4v')。这次,IR保存了我可以播放的视频。但这与 cv2.imshow 结果有很大不同。它显示在这里

我想知道如何与 cv2.imshow 命令正确保存结果。应该使用哪些Fourcc代码?多谢!

I am trying to store video file from multiple sources (color, depth, and infrared) from Kinect sensors.

This is the image that I visualized using cv2.imshow command
using the following code:

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

IR and depth both are array with size of (height, width), float32. Color is an array with size of (height, width, 3), where 3 is the RGB channel and uint8 type from 0-255. Since IR and depth's values are large, we need to normalize them using the code above. This code gave the above figures.

Now I want to store a series of image array as a video file. I use the following code:

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()

Color video works very well, looks very similar to the cv2.imshow command. However, IR and depth video are corrupted. All 0kb.
I tried to change the fourcc code to cv2.VideoWriter_fourcc(*'mp4v'). This time the IR one saved a video that I can play. But it is very different from the cv2.imshow result. It is shown here.

I'm wondering how I can correctly save the result as with cv2.imshow command. What fourcc code should be used? Thanks a lot!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

挖个坑埋了你 2025-01-29 21:37:22

从OpenCV 4.7.0开始,可以写16位深度视频,请参阅添加了对此的支持

对于 videoWriter 您必须:

  • 指定 cap_ffmpeg ,因为目前似乎仅支持FFMPEG,
  • 使用 ffv1
  • cododec codecify { ,false} as params

videcapture videocapture (阅读)

  • for
  • videowriter_prop_depth,cv_16u, videowriter_prop_is_color {cap_prop_convert_rgb,false} as params
    请注意,这将打印出“ Videoio/ffmpeg:BGR转换关闭...”之类的警告。

但是,似乎有一些限制,请参见

该拉的请求还添加了一个单位测试 videoWriter & videocapture 往返

Starting with OpenCV 4.7.0 it is possible to write 16-bit depth videos, see the pull request which added support for it.

For VideoWriter you have to:

  • specify CAP_FFMPEG because this only seems to be supported for FFmpeg at the moment
  • use the FFV1 codec
  • specify {VIDEOWRITER_PROP_DEPTH, CV_16U, VIDEOWRITER_PROP_IS_COLOR, false} as params

For VideoCapture (reading) you have to:

  • specify CAP_FFMPEG
  • specify {CAP_PROP_CONVERT_RGB, false} as params
    Note that this will print a warning like "VIDEOIO/FFMPEG: BGR conversion turned OFF ..." to the console.

There appear to be some limitations with this though, see the description of the pull request.

That pull request also added a unit test which contains a VideoWriter & VideoCapture round trip.

尛丟丟 2025-01-29 21:37:22

问题注释中提供的解决方案将图像数据从 float32 转换为 uint8 ,这足以保存视频。但是,由于 uint8 仅能表示256个值,因此丢失了很多信息。这也是为什么源数据(IR和深度)为 float32 而不是 uint8 的原因 - 当颜色images> - 当保存为<时会丢失很多信息。代码> uint8 。因此,我提出了一个解决方案,将视频保存在 uint16 格式中,并使用 videoWriter 提交了该问题的作者。

首先,有必要将值从 float32 转换为 uint16 (范围0-65,535)。根据作者的代码,IR映像似乎已经属于该范围,因此只需要投射到 uint16 。但是,深度图像必须从其原始范围0-4,500到 uint16 范围进行标准化。该代码应放在作者提供的写入方法之前。

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

@marcono1234 提供了一个想法如何使用 opencv VideoWriter (since version 4.7.0) but didn't provide the Python code.我发现正确编程的编程并不容易,因此我提供了一个完全有效的示例,可以将其从网络摄像头读取图像,将其转换为单色图像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()

为了使示例完成,您还想以某种方式阅读视频。 Here's again a fully working example of 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()

请注意,由于 ffv1 编码16位深度单声道视频的编码尚不那么普遍,因此每一个视频播放器都无法播放视频。 vlc Media Player 让此讨论支持它,因为版本3.0.18 ,一些改进也可能在释放时出现在版本4.0 中。

Solution provided in the question comments converts the image data from float32 to uint8 which is sufficient to save the video properly. However, a lot of information is lost due to uint8 only being able to represent 256 values. That is also the reason why the source data (IR and depth) are float32 and not uint8 as with the color images - a lot of information would be lost when saved as uint8. Therefore, I propose a solution that saves the video in uint16 format with the VideoWriter used by the author of the question.

At first, it is necessary to convert the values from float32 to uint16 (range 0-65,535). According to author's code, IR image seems to already fall in that range, so only casting to uint16 is necessary. However, depth image has to be normalized from its original range 0-4,500 to the uint16 range. This code should be placed in the for loop provided by author before the write method.

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

@Marcono1234 provided an idea how to save video with OpenCV VideoWriter (since version 4.7.0) but didn't provide the Python code. I find it not trivial to program it correctly, so I provide a fully working example of reading an image from your webcam, converting it to monochrome image 16 bits of depth and saving it as such. Run to record the video and use keyboard letter q to stop recording. The most important part is obviously the VideoWriter definition.

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()

To make the example complete, you'd also like to read the video somehow. Here's again a fully working example of OpenCV VideoCapture with monochrome 16-bit depth video.

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()

Be aware that produced video might not be playable with every video player since FFV1 encoding of 16-bit depth mono video is not so common yet. VLC media player had this discussed and supports it since version 3.0.18 and some improvements might also come in version 4.0 when it is released.

囚我心虐我身 2025-01-29 21:37:22

我使用其他深度摄像头(ORBBEC,ASUS XTION)和AFAIK VIDEOWRITER类的OpenCV类似的项目进行了类似项目的工作,这就是为什么您应该转换为8位的评论中建议的。您可以看一下

I worked on a similar project using other depth cameras (Orbbec, Asus Xtion) and afaik videowriter class of OpenCV does not support 16-bit depth images, that's why as suggested in the comments you should convert to 8 bit. You can take a look here for what I was using to save such a video (It's about using OpenNI2 but the main concept is there).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文