Python 将 float64 类型的 np.array 转换为 uint8 缩放值类型
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/46689428/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Convert np.array of type float64 to type uint8 scaling values
提问by decadenza
I have a particular np.array datawhich represents a particular grayscale image. I need to use SimpleBlobDetector() that unfortunately only accepts 8bit images, so I need to convert this image, obviously having a quality-loss.
我有一个特定的 np.array数据,它代表一个特定的灰度图像。我需要使用 SimpleBlobDetector() 不幸的是只接受 8 位图像,所以我需要转换这个图像,显然有质量损失。
I've already tried:
我已经试过了:
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)
But cv2.imshowis not giving the image as expected, but with strange distortion...
但是cv2.imshow并没有按预期给出图像,而是出现了奇怪的失真......
In the end, I only need to convert a np.float64 to np.uint8 scaling all the values and truncating the rest, eg. 65535 becomes 255, 65534 becomes 254 and so on.... Any help?
最后,我只需要将 np.float64 转换为 np.uint8 缩放所有值并截断其余值,例如。65535 变成 255,65534 变成 254 等等......有什么帮助吗?
Thanks.
谢谢。
回答by rayryeng
A better way to normalize your image is to take each value and divide by the largest value experienced by the data type. This ensures that images that have a small dynamic range in your image remain small and they're not inadvertently normalized so that they become gray. For example, if your image had a dynamic range of [0-2]
, the code right now would scale that to have intensities of [0, 128, 255]
. You want these to remain small after converting to np.uint8
.
标准化图像的更好方法是取每个值并除以数据类型所经历的最大值。这可确保图像中具有较小动态范围的图像保持较小,并且不会无意中将它们归一化,从而使它们变成灰色。例如,如果您的图像的动态范围为[0-2]
,则现在的代码会将其缩放为强度[0, 128, 255]
。您希望这些在转换为np.uint8
.
Therefore, divide every value by the largest value possible by the image type, not the actual image itself. You would then scale this by 255 to produced the normalized result. Use numpy.iinfo
and provide it the type (dtype
) of the image and you will obtain a structure of information for that type. You would then access the max
field from this structure to determine the maximum value.
因此,将每个值除以图像类型可能的最大值,而不是实际图像本身。然后将其缩放 255 以生成标准化结果。使用numpy.iinfo
并为其提供dtype
图像的类型 ( ),您将获得该类型的信息结构。然后您将从此max
结构访问该字段以确定最大值。
So with the above, do the following modifications to your code:
因此,根据上述内容,对您的代码进行以下修改:
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)
Note that I've additionally converted the image into np.float64
in case the incoming data type is not so and to maintain floating-point precision when doing the division.
请注意,np.float64
如果传入的数据类型不是这样,并在进行除法时保持浮点精度,我还额外将图像转换为。
回答by Vasyl Vaskivskyi
Considering that you are using OpenCV, the best way to convert between data types is to use normalize
function.
考虑到您使用的是 OpenCV,在数据类型之间进行转换的最佳方法是使用normalize
函数。
img_n = cv2.normalize(src=img, dst=None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
img_n = cv2.normalize(src=img, dst=None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
However, if you don't want to use OpenCV, you can do this in numpy
但是,如果您不想使用 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
And then use it like this
然后像这样使用它
imgu8 = convert(img16u, 0, 255, np.uint8)
imgu8 = convert(img16u, 0, 255, np.uint8)
This is based on the answer that I found on crossvalidated board in comments under this solution https://stats.stackexchange.com/a/70808/277040
这是基于我在此解决方案下的评论中在交叉验证板上找到的答案https://stats.stackexchange.com/a/70808/277040
回答by Ali Farouk
you can use skimage.img_as_ubyte(yourdata)
it will make you numpy array ranges from 0->255
你可以使用skimage.img_as_ubyte(yourdata)
它会让你的 numpy 数组范围从 0->255
from skimage import img_as_ubyte
img = img_as_ubyte(data)
cv2.imshow("Window", img)