cvtColor()转换为LAB颜色空间后的Numpy 8和32位图像数据类型

时间:2017-09-17 12:20:59

标签: python opencv numpy image-processing colors

我想了解LAB如何在OpenCV中工作。以前在HSV打开帖子我在转换到LAB后正在玩数据类型并进行测试

LAB标准范围内的像素数据在亮度= 0-100,a * = -127到+127,b * = -127到+127。但我对openCV中显示的数据感到困惑。任何人都可以帮我检查我是否正在进行数据类型转换和缩放正确吗?

import cv2
import numpy as np

im = cv2.imread(r'G:\Checkerboardfordummies.png')
cv2.namedWindow('im', cv2.WINDOW_NORMAL)
cv2.imshow('im', im)
print(im)
print(im.dtype)

#Conversion from 8uint to float32 before cvtColor()
im = im.astype(np.float32)          #Cast Image data type        
im /= 255.                          #Scale value to float32 range 0-1
print(im)
print(im.dtype)
#Colour Space Conversion to LAB
im = cv2.cvtColor(im, cv2.COLOR_BGR2LAB)
cv2.namedWindow('Float32_Checkerboard', cv2.WINDOW_NORMAL)
cv2.imshow('Float32_Checkerboard', im)
cv2.imwrite('Float32_Checkerboard.png',im)

#Conversion from float32 to uint8
im = im*(255.)                #Scale value to uint8 range 0-255
im = im.astype(np.uint8)            #Cast Image data type
print(im)
print(im.dtype)
cv2.namedWindow('uint8_Checkerboard', cv2.WINDOW_NORMAL)
cv2.imshow('uint8_Checkerboard', im)
cv2.imwrite('uint8_Checkerboard.png',im)

测试图片:

enter image description here

转换测试结果

enter image description here

我不确定哪一种是在LAB中观察到的预期颜色? 8uint还是浮动32?我以为它应该显示相同的颜色?我的缩放可能有问题

这是打印出来的数据供参考:看起来缩小到8uint是错误的看值

>>> 

[[[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ..., 
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ..., 
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ..., 
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 ..., 
 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ..., 
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ..., 
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ..., 
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]]
uint8
[[[ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]
  ..., 
  [ 1.  1.  1.]
  [ 1.  1.  1.]
  [ 1.  1.  1.]]

 [[ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]
  ..., 
  [ 1.  1.  1.]
  [ 1.  1.  1.]
  [ 1.  1.  1.]]

 [[ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]
  ..., 
  [ 1.  1.  1.]
  [ 1.  1.  1.]
  [ 1.  1.  1.]]

 ..., 
 [[ 1.  1.  1.]
  [ 1.  1.  1.]
  [ 1.  1.  1.]
  ..., 
  [ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]]

 [[ 1.  1.  1.]
  [ 1.  1.  1.]
  [ 1.  1.  1.]
  ..., 
  [ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]]

 [[ 1.  1.  1.]
  [ 1.  1.  1.]
  [ 1.  1.  1.]
  ..., 
  [ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]]]
float32
[[[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ..., 
  [156   0   0]
  [156   0   0]
  [156   0   0]]

 [[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ..., 
  [156   0   0]
  [156   0   0]
  [156   0   0]]

 [[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ..., 
  [156   0   0]
  [156   0   0]
  [156   0   0]]

 ..., 
 [[156   0   0]
  [156   0   0]
  [156   0   0]
  ..., 
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]

 [[156   0   0]
  [156   0   0]
  [156   0   0]
  ..., 
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]

 [[156   0   0]
  [156   0   0]
  [156   0   0]
  ..., 
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]]
uint8
>>>

编辑:与Danmasek讨论后......设法在8位和32位正确显示图像

import cv2
import numpy as np

im = cv2.imread(r'G:\Checkerboardfordummies.png')
cv2.namedWindow('im', cv2.WINDOW_NORMAL)
cv2.imshow('im', im)
print(im)
print(im.dtype)

#Conversion from 8uint to float32 before cvtColor()
im = im.astype(np.float32)          #Cast Image data type        
im /= 255                        #Scale value to float32 range 0-1
print(im)
print(im.dtype)
#Colour Space Conversion to HSV
im = cv2.cvtColor(im, cv2.COLOR_BGR2LAB)
cv2.namedWindow('Float32_Checkerboard', cv2.WINDOW_NORMAL)
cv2.imshow('Float32_Checkerboard', im)
cv2.imwrite('Float32_Checkerboard.png',im)


#Conversion from float32 to uint8
im[:,:,0] = im[:,:,0]*(255./100)#Scale value to uint8 range 0-255
im[:,:,1] = (im[:,:,1] + 128)/255
im[:,:,2] = (im[:,:,2] + 128)/255

im = im.astype(np.uint8)            #Cast Image data type
print(im)
print(im.dtype)
cv2.namedWindow('uint8_Checkerboard', cv2.WINDOW_NORMAL)
cv2.imshow('uint8_Checkerboard', im)
cv2.imwrite('uint8_Checkerboard.png',im)

cv2.imwrite('uint8_Checkerboard.png',im)

得到了这个结果:

enter image description here

打印数据:从32位转换为8位....在缩放后,它仍然在L通道上打印255。非常奇怪

>>> 
[[[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ..., 
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ..., 
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 [[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ..., 
  [255 255 255]
  [255 255 255]
  [255 255 255]]

 ..., 
 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ..., 
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ..., 
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]

 [[255 255 255]
  [255 255 255]
  [255 255 255]
  ..., 
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]]
uint8
[[[ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]
  ..., 
  [ 1.  1.  1.]
  [ 1.  1.  1.]
  [ 1.  1.  1.]]

 [[ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]
  ..., 
  [ 1.  1.  1.]
  [ 1.  1.  1.]
  [ 1.  1.  1.]]

 [[ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]
  ..., 
  [ 1.  1.  1.]
  [ 1.  1.  1.]
  [ 1.  1.  1.]]

 ..., 
 [[ 1.  1.  1.]
  [ 1.  1.  1.]
  [ 1.  1.  1.]
  ..., 
  [ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]]

 [[ 1.  1.  1.]
  [ 1.  1.  1.]
  [ 1.  1.  1.]
  ..., 
  [ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]]

 [[ 1.  1.  1.]
  [ 1.  1.  1.]
  [ 1.  1.  1.]
  ..., 
  [ 0.  0.  0.]
  [ 0.  0.  0.]
  [ 0.  0.  0.]]]
float32
[[[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ..., 
  [255   0   0]
  [255   0   0]
  [255   0   0]]

 [[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ..., 
  [255   0   0]
  [255   0   0]
  [255   0   0]]

 [[  0   0   0]
  [  0   0   0]
  [  0   0   0]
  ..., 
  [255   0   0]
  [255   0   0]
  [255   0   0]]

 ..., 
 [[255   0   0]
  [255   0   0]
  [255   0   0]
  ..., 
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]

 [[255   0   0]
  [255   0   0]
  [255   0   0]
  ..., 
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]

 [[255   0   0]
  [255   0   0]
  [255   0   0]
  ..., 
  [  0   0   0]
  [  0   0   0]
  [  0   0   0]]]
uint8
>>>

1 个答案:

答案 0 :(得分:2)

你只有2种不同的颜色,所以让我们简化它,只使用2像素的图像,并消除成千上万的冗余像素,只会使行为更难以观察。

因此,我们可以简化这个在线人员的整个过程:

cv2.cvtColor(np.array([[[0,0,0],[1,1,1]]], dtype=np.float32), cv2.COLOR_BGR2LAB)

返回

 array([[[   0.,    0.,    0.],
    [ 100.,    0.,    0.]]], dtype=float32)

好吧,看看第二个像素。

此时,让我们咨询the documentation进行这种颜色转换。

  

输出0≤L≤100,-127≤a≤127,-127≤b≤127。然后将值转换为目标数据类型:

     
      
  • 8位图像:L←L * 255/100,a←a + 128,b←b + 128
  •   
  • 16位图像:(目前不支持)
  •   
  • 32位图像:L,a和b按原样保留
  •   

我们有一个32位图像,因此值“保持原样”(即在0≤L≤100, −127≤a≤127, −127≤b≤127范围内)

因此,将结果乘以255并将其转换为8位无符号整数将导致由于溢出而产生无意义。

  

但是我应该如何缩放并在LAB颜色空间中从float32转换回8bits而不会出现溢出。

应用一些基本数学(引用文献暗示):L←L∗255/100,a←a+128,b←b+128

float_img = cv2.cvtColor(np.array([[[0,0,0],[1,1,1]]], dtype=np.float32), cv2.COLOR_BGR2LAB)
# Channel L
float_img[:,:,0] = float_img[:,:,0] * (255.0/100.0)
# Channels a and b
float_img[:,:,1:] = float_img[:,:,1:] + 128

result = np.uint8(float_img)

result正在

array([[[  0, 128, 128],
        [255, 128, 128]]], dtype=uint8)

进行比较:

>>> cv2.cvtColor(np.array([[[0,0,0],[255,255,255]]], dtype=np.uint8), cv2.COLOR_BGR2LAB)
array([[[  0, 128, 128],
        [255, 128, 128]]], dtype=uint8)