将float64类型的np.array转换为类型uint8缩放值

dec*_*nza 19 python numpy image

我有一个特定的np.array 数据,它代表一个特定的灰度图像.我需要使用SimpleBlobDetector(),遗憾的是只接受8位图像,所以我需要转换这个图像,显然有质量损失.

我已经尝试过了:

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)
Run Code Online (Sandbox Code Playgroud)

但是cv2.imshow没有像预期的那样给出图像,但是有着奇怪的失真......

最后,我只需要将np.float64转换为np.uint8,缩放所有值并截断其余值,例如.65535变为255,65534变为254等等....任何帮助?

谢谢.

ray*_*ica 33

标准化图像的更好方法是获取每个值并除以数据类型所经历的最大值.这样可以确保图像中动态范围较小的图像保持较小,并且不会无意中将其标准化,使其变为灰色.例如,如果您的图像具有动态范围[0-2],则现在的代码会将其缩放为具有强度[0, 128, 255].你希望这些在转换后保持小np.uint8.

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

因此,使用上述内容,请对您的代码进行以下修改:

import numpy as np
import cv2
[...]
info = np.info(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)
Run Code Online (Sandbox Code Playgroud)

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

  • 我看到 astype 无处不在的一个小评论。“你永远不应该在图像上使用 astype,因为它违反了关于 dtype 范围的这些假设”。来自 http://scikit-image.org/docs/dev/user_guide/data_types.html (2认同)
  • @rayryeng 对我来说`np.iinfo(data.dtype)` 给出了这个错误:`ValueError: Invalid integer data type.`。`data` 只是一个 float64 numpy 数组,对吗? (2认同)
  • @holastello `data` 在转换之前需要是整数类型。如果它已经是浮点数组,则此方法将不起作用。 (2认同)

Vas*_*kyi 15

考虑到您使用的是 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 中执行此操作

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
Run Code Online (Sandbox Code Playgroud)

然后像这样使用它

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

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


小智 10

你可以使用skimage.img_as_ubyte(yourdata)它会让你的 numpy 数组范围从 0->255

from skimage import img_as_ubyte

img = img_as_ubyte(data)
cv2.imshow("Window", img)
Run Code Online (Sandbox Code Playgroud)

  • 产生 ```float 类型的图像必须在 -1 和 1 之间``` (3认同)