关于python:将float64类型的np.array转换为uint8缩放值

Convert np.array of type float64 to type uint8 scaling values

我有代表特定灰度图像的特定np.array数据。
我需要使用SimpleBlobDetector(),不幸的是,该SimpleBlobDetector()仅接受8位图像,因此我需要转换此图像,显然会有质量损失。

我已经尝试过:

1
2
3
4
5
6
7
import numpy as np
import cv2
[...]
data = data / data.max() #normalizes data in range 0 - 255
data = 255 * data
img = data.astype(np.uint8)
cv2.imshow("Window", img)

但是cv2.imshow不能提供预期的图像,但是具有奇怪的失真...

最后,我只需要将np.float64转换为np.uint8即可缩放所有值,并截断其余所有值,例如。 65535变为255,65534变为254,依此类推。...有什么帮助吗?

谢谢。


对图像进行规范化的更好方法是采用每个值,然后除以数据类型所经历的最大值。这样可以确保图像中动态范围较小的图像保持较小,并且不会被意外归一化,从而变为灰色。例如,如果图像的动态范围为[0-2],则当前代码将对其进行缩放以使其强度为[0, 128, 255]。您希望它们在转换为np.uint8之后保持较小。

因此,将每个值除以图像类型可能的最大值,而不是实际图像本身。然后,您可以将其缩放255以产生归一化的结果。使用numpy.iinfo并为其提供图像的类型(dtype),您将获得该类型的信息结构。然后,您可以从此结构访问max字段以确定最大值。

因此,对上述代码进行以下修改:

1
2
3
4
5
6
7
8
import numpy as np
import cv2
[...]
info = np.iinfo(data.dtype) # Get the information of the incoming image type
data = data.astype(np.float64) / info.max # normalize the data to 0 - 1
data = 255 * data # Now scale by 255
img = data.astype(np.uint8)
cv2.imshow("Window", img)

请注意,如果输入的数据类型不是这样,我还将图像转换为np.float64,并在进行除法运算时保持浮点精度。


考虑到您正在使用OpenCV,在数据类型之间进行转换的最佳方法是使用normalize函数。

img_n = cv2.normalize(src=img, dst=None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)

但是,如果您不想使用OpenCV,则可以在numpy

中执行此操作

1
2
3
4
5
6
7
8
def convert(img, target_type_min, target_type_max, target_type):
    imin = img.min()
    imax = img.max()

    a = (target_type_max - target_type_min) / (imax - imin)
    b = target_type_max - a * imax
    new_img = (a * img + b).astype(target_type)
    return new_img

然后像这样使用它

imgu8 = convert(img16u, 0, 255, np.uint8)

这基于我在此解决方案下的评论中的交叉验证板上找到的答案https://stats.stackexchange.com/a/70808/277040


您可以使用skimage.img_as_ubyte(yourdata),它将使您的numpy数组范围从0-> 255

1
2
3
4
from skimage import img_as_ubyte

img = img_as_ubyte(data)
cv2.imshow("Window", img)