如何将一个 np.uint16 格式的图像转换为 np.uint8 格式?

30

我正在创建一张图片:

image = np.empty(shape=(height, width, 1), dtype = np.uint16)

之后我将图片转换为BGR模式:

image = cv2.cvtColor(image, cv2.COLOR_GRAY2BGR)

我希望将图像转换为 dtype = np.uint8,以便将该图像与 cv2.threshold() 函数一起使用。我的意思是,我想将图像转换为 CV_8UC1

3个回答

38
你可以使用cv2.convertScaleAbs来解决这个问题。请查看文档。 请查看下面的命令行演示:
>>> img = np.empty((100,100,1),dtype = np.uint16)
>>> image = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)

>>> cvuint8 = cv2.convertScaleAbs(image)

>>> cvuint8.dtype
dtype('uint8')
希望能帮到你!!!

14

我建议你使用这个:

outputImg8U = cv2.convertScaleAbs(inputImg16U, alpha=(255.0/65535.0))

这将输出一个uint8图像,并根据它们在0-65535之间的先前值,分配介于0-255之间的值。

exemple :
pixel with value == 65535 will output with value 255 
pixel with value == 1300 will output with value 5 etc...

4

我猜你想将 uint16 范围的 0..65535 转换为 uint8 范围的 0..255。换句话说,图像在视觉上看起来是一样的,只是颜色深度更低。

np_uint16 = np.arange(2 ** 16, dtype=np.uint16).reshape(256, 256)
np_uint8 = (np_int16 // 256).astype(np.uint8)

生成映射:
[0..255] => 0 (256 values)
[256..511] => 1 (256 values)
... 
[65280..65535] => 255 (256 values)

为什么另外两个答案是不正确的:

被接受的答案

img = np.empty((100,100,1), dtype = np.uint16)
image = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
cvuint8 = cv2.convertScaleAbs(image)

^将创建一个未初始化的uint16数组,然后将其转换为uint8,使用abs()函数并将值剪切至255以外的值裁剪为255。得到的映射如下:

[0..254] => [0..254]
[255..65535] => 255

下一个:
outputImg8U = cv2.convertScaleAbs(inputImg16U, alpha=(255.0/65535.0))

^ 会产生略微错误的映射:

[0..128] => 0 (129 values)
[129..385] => 1 (257 values)
...
[65407..65535] => 255 (129 values)

因此,2、...、254个箱子在0处得到一个额外的值,而255则要承担费用。 使用convertScaleAbs进行精确映射有些棘手,因为它使用四舍五入向下取整

np_int16 = np.arange(2 ** 16, dtype=np.uint16).reshape(256, 256)
np_uint8 = cv2.convertScaleAbs(np_int16, alpha = 1./256., beta=-.49999)

提示:如果您关心性能,OpenCV版本在我的Mac电脑上比Numpy快约50%。


1
很有见地 +1。使用cv2.normalize怎么样? - Jeru Luke
1
@JeruLuke 谢谢!normalize会拉伸你的强度,从而在视觉上改变图像。如果这是目标 - 是的(即您有一个在最小-最大归一化数据集上训练的模型)。 - apatsekin
np.empty 是一个占位符,不需要任何注释。但是截断/环绕需要注意。 - Christoph Rackwitz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接