将RGB图像转换为LAB图像时出现意外输出

时间:2016-11-14 10:14:38

标签: python opencv color-space scikit-image

我正在尝试提取32位RGB图像的LAB a通道。但是我无法正确读取图像,我得到了意想不到的结果。

import cv2
org = cv2.imread('42.png', -1)
print org.dtype
# print uint8
lab_image = cv2.cvtColor(org, cv2.COLOR_RGB2LAB)
l,a,b = cv2.split(lab_image)
cv2.imshow('', a)
cv2.waitKey(0)

原始图片: http://labtools.ipk-gatersleben.de/images/42.png

预期输出(ImageJ): http://labtools.ipk-gatersleben.de/images/imagej_out.png

OpenCV输出: http://labtools.ipk-gatersleben.de/images/python_out.png

我也尝试用skimage读取/转换图像,但结果是一样的......

1 个答案:

答案 0 :(得分:2)

您的代码有几个问题。首先,正如Miki正确指出的那样,你必须交换红色和蓝色通道。根据{{​​3}}(强调我的):

  

请注意,OpenCV中的默认颜色格式通常称为RGB,但实际上是BGR (字节反转)

然后您需要将图像投射到float32(因为float64不支持cv2.cvtColor)并将其缩小以适应0..1范围:

  

在线性变换的情况下,范围无关紧要。但是在非线性变换的情况下,应将输入RGB图像标准化为适当的值范围以获得正确的结果,例如,对于RGB→Lu * v * 转换。例如,如果您有一个直接从8位图像转换而没有任何缩放的32位浮点图像,那么它将具有0..255值范围而不是函数假定的0..1 即可。因此,在致电cvtColor之前,首先需要缩小图片

a返回的cv2.cvtColor的值被限制为OpenCV documentation。为了改进可视化,通过从a.min()中减去a来拉伸对比度并将结果值重新调整为255./(a.max() - a.min())因子以适应0..255的范围是很有用的。如果这样做,您应该获得预期的结果。这是完整的代码:

import cv2
import numpy as np
org = np.float32(cv2.imread('42.png', -1))/255.
lab_image = cv2.cvtColor(org, cv2.COLOR_BGR2LAB)
l, a, b = cv2.split(lab_image)
a_scaled = np.uint8(255.*(a - a.min())/(a.max() - a.min()))
cv2.imshow('', a_scaled)
cv2.waitKey(0)

加成

您可以使用scikit-image获得相同的结果:

from skimage import io, color
import matplotlib.pyplot as plt

org = io.imread('http://labtools.ipk-gatersleben.de/images/42.png')
lab_image = color.rgb2lab(org)
a = lab_image[:, :, 1]

fig, ax = plt.subplots(1, 1)
plt.set_cmap('gray')
ax.imshow(a)

-127 <= a <= 127

†实际上,OpenCV和scikit-image产生的结果并不完全相同。由于与浮点算法相关的数值错误,存在细微差别。这种差异源于cv2.cvtColor返回 float32 的三个2D数组,而skimage.color.rgb2lab产生 float64 的3D数组。