将 RGB 图像转换为 LAB 图像时出现意外输出
Unexpected output while converting RGB image to LAB 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
我也试过 read/convert 用 skimage 的图像,但结果是一样的...
您的代码有几个问题。首先,正如 Miki 正确指出的那样,您必须交换红色和蓝色通道。根据 OpenCV documentation(强调我的):
Note that the default color format in OpenCV is often referred to as RGB but it is actually BGR (the bytes are reversed)
然后你需要将图像投射到float32
(因为float64
不被cv2.cvtColor
支持)并缩小它以适应0..1范围:
In case of linear transformations, the range does not matter. But in case of a non-linear transformation, an input RGB image should be normalized to the proper value range to get the correct results, for example, for RGB → Lu*v* transformation. For example, if you have a 32-bit floating-point image directly converted from an 8-bit image without any scaling, then it will have the 0..255 value range instead of 0..1 assumed by the function. So, before calling cvtColor
, you need first to scale the image down
cv2.cvtColor
返回的 a
的值被限制为 。为了改进可视化,通过从 a
中减去 a.min()
来拉伸对比度并将结果值重新缩放一个因子 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)
† 实际上,OpenCV 和 scikit-image 得出的结果并不完全相同。由于与浮点运算相关的数字错误,存在细微差异。这种差异源于 cv2.cvtColor
returns 三个 float32 的 2D 数组,而 skimage.color.rgb2lab
产生 float64[ 的 3D 数组=46=].
我正在尝试提取 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
我也试过 read/convert 用 skimage 的图像,但结果是一样的...
您的代码有几个问题。首先,正如 Miki 正确指出的那样,您必须交换红色和蓝色通道。根据 OpenCV documentation(强调我的):
Note that the default color format in OpenCV is often referred to as RGB but it is actually BGR (the bytes are reversed)
然后你需要将图像投射到float32
(因为float64
不被cv2.cvtColor
支持)并缩小它以适应0..1范围:
In case of linear transformations, the range does not matter. But in case of a non-linear transformation, an input RGB image should be normalized to the proper value range to get the correct results, for example, for RGB → Lu*v* transformation. For example, if you have a 32-bit floating-point image directly converted from an 8-bit image without any scaling, then it will have the 0..255 value range instead of 0..1 assumed by the function. So, before calling
cvtColor
, you need first to scale the image down
cv2.cvtColor
返回的 a
的值被限制为 a
中减去 a.min()
来拉伸对比度并将结果值重新缩放一个因子 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)
† 实际上,OpenCV 和 scikit-image 得出的结果并不完全相同。由于与浮点运算相关的数字错误,存在细微差异。这种差异源于 cv2.cvtColor
returns 三个 float32 的 2D 数组,而 skimage.color.rgb2lab
产生 float64[ 的 3D 数组=46=].