gpt4 book ai didi

java - FFmpeg 无法识别每个 32 位的 3 个 channel

转载 作者:行者123 更新时间:2023-12-04 22:47:40 25 4
gpt4 key购买 nike

我正在使用 FFmpeg 将游戏的线性化深度缓冲区写入 openEXR。不幸的是,FFmpeg 没有完全遵守 openEXR 文件规范(比如允许一个 channel 使用无符号整数),所以我正在向 openEXR 写入一个浮点 channel ,使用此命令将其放入绿色 channel -f rawvideo -pix_fmt grayf32be -s %WIDTH%x%HEIGHT% -r %FPS% -i - -vf %DEFVF% -preset ultrafast -tune zerolatency -qp 6 -compression zip1 -pix_fmt gbrpf32le %NAME%_depth_%d.exr .
float 范围是从 0F 到 1F,它是线性的。我可以通过在 Blender 合成器中测试 16 位整数(每个像素分量)PNG 来确认计算和线性化是正确的。 16位整数数据写成这样short s = (short) (linearzieDepth(depth) * (Math.pow(2,16) - 1))而对于浮点数,线性化值直接写入 OpenEXR,而不乘以一个值。
但是,当查看 openEXR 文件时,它没有与 16 位 png 相同的“渐变”……当并排查看它们时,看起来 0 附近的值不是线性的,并且它们不是那么暗因为它们应该像 16 位 png 一样。
(是的,我将图像节点设置为线性),并将其与游戏中的 3D 跟踪数据进行比较,我无法重现深度,也无法使用深度缓冲区来掩盖事物,而我可以使用 png。
线性浮点范围如何与图像中的线性整数范围如此不同?
更新:
我现在用这段代码将 3 个 channel 写入 ffmpeg

float f2 = this.linearizeDepth(depth);

buffer.putFloat(f2);
buffer.putFloat(0);
buffer.putFloat(0);
字节缓冲区的大小为 width * height * 3 * 4 -> 3 个 channel ,每个 channel 4 个字节。该命令现在是 -f rawvideo -pix_fmt gbrpf32be -s %WIDTH%x%HEIGHT% -r %FPS% -i - -vf %DEFVF% -preset ultrafast -tune zerolatency -qp 6 -compression zip1 -pix_fmt gbrpf32le %NAME%_depth_%d.exr这应该意味着输入(字节缓冲区)期望具有 3 个 channel 的 32 位浮点数。 This is how it turns out
FFmpeg 以某种方式拆分 channel 或其他任何东西......可能是一个错误,可能是我的错吗?

最佳答案

问题是 grayf32be 的颜色转换至gbrpf32le .
假设源像素范围为 [0, 1],我们可以添加格式转换过滤器:-vf format=rgb48le在将像素格式转换为 gbrpf32le 之前.
看起来 FFmpeg 忽略了范围参数,修复是添加比例过滤器:scale=in_range=full:out_range=full .
更新命令:

ffmpeg -y -f rawvideo -pix_fmt grayf32be -src_range 1 -s 192x108 -i in.raw -vf "scale=in_range=full:out_range=full,format=rgb48le" -vcodec exr -compression zip1 -pix_fmt gbrpf32le -dst_range 1 out.exr

可重现的例子:
  • 创建 16 位 Tiff 图像(用作引用):
     ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1:duration=1 -pix_fmt gray16le in.tif
  • 将 Tiff 转换为浮点数(大端):
     ffmpeg -y -src_range 1 -i in.tif -pix_fmt grayf32be -dst_range 1 -f rawvideo in.raw
  • 从原始格式转换为 OpenEXR 格式:
     ffmpeg -y -f rawvideo -pix_fmt grayf32be -src_range 1 -s 192x108 -i in.raw -vf "scale=in_range=full:out_range=full,format=rgb48le" -vcodec exr -compression zip1 -pix_fmt gbrpf32le -dst_range 1 out.exr

  • 用于比较差异的 Python 代码:
    img1 = cv2.imread('in.tif', cv2.IMREAD_UNCHANGED)
    img2 = cv2.imread('out.exr', cv2.IMREAD_UNCHANGED)

    green_ch = img2[:, :, 1] # Green channel

    max_abs_diff = np.max(np.abs(green_ch*65535 - img1.astype(float)))
    最大差异为 3 (共 65535 个级别)。
    我们可能需要对过滤器参数进行一些操作......

    由于 FFmpeg 颜色转换和范围转换存在问题(看起来如此),因此在问题得到解决之前,您不会获得所需的结果。

    更新:
    当输入的像素格式为 grayf32be 时,它似乎可以正常工作(三个颜色 channel 平面格式)。
    测试:
  • 创建 16 位 Tiff 图像(用作引用):
     ffmpeg -y -f lavfi -i testsrc=size=192x108:rate=1:duration=1 -pix_fmt gray16le in.tif
  • 将 Tiff 转换为浮点数(大端):
     ffmpeg -y -src_range 1 -i in.tif -pix_fmt grayf32be -dst_range 1 -f rawvideo in.raw
  • 将“灰度平面”复制三次以获得 3 个相同的颜色平面(使用“concat 协议(protocol)”来避免任何颜色转换问题):
     ffmpeg -y -f rawvideo -pix_fmt grayf32be -s 192x108 -i "concat:in.raw|in.raw|in.raw" -f rawvideo in3.raw
  • 从 3 个颜色 channel raw 转换为 OpenEXR 格式:
     ffmpeg -y -f rawvideo -pix_fmt gbrpf32be -s 192x108 -i in3.raw -vcodec exr -compression zip1 -pix_fmt gbrpf32le out.exr

  • 用于比较差异的 Python 代码(比较 3 个颜色 channel ):
    img1 = cv2.imread('in.tif', cv2.IMREAD_UNCHANGED)
    img2 = cv2.imread('out.exr', cv2.IMREAD_UNCHANGED)

    blue_ch = img2[:, :, 0] # Blue channel
    green_ch = img2[:, :, 1] # Green channel
    red_ch = img2[:, :, 2] # Red channel

    max_red_abs_diff = np.max(np.abs(red_ch*65535 - img1.astype(float)))
    max_green_abs_diff = np.max(np.abs(green_ch*65535 - img1.astype(float)))
    max_blue_abs_diff = np.max(np.abs(blue_ch*65535 - img1.astype(float)))
    最大差异为 0.001953125 (微不足道)。

    关于java - FFmpeg 无法识别每个 32 位的 3 个 channel ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71725213/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com