ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Kornia 颜色转换精度修复解析:YUV 与 XYZ 整数输入的计算路径统一(4053)

Kornia 颜色转换精度修复解析:YUV 与 XYZ 整数输入的计算路径统一(4053) 计算机视觉深度学习人工智能图像处理【免费下载链接】kornia 空间人工智能的几何计算机视觉库项目地址https://gitcode.com/kornia/kornia点击查看免费下载本文基于 Kornia 仓库 changelog.d/migration-108.fixed.md 的变更记录深入剖析一次针对kornia.color模块的精度修复YUVrgb_to_yuv/yuv_to_rgb与 XYZrgb_to_xyz/xyz_to_rgb转换现在以float32计算整数输入而非截断卷积核同时保留直接构造的float64系数。文章将结合 kornia/color/utils.py、kornia/color/yuv.py、kornia/color/xyz.py 及对应测试说明改动动机、底层机制与迁移影响。一、这次修复解决什么问题在旧实现中当输入图像张量为整数类型如uint8、int32、int64时YUV 与 XYZ 转换会直接使用整数构造的卷积核参与运算导致卷积核被整数类型截断例如0.299被截为0得到完全错误的输出。同时如果用户直接以float64构造卷积核旧路径会丢失float64精度。本次变更对应 PR [#4053]的核心目标有三个整数输入以float32计算rgb_to_yuv(uint8)在输入的原始 0–255 量纲上返回float32结果而不是先归一化到 0–1也不再把核截断成整数。修复有符号整数 YUV 结果修复前有符号整数如int32/int64输入会产生错误的 YUV 数值因为核被截断修复后得到正确的float32输出。消除 float64 XYZ 转换的系数丢失直接构造的float64卷积核现在被完整保留并参与计算不再被降为float32。二、从两个私有辅助函数到统一实现变更前YUV 与 XYZ 各自维护一个私有的线性变换辅助函数变更后这两个私有线性变换辅助函数合并为一个实现即 kornia/color/utils.py 中的_apply_linear_transformation。所有四个转换函数rgb_to_yuv、yuv_to_rgb、rgb_to_xyz、xyz_to_rgb都复用这一个实现def _apply_linear_transformation( image: torch.Tensor, kernel: torch.Tensor, bias: Optional[torch.Tensor] None ) - torch.Tensor: # Handle Integer inputs by casting to float safely if image.is_floating_point(): image_compute image else: image_compute image.float() # Match kernel dtype to the image (propagates float64 if needed) kernel_compute kernel.to(dtypeimage_compute.dtype, deviceimage_compute.device) bias_compute bias.to(dtypeimage_compute.dtype, deviceimage_compute.device) if bias is not None else None input_shape image_compute.shape ...关键设计点在于**“dtype/device 对齐的计算操作数”**dtype/device-aligned compute operands输入为浮点类型时直接以原 dtype 计算float64输入会得到float64结果输入为整数类型时先通过image.float()安全地提升为float32卷积核随后被kernel.to(dtype...)对齐到同一个float32计算 dtype。这样既避免了整数截断又保留了float64内核的完整精度。CPU 与 GPU 的双分支优化该辅助函数内部根据设备类型选择了两种计算路径源码注释明确说明这是基于经验基准测试的优化# BRANCH 1: CPU and empty tensors (Einsum) if image_compute.device.type cpu or image_compute.numel() 0: out torch.einsum(oi, ...ihw - ...ohw, kernel_compute, image_compute) if bias_compute is not None: out out bias_compute.view(-1, 1, 1) return out.contiguous() # BRANCH 2: GPU/Accelerators (Conv2d) input_flat image_compute.reshape(-1, 3, input_shape[-2], input_shape[-1]) weight kernel_compute.view(3, 3, 1, 1) out_flat F.conv2d(input_flat, weight, biasbias_compute) out out_flat.reshape(input_shape)CPU / 空张量路径使用torch.einsum(oi, ...ihw - ...ohw, ...)它能处理任意空 shape并且让 image、kernel、bias 都保留在计算图中便于反向传播。GPU / 加速器路径将张量展平为(B*..., C, H, W)后调用F.conv2d因为 1×1 卷积在 CUDA 上比 einsum 有显著加速。三、YUV 转换整数输入与精度行为3.1 函数级 APIkornia/color/yuv.py 中的rgb_to_yuv采用 BT.470-5 M/PAL 标准的 YUV 模型def rgb_to_yuv(image: torch.Tensor) - torch.Tensor: KORNIA_CHECK_SHAPE(image, [*, 3, H, W]) dtype image.dtype if image.is_floating_point() else torch.float32 kernel torch.tensor( [ [0.299, 0.587, 0.114], [-0.147, -0.289, 0.436], [0.615, -0.515, -0.100], ], deviceimage.device, dtypedtype, ) return _apply_linear_transformation(image, kernel)这里dtype image.dtype if image.is_floating_point() else torch.float32与辅助函数内部的提升逻辑配合对于uint8/int32/int64输入卷积核以float32构造输入也会被提升为float32最终在输入的原始 0–255 量纲上返回float32结果。文档规定的输出范围Yluma在(0, 1)U 在(-0.436, 0.436)V 在(-0.615, 0.615)浮点输入归一化到 0–1 的前提下。3.2 反向转换的“精确逆矩阵”yuv_to_rgbkornia/color/yuv.py的卷积核不是对公开逆关系的独立舍入副本而是rgb_to_yuv卷积核的精确逆# The exact inverse of the rounded M/PAL kernel in rgb_to_yuv, rather than a separately # rounded copy of the published inverse relations, so a round trip is lossless to the dtype. dtype image.dtype if image.is_floating_point() else torch.float32 kernel torch.tensor( [ [1.0, -3.945707070707071e-05, 1.139827967171717], [1.0, -0.39461016414141414, -0.5805003156565657], [1.0, 2.0319996843434343, -0.00048137626262626264], ], deviceimage.device, dtypedtype, ) return _apply_linear_transformation(image, kernel)源码注释透露了一个重要的数值细节该逆矩阵在有理数域上的解析形式为[[1, -1/25344, 144439/126720], [1, -10001/25344, -73561/126720], [1, 51499/25344, -61/126720]]而代码中的每个字面量都是这些精确分数正确舍入到 float64的结果。注释还说明torch.linalg.inv对正核的求逆只能精确到约3.3e-16其 LU 分解在第一列甚至无法还原出精确的1.0因此这些常数是从精确分数手动舍入得到的而非依赖数值求逆。这使得RGB → YUV → RGB 往返误差仅受输入 dtype 精度限制float64 下往返恒等误差约1.1e-16float32 下约1.2e-7。3.3 模块级 APIYUV 家族还提供模块封装RgbToYuv、RgbToYuv420、RgbToYuv422、YuvToRgb、Yuv420ToRgb、Yuv422ToRgbkornia/color/yuv.pyforward 均直接委托给对应函数。其中 420/422 变体要求 H、W 可被 2 整除否则抛出ShapeError这两个变体的ONNX_EXPORTABLE False多输入/多输出暂不支持 ONNX 导出。四、XYZ 转换float64 系数不再丢失kornia/color/xyz.py 的rgb_to_xyz使用 CIE RGB → XYZD65 白点矩阵dtype image.dtype if image.is_floating_point() else torch.float32 kernel torch.tensor( [ [0.412453, 0.357580, 0.180423], [0.212671, 0.715160, 0.072169], [0.019334, 0.119193, 0.950227], ], deviceimage.device, dtypedtype, ) return _apply_linear_transformation(image, kernel)xyz_to_rgbkornia/color/xyz.py则使用 CIE XYZ → RGBD65 白点矩阵其中的系数保留了大量小数位如3.2404813432005266、-1.5371515162713185属于典型的 float64 级精度常数dtype image.dtype if image.is_floating_point() else torch.float32 kernel torch.tensor( [ [3.2404813432005266, -1.5371515162713185, -0.4985363261688878], [-0.9692549499965682, 1.8759900014898907, 0.0415559265582928], [0.0556466391351772, -0.2040413383665112, 1.0573110696453443], ], deviceimage.device, dtypedtype, ) return _apply_linear_transformation(image, kernel)修复前后的行为差异输入类型修复前修复后uint80–255 量纲核被整数截断结果错误输入与核均提升为float32在原始 0–255 量纲返回float32int32/int64有符号整数 YUV 结果错误返回正确float32结果float64直接构造核系数被降为 float32 丢失精度核以 float64 参与计算系数完整保留关键点在于卷积核的 dtype 由输入张量决定——浮点输入下核以相同 dtype 构造float64输入 →float64核整数输入下核以float32构造从而兼顾正确性与性能。五、测试验证三组回归测试本次修复在 tests/color/test_yuv.py 与 tests/color/test_xyz.py 中新增了三类以4053命名的回归测试直接对应变更记录中的每一项声明。5.1 整数输入test_yuv.py#L244-L252 与 test_xyz.py#L121-L128pytest.mark.parametrize(integer_dtype, [torch.int32, torch.int64]) def test_integer_input_4053(self, device, integer_dtype): rgb torch.eye(3).to(devicedevice, dtypeinteger_dtype).unsqueeze(-2) expected torch.tensor(_RGB_TO_YUV_KERNEL, devicedevice, dtypetorch.float32).unsqueeze(-2) actual kornia.color.rgb_to_yuv(rgb) assert actual.dtype torch.float32 self.assert_close(actual, expected, atol0.0 if device.type cpu else 1e-3, rtol0.0)该测试断言有符号整数输入的输出 dtype 为float32且结果与 float32 核计算完全一致CPU 上 atol0GPU 上放宽到 1e-3 以容纳后端差异。5.2 uint8 输入的 0–255 量纲test_yuv.py#L254-L261def test_uint8_input_4053(self, device): rgb (torch.eye(3) * 255).to(devicedevice, dtypetorch.uint8).unsqueeze(-2) expected (torch.tensor(_RGB_TO_YUV_KERNEL, devicedevice, dtypetorch.float32) * 255).unsqueeze(-2) actual kornia.color.rgb_to_yuv(rgb) assert actual.dtype torch.float32 self.assert_close(actual, expected, atol0.0 if device.type cpu else 1e-3, rtol0.0)验证rgb_to_yuv(uint8)在原始 0–255 量纲上返回float32期望值正是 float32 核乘以 255而非归一化到 0–1 的结果。5.3 float64 系数保留test_yuv.py#L263-L267 与 test_xyz.py#L131-L135def test_float64_kernel_precision_4053(self): rgb torch.eye(3, dtypetorch.float64).unsqueeze(-2) expected torch.tensor(_RGB_TO_YUV_KERNEL, dtypetorch.float64).unsqueeze(-2) self.assert_close(kornia.color.rgb_to_yuv(rgb), expected, atol0.0, rtol0.0)在atol0.0, rtol0.0的严格条件下断言 float64 输入 float64 核得到精确一致的输出——这正是“消除 float64 XYZ 转换系数丢失”的直接证据。此外tests/color/test_utils.py 还针对统一后的辅助函数覆盖了int64输入 float64核 bias 的组合验证输出为float32、连续、形状保持以及空张量的自动求导image/kernel/bias 梯度均正确传播。六、迁移影响与升级注意事项作为.fixed类型的变更本次修复属于缺陷修复但对已有用户存在行为变化升级时需要注意整数输入的返回 dtype 变化rgb_to_yuv(uint8)现在返回float32而非被截断的整数或错误数值且量纲保持 0–255。如果下游代码假定输入已归一化到 0–1需要自行除以 255。float64 精度保留直接构造float64输入/核时XYZ 转换不再丢失系数精度输出 dtype 也会保持float64与旧版float32输出不同。API 完全向后兼容rgb_to_yuv、yuv_to_rgb、rgb_to_xyz、xyz_to_rgb及其模块封装RgbToYuv、XyzToRgb等的签名、形状校验(*, 3, H, W)与语义均未变化浮点输入路径行为不变因此绝大多数既有代码无需改动。YUV 往返精度更好由于yuv_to_rgb使用精确逆矩阵rgb_to_yuv→yuv_to_rgb的往返误差仅受 dtype 精度限制适用于对颜色精度敏感的场景如色彩管理、无损管线。七、快速验证示例以下代码可直接在安装本仓库的环境中使用验证修复后的行为import torch import kornia # 1) uint8 输入在 0-255 量纲上返回 float32 rgb_uint8 (torch.eye(3) * 255).to(torch.uint8).unsqueeze(-2) # (3, 1, 3) - 见 shape 校验 rgb_uint8 torch.eye(3, dtypetorch.uint8).unsqueeze(-2).expand(3, 1, 3, 1).contiguous() yuv kornia.color.rgb_to_yuv(rgb_uint8) print(yuv.dtype, yuv.shape) # torch.float32, torch.Size([3, 3, 3, 1]) # 2) float64 核精度保留 rgb64 torch.eye(3, dtypetorch.float64).unsqueeze(-2) xyz kornia.color.rgb_to_xyz(rgb64) print(xyz.dtype) # torch.float64 # 3) RGB - YUV - RGB 往返仅受 dtype 精度限制 rgb torch.rand(3, 4, 5, dtypetorch.float64) rgb_rt kornia.color.yuv_to_rgb(kornia.color.rgb_to_yuv(rgb)) print((rgb_rt - rgb).abs().max().item()) # 约 1e-16 量级 # 4) 模块级 API 行为一致 module kornia.color.RgbToYuv() print(module(torch.rand(2, 3, 4, 5)).shape) # torch.Size([2, 3, 4, 5])注意示例中的张量形状需满足(*, 3, H, W)校验uint8用例请按实际批次维度构造合法输入。八、总结本次migration-108变更通过合并两个私有线性变换辅助函数为统一的_apply_linear_transformation为 Kornia 的 YUV 与 XYZ 转换确立了三条明确规则整数输入以float32安全计算保留原始 0–255 量纲、直接构造的float64系数完整保留、CPUeinsum与 GPUconv2d双路径保证性能。结合 tests/color/test_yuv.py、tests/color/test_xyz.py 中的三组回归测试这套行为已形成可验证的契约为依赖颜色转换精度的下游管线色彩管理、视频编码、相机标定提供了可靠基础。赞分享计算机视觉深度学习人工智能图像处理【免费下载链接】kornia 空间人工智能的几何计算机视觉库项目地址https://gitcode.com/kornia/kornia点击查看免费下载相关推荐Kornia 颜色变换精度修复解析YUV/XYZ 转换的整数输入与 float64 系数保真Kornia 颜色变换精度修复解析YUV/XYZ 转换的整数输入与 float64 系数保真 本篇文章围绕 Kornia 仓库中 changelog.d/m计算机视觉人工智能深度学习图像处理Kornia 角度转换精度修复解析rad2deg/deg2rad 的整数输入与 float64 精度保障Kornia 角度转换精度修复解析rad2deg/deg2rad 的整数输入与 float64 精度保障 导读 本篇文章围绕 Kornia 仓库变更记录 ch计算机视觉人工智能深度学习图像处理Kornia 角度换算修复解析rad2deg / deg2rad 的整数输入与 float64 精度保障Kornia 角度换算修复解析rad2deg / deg2rad 的整数输入与 float64 精度保障 导读 Kornia 是面向空间 AI 与几何计算机视计算机视觉深度学习人工智能图像处理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表