
Kornia 颜色变换精度修复解析YUV/XYZ 转换的整数输入与 float64 系数保真【免费下载链接】kornia Geometric Computer Vision Library for Spatial AI项目地址: https://gitcode.com/GitHub_Trending/ko/kornia本篇文章围绕 Kornia 仓库中changelog.d/migration-108.fixed.md记录的修复展开剖析rgb_to_yuv/yuv_to_rgb与rgb_to_xyz/xyz_to_rgb系列颜色空间转换在整数输入与float64系数处理上的行为变化。通过对照 kornia/color/yuv.py 与 kornia/color/xyz.py 的源码实现及 tests/color/test_yuv.py、tests/color/test_xyz.py 的回归测试读者可以掌握整数图像输入时结果 dtype 与数值尺度的正确预期、float64转换系数的保留方式以及两个私有线性变换辅助函数合并后的 CPU 计算路径。适合在迁移 Kornia 版本时排查颜色转换输出差异的开发者阅读。修复背景颜色转换中的两类精度缺陷migration-108.fixed.md对应 PR #4053描述的修复共涉及四个行为变更全部集中在颜色空间中三通道线性变换3×3 矩阵乘的实现细节上整数输入的截断问题YUV 与 XYZ 变换在计算整数输入时原来的实现会截断truncate变换核kernel的精度导致结果与预期不符float64系数的丢失当输入是直接构造的float64张量时原本独立构造的变换核系数字面量精度仅到float32会被丢弃转换精度达不到输入 dtype 应有的水平有符号整数 YUV 结果错误修复前对整数输入例如torch.int32/torch.int64执行rgb_to_yuv会产生错误的有符号整型结果实现冗余此前存在两个私有线性变换辅助函数现已合并为单一实现。核心变更一整数输入在float32中计算不再截断变换核修复后的行为契约修复后的语义可以用一句话概括对整数非浮点输入先在内部提升为float32参与矩阵运算最终结果返回float32并且输出的数值尺度与输入保持一致即uint8输入在 0–255 尺度上运算而不是先归一化到 0–1。以 kornia/color/yuv.py 中的rgb_to_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的取值规则是输入为浮点类型float16/float32/float64/bfloat16时dtype与输入一致变换核按该 dtype 构造输入为整数类型uint8/int32/int64等时dtype固定为torch.float32变换核按float32构造。uint8输入的结果示例修复后rgb_to_yuv(uint8)会在输入原始的 0–255 尺度上计算并返回float32。测试 tests/color/test_yuv.py 对此有明确的断言def 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)即对uint8输入的期望值是把float32的变换核整体乘以 255而不是把输入先除以 255 再在 0–1 尺度上计算。因此修复后rgb_to_yuv(uint8)返回float32并且数值保留在输入原始的 0–255 尺度上这正是本文档所说的 returnfloat32on the inputs original 0--255 scale。有符号整数输入的修复对int32/int64输入测试 tests/color/test_yuv.py 同样验证了输出必须是float32且与float32变换核直接作用的结果一致pytest.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修复前整数输入会被当作整型进行截断运算导致 YUV 的 U/V 分量包含负数系数产生错误的有符号整型结果修复后所有整数输入统一走float32路径输出恒为float32。同样的模式也应用于 kornia/color/xyz.py 的rgb_to_xyz与xyz_to_rgb对应测试见 tests/color/test_xyz.py 与 tests/color/test_xyz.py。核心变更二直接构造的float64系数被完整保留修复前的问题修复前XYZ 转换中的 float32 系数丢失 问题表现如下rgb_to_xyz/xyz_to_rgb的变换核字面量虽然带有完整的十进制精度例如3.2404813432005266但内部实现可能会把核强转为float32后再与float64输入运算导致float64输入的转换精度被核的float32精度所限制无法发挥float64应有的精度。修复后的实现现在的实现kornia/color/xyz.py按输入 dtype 构造核# CIE RGB to XYZ Matrix (D65 White Point) 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, ) # Apply Optimized Linear Transformation return _apply_linear_transformation(image, kernel)当输入为float64时核以float64构造字面量中的完整精度被保留。测试 tests/color/test_xyz.py 用atol0.0, rtol0.0的严格断言验证了这一点def test_float64_kernel_precision_4053(self): rgb torch.eye(3, dtypetorch.float64).unsqueeze(-2) expected torch.tensor(_RGB_TO_XYZ_KERNEL, dtypetorch.float64).unsqueeze(-2) self.assert_close(kornia.color.rgb_to_xyz(rgb), expected, atol0.0, rtol0.0)即对单位矩阵输入float64输入 float64核必须逐位等于float64变换核本身不允许任何精度损失。YUV 方向同样如此tests/color/test_yuv.py。YUV 方向的特殊情况精确逆矩阵值得单独说明的是 kornia/color/yuv.py 中yuv_to_rgb的核。它的注释明确写道该核是rgb_to_yuv舍入核的精确逆而非另行舍入的公开逆变换关系因此 RGB → YUV → RGB 的往返误差只受输入 dtype 精度限制。其在有理数域上的逆矩阵为[[1, -1/25344, 144439/126720], [1, -10001/25344, -73561/126720], [1, 51499/25344, -61/126720]]源码中的每个字面量都是上述精确分数正确舍入到float64的结果如-3.945707070707071e-05、1.139827967171717而不是调用torch.linalg.inv得到的近似值——注释指出 LU 分解连第一列的精确 1.0 都无法保证。相关回归测试见 tests/color/test_yuv.pyrgb (1, 1, 0)单位立方体上 B 通道往返误差最大的点在float64下往返误差被压到1e-12以下且 U → B 系数必须精确等于2.0319996843434343。核心变更三两个私有辅助函数合并为单一实现合并后的单一实现修复前存在两个功能重复的私有线性变换辅助函数现在统一收敛到 kornia/color/utils.py 中的_apply_linear_transformation。rgb_to_yuv、yuv_to_rgbkornia/color/yuv.py、rgb_to_xyz、xyz_to_rgbkornia/color/xyz.py四个函数均通过它完成计算。其核心逻辑分三步整数输入安全提升image.is_floating_point()为假时将输入提升为float32image.float()避免整数参与矩阵乘时的截断问题核与输入 dtype/device 对齐通过kernel.to(dtypeimage_compute.dtype, deviceimage_compute.device)把核对齐到计算 dtype 与设备。这里的关键点在于——如果输入是float64核的 dtype 会被对齐为float64从而保留全部系数精度可选偏置bias也执行同样的对齐按设备分支计算根据计算设备选择不同的矩阵运算实现。CPU 路径dtype/device 对齐的einsum计算文档中提到的 CPU path uses its dtype/device-aligned compute operands 对应 kornia/color/utils.py 的第一分支# BRANCH 1: CPU and empty tensors (Einsum) # Einsum handles every empty shape and keeps image, kernel, and bias in the graph. 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()在 CPU 上使用torch.einsum执行oi输出通道 × 输入通道与通道维的收缩变换核与输入都已完成 dtype/device 对齐因此浮点输入的精度被完整保留空张量也能被正确支持。GPU/加速器路径conv2d分支第二分支kornia/color/utils.py针对 GPU/CUDA 等加速器将输入 reshape 为(-1, 3, H, W)后用F.conv2d实现 1×1 卷积式的通道线性变换最后还原为原始形状# 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) return out_flat.reshape(input_shape)注释说明了分支选择的依据经验基准表明该模式在 CPU 上einsum更快而在 GPU/CUDA 上conv2d有显著加速因此按设备分流以获得两端的较优性能。_apply_linear_transformation自身的单元测试位于 tests/color/test_utils.py其中就包含float64核 float32输入 → 输出float32以及float32输入时核被对齐为float32的对齐行为验证。对使用者的实际影响与迁移建议输出 dtype 与尺度对照表修复后各输入类型的输出行为可总结如下输入 dtype计算/输出 dtype数值尺度说明float64float64原始尺度核按float64构造完整精度保留float32float32原始尺度常规路径行为不变float16/bfloat16float16/bfloat16原始尺度核按输入 dtype 构造uint8float320–255结果尺度与输入一致不归一化int32/int64float32原始整数尺度修复了错误的有符号整型结果需要关注的差异点uint8输入的输出尺度变化如果此前代码依赖整数输入被截断的旧行为例如期望输出落在 0–1 区间或整型结果修复后需改为按float32处理float64结果更精确float64转换现在完整保留系数精度往返误差显著下降对需要高精度颜色计算的场景如科学研究、色彩管理管线是严格改进往返误差显著下降对 YUV 而言由于yuv_to_rgb精确求逆了rgb_to_yuv的舍入核RGB → YUV → RGB 往返在float64下约为1.1e-16、float32下约为1.2e-7级别的纯浮点精度误差tests/color/test_yuv.py 给出了各 dtype 的往返容差表。验证方式仓库中的回归测试覆盖了上述全部行为整数输入与uint8输入test_integer_input_4053/test_uint8_input_4053tests/color/test_yuv.py、tests/color/test_xyz.pyfloat64核精度test_float64_kernel_precision_4053tests/color/test_yuv.py、tests/color/test_xyz.pyYUV 往返回归test_convention_yuv_to_rgb_inverts_rgb_to_yuv_4044tests/color/test_yuv.py。这些测试以4053命名直接对应文档引用的 PR 编号便于在版本迁移时定位行为变更的出处。小结migration-108.fixed.md#4053所记录的变化本质上是把颜色变换中核精度与输入 dtype解耦并统一整数输入一律提升到float32计算且保持原始数值尺度float64输入则完整保留变换核的float64精度同时将两个重复的私有辅助函数合并为 kornia/color/utils.py 中 dtype/device 对齐的单一实现。对于依赖rgb_to_yuv、yuv_to_rgb、rgb_to_xyz、xyz_to_rgb的 Kornia 用户升级后应重点核对整数图像输入的输出 dtype 与尺度并可在精度敏感场景下受益于float64系数保真带来的更低往返误差。【免费下载链接】kornia Geometric Computer Vision Library for Spatial AI项目地址: https://gitcode.com/GitHub_Trending/ko/kornia创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。