简体   繁体   English

如何将图像的像素值归一化为 0~1?

[英]How do I normalize the pixel value of an image to 0~1?

The type of my train_data is ' Array of unit 16 '.我的train_data的类型是“ Array of unit 16 ”。 The size is (96108,7,7) .大小为(96108,7,7) Therefore, there are 96108 images.因此,有 96108 张图像。

The image is different from the general image.该图像与一般图像不同。 My image has a sensor of 7x7 and 49 pixels contain the number of detected lights.我的图像有一个 7x7 的传感器,49 个像素包含检测到的光的数量。 And one image is the number of light detected for 0 to 1 second.一张图像是0到1秒检测到的光的数量。 Since the sensor detects randomly for a unit time, the maximum values of the pixel are all different.由于传感器在单位时间内随机检测,因此像素的最大值都不同。

If the max value of all images is 255, I can do 'train data/255', but I can't use the division because the max value of the image I have is all different.如果所有图像的最大值都是 255,我可以做“train data/255”,但我不能使用除法,因为我拥有的图像的最大值都是不同的。 I want to make the pixel value of all images 0 to 1. What should I do?我想让所有图片的像素值都变成0到1,怎么办?

Contrast Normalization (or contrast stretch) should not be confused with Data Normalization which maps data between 0.0-1.0.对比度归一化(或对比度拉伸)不应与将数据映射到 0.0-1.0 之间的数据归一化相混淆。


Data Normalization数据规范化

We use the following formula to normalize data.我们使用以下公式对数据进行归一化。 The min() and max() values are the possible minimum and maximum values supported within the type of data. min()max()值是数据类型支持的可能的最小值和最大值。

在此处输入图像描述

When we use it with images, x is the whole image and i is an individual pixel of that image.当我们将它用于图像时, x是整个图像, i是该图像的单个像素。 If you are using an 8-bit image the min() and max() values become 0 and 255 respectively.如果您使用的是 8 位图像,则min()max()值分别变为 0 和 255。 This should not be confused with the minimum and maximum values presented within your image in question.这不应与相关图像中显示的最小值和最大值相混淆。

To convert an 8-bit image into a floating-point image, As min() value reaches 0, the simple math is image/255.要将 8 位图像转换为浮点图像,当 min() 值达到 0 时,简单的数学运算是image/255。

img = img/255

NumPy methods likes to output arrays in 64-bit floating-point by default. NumPy 方法默认类似于 output arrays 的 64 位浮点数。 To effectively test methods applied to 8-bit images with NumPy, an 8-bit array is required as the input:为了有效地测试应用于 NumPy 的 8 位图像的方法,需要一个 8 位数组作为输入:

image = np.random.randint(0,255, (7,7),  dtype=np.uint8)
normalized_image = image/255

When we examine the output of the above two lines we can see the maximum value of the image is 252 which has now mapped to 0.9882352941176471 on the 64-bit normalized image.当我们检查上面两行的 output 时,我们可以看到图像的最大值是 252,现在已经映射到 64 位归一化图像上的 0.9882352941176471。

在此处输入图像描述

However, in most cases, you wouldn't need a 64-bit image.但是,在大多数情况下,您不需要 64 位图像。 You can output (or in other words cast) it to 32-bit (or 16-bit) using the following code.您可以使用以下代码将 output(或换句话说转换)为 32 位(或 16 位)。 If you try to cast it to 8-bit it will throw an error.如果您尝试将其转换为 8 位,则会引发错误。 Using '/' for division is a shorthand for np.true_divide but lacks the ability to define the output data format.使用 '/' 作为除法是np.true_divide的简写,但无法定义 output 数据格式。

normalized_image_2 = np.true_divide(image, 255, dtype=np.float32)

The properties of the new array is shown below.新数组的属性如下所示。 You can see the number of digits is now reduced and 252 has now been remapped to 0.9882353.您可以看到位数现在减少了,252 现在已重新映射为 0.9882353。

在此处输入图像描述

Contrast Normalization对比度归一化

The method shown by @3dSpatialUser effectively does a partial contrast normalization, meaning it stretches the intensities of the image within the available intensity range. @3dSpatialUser 展示的方法有效地进行了部分对比度归一化,这意味着它在可用强度范围内拉伸图像的强度。 Test it with an 8-bit array with the following code.使用以下代码使用 8 位数组对其进行测试。

c_image = np.random.randint(64,128, (7,7),  dtype=np.uint8)
cn_image = (c_image - c_image.min()) / (c_image.max()- c_image.min())

Contrast is now stretched mapping minimum contrast of 64 to 0.0 and maximum 127 to 1.0.对比度现在被拉伸,最小对比度为 64 到 0.0,最大对比度为 127 到 1.0。

在此处输入图像描述

The formula for contrast normalization is shown below.对比度归一化的公式如下所示。

在此处输入图像描述

Using the above formula with NumPy and to remap data back to the 8-bit input format after contrast normalization, the image should be multiplied by 255, then change the data type back to unit8:使用上面的公式和 NumPy 并在对比度归一化后将数据重新映射回 8 位输入格式,图像应乘以 255,然后将数据类型更改回 unit8:

cn_image_correct = (c_image - c_image.min()) / (c_image.max()- c_image.min()) * 255
cn_image_correct = cn_image_correct.astype(np.int8)

64 is now mapped to 0 and 174 is mapped to 255 stretching the contrast. 64 现在映射到 0,174 映射到 255 拉伸对比度。

在此处输入图像描述

Where the confusion arise混乱发生的地方

In most applications, the intensity values of an image are spread close to their minima and maxima.在大多数应用中,图像的强度值分布在它们的最小值和最大值附近。 Hence when we apply the normalization formula using the min and max values presented within the image, instead of the min max of the available range, it will output a better looking image (in most cases) within the 0.0-1.0 range, which effectively does normalize both data and contrast at the same time.因此,当我们使用图像中出现的最小值和最大值而不是可用范围的最小最大值应用归一化公式时,它将 output 在 0.0-1.0 范围内得到更好看的图像(在大多数情况下),这有效地做到了同时标准化数据和对比度。 Also, image editing software does gamma corrections or remapping when switching between image data types 8/16/32-bits.此外,在 8/16/32 位图像数据类型之间切换时,图像编辑软件会进行伽玛校正或重新映射。

You can gather the maximum values with np.ndarray.max across multiple axes: here axis=1 and axis=2 (ie on each image individually).您可以使用np.ndarray.max跨多个轴收集最大值:此处axis=1axis=2 (即分别在每个图像上)。 Then normalize the initial array with it.然后用它规范化初始数组。 To avoid having to broadcast this array of maxima yourself, you can use the keepdims option:为了避免自己广播这个最大值数组,您可以使用keepdims选项:

>>> x = np.random.rand(96108,7,7)

>>> x.max(axis=(1,2), keepdims=True).shape
(96108, 1, 1)

While x.max(axis=(1,2)) alone would have returned an array shaped (96108,) ...虽然x.max(axis=(1,2))单独会返回一个数组形状(96108,) ...

Such that you can then do:这样你就可以做到:

>>> x /= x.max(axis=(1,2), keepdims=True)
import numpy as np

data = np.random.normal(loc=0, scale=1, size=(96108, 7, 7))
data_min = np.min(data, axis=(1,2), keepdims=True)
data_max = np.max(data, axis=(1,2), keepdims=True)

scaled_data = (data - data_min) / (data_max - data_min)

EDIT: I have voted for the other answer since that is a cleaner way (in my opinion) to do it, but the principles are the same.编辑:我投票支持另一个答案,因为这是一种更清洁的方式(在我看来),但原则是相同的。

EDIT v2: I saw the comment and I see the difference.编辑 v2:我看到了评论,我看到了不同之处。 I will rewrite my code so it is "cleaner" with less extra variables but still correct using min/max:我将重写我的代码,使其“更干净”,额外变量更少,但使用 min/max 仍然正确:

data -= data.min(axis=(1,2), keepdims=True)
data /= data.max(axis=(1,2), keepdims=True)

First the minimum value is moved to zero, thereafter one can take the maximum value to get the full range (max-min) of the specific image.首先将最小值移动到零,然后可以取最大值以获得特定图像的全范围(max-min)。

After this step np.array_equal(data, scaled_data) = True .在这一步之后np.array_equal(data, scaled_data) = True

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM