使用pytorch从RGB转换为LAB?Opencv的颜色转换与自己的公式不符

Lem*_*hat 1 python opencv pytorch

为了加速我过去的一些 opencv/numpy 支持的操作,我尝试将它们转换为 PyTorch,以便在 GPU 上运行。其中第一个步骤是将 RGB 转换为 LAB。

我提到:

我已经成功地生成了这段代码:

import torch

def tensor_like(source_data, target_tensor):
    return torch.tensor(
        source_data,
        device=target_tensor.device,
        dtype=target_tensor.dtype,
    )


RGB_TO_XYZ_FACTOR_MATRIX = [
    [0.412453, 0.357580, 0.180423],
    [0.212671, 0.715160, 0.072169],
    [0.019334, 0.119193, 0.950227],
]


def cie_f(input_: torch.Tensor):
    e = 6 / 29
    return torch.where(
        input_ > e ** 3,
        input_ ** (1 / 3),
        input_ / (3 * e ** 2) + 4 / 29,
    )



def tensor_rgb_to_lab(input_: torch.Tensor):
    # input_ is expected to be RGB 0-255, and of shape B, C, H, W
    # Implemented based on formulas written here (may need to scroll down):
    # https://docs.opencv.org/4.x/de/d25/imgproc_color_conversions.html
    dtype = input_.dtype
    if not torch.is_floating_point(input_):
        input_ = input_.float()

    input_ = input_.permute(0, 2, 3, 1)
    rgb_colors = input_.reshape(-1, 3)
    rgb_colors /= 255.0

    # RGB -> XYZ
    factor_matrix = tensor_like(RGB_TO_XYZ_FACTOR_MATRIX, rgb_colors)
    xyz_colors = torch.mm(rgb_colors, factor_matrix.T)
    # xyz_colors.mul_(255)

    # XYZ -> LAB
    xyz_colors *= tensor_like([1 / 0.950456, 1.0, 1 / 1.088754], xyz_colors)
    f_xyz_colors = cie_f(xyz_colors)
    fxyz_to_lab_factor_matrix = tensor_like([
        [0.0, 500.0, 0.0],
        [116.0, -500.0, 200.0],
        [0.0, 0.0, -200.0],
    ], f_xyz_colors)
    lab_colors = torch.mm(f_xyz_colors, fxyz_to_lab_factor_matrix)
    lab_colors += tensor_like([-16, 128, 128], lab_colors)
    lab_colors[:, 0] *= 255 / 100

    lab_colors = lab_colors.view_as(input_).permute(0, 3, 1, 2)
    lab_colors = lab_colors.round_().clamp_(0, 255).type(dtype)
    return lab_colors
Run Code Online (Sandbox Code Playgroud)

将我的输出与 进行比较时cv2.cvtColor(image, cv2.COLOR_RGB2LAB),我的代码确实产生了正确的 RGB 颜色结果,例如 (000, 000, 000)、(255, 255, 255)、(000, 255, 255)、(255, 000, 255), ( 255, 255, 000), (255, 000, 000), (000, 255, 000), (000, 000, 255),但它在许多其他情况下失败(根据我的说法,超过 99% 的 RGB 颜色)测试)。

其中一种失败的情况是 RGB(128, 128, 128),open-cv 表示它对应于 Lab(137, 128, 128),但我的代码指示 Lab(194, 128, 128)。这是一个有趣的失败案例,因为只有 1 个值是错误的,我只能手动执行 L 公式的不同步骤,以尝试隔离问题:

g = np.array((0.412453+0.357580+0.180423, 0.212671+0.715160+0.072169,0.019334+0.119193+0.950227)) * 128/255
g[0]/=0.950456
g[2]/=1.088754
# g => array([0.50196078, 0.50196078, 0.50196078]). Makes sense since 128/255=0.50196078
l = 116*g[1]**(1/3)-16  # since 0.50196078>0.008856
# l => 76.18945600835188  This is already wrong according to online RGB converters
l *= 255/100
# l => 194.2831128212973  This contradicts opencv's value and correlates with mine
Run Code Online (Sandbox Code Playgroud)

在对我的代码进行四重检查之后,我开始认为 opencv 的代码中可能存在错误/舍入错误,或者他们正在执行与文档中所述不同的额外步骤。所以我查找了一些在线RGB到Lab转换器(12),在将输出L值重新调整到255范围后,它们与opencv一致。我想这确实表明了我的错误(除非网站内部依赖 opencv?)。

考虑到 RGB 值 0 和 255(或缩放到 0..1 时的 0 和 1)的结果如何正确,我认为所有 ax+b 操作都必须正确,并且一定是t**(1/3)问题所在。 ..行业是否可能出于性能优势而以某种方式使用不同的指数?

我在这里缺少什么?我使用的是opencv 4.4.0.46

Sha*_*hai 6

您可以使用 的实现:而不是自己实现此转换kornia似乎kornia.color.rgb_to_lab(image)完全按照您在函数中尝试执行的操作进行tensor_rgb_to_lab

如果您坚持,您可以在此处查看它们的实现。