簡體   English   中英

如何將圖像的像素值歸一化為 0~1?

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

我的train_data的類型是“ Array of unit 16 ”。 大小為(96108,7,7) 因此,有 96108 張圖像。

該圖像與一般圖像不同。 我的圖像有一個 7x7 的傳感器,49 個像素包含檢測到的光的數量。 一張圖像是0到1秒檢測到的光的數量。 由於傳感器在單位時間內隨機檢測,因此像素的最大值都不同。

如果所有圖像的最大值都是 255,我可以做“train data/255”,但我不能使用除法,因為我擁有的圖像的最大值都是不同的。 我想讓所有圖片的像素值都變成0到1,怎么辦?

對比度歸一化(或對比度拉伸)不應與將數據映射到 0.0-1.0 之間的數據歸一化相混淆。


數據規范化

我們使用以下公式對數據進行歸一化。 min()max()值是數據類型支持的可能的最小值和最大值。

在此處輸入圖像描述

當我們將它用於圖像時, x是整個圖像, i是該圖像的單個像素。 如果您使用的是 8 位圖像,則min()max()值分別變為 0 和 255。 這不應與相關圖像中顯示的最小值和最大值相混淆。

要將 8 位圖像轉換為浮點圖像,當 min() 值達到 0 時,簡單的數學運算是image/255。

img = img/255

NumPy 方法默認類似於 output arrays 的 64 位浮點數。 為了有效地測試應用於 NumPy 的 8 位圖像的方法,需要一個 8 位數組作為輸入:

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

當我們檢查上面兩行的 output 時,我們可以看到圖像的最大值是 252,現在已經映射到 64 位歸一化圖像上的 0.9882352941176471。

在此處輸入圖像描述

但是,在大多數情況下,您不需要 64 位圖像。 您可以使用以下代碼將 output(或換句話說轉換)為 32 位(或 16 位)。 如果您嘗試將其轉換為 8 位,則會引發錯誤。 使用 '/' 作為除法是np.true_divide的簡寫,但無法定義 output 數據格式。

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

新數組的屬性如下所示。 您可以看到位數現在減少了,252 現在已重新映射為 0.9882353。

在此處輸入圖像描述

對比度歸一化

@3dSpatialUser 展示的方法有效地進行了部分對比度歸一化,這意味着它在可用強度范圍內拉伸圖像的強度。 使用以下代碼使用 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())

對比度現在被拉伸,最小對比度為 64 到 0.0,最大對比度為 127 到 1.0。

在此處輸入圖像描述

對比度歸一化的公式如下所示。

在此處輸入圖像描述

使用上面的公式和 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 現在映射到 0,174 映射到 255 拉伸對比度。

在此處輸入圖像描述

混亂發生的地方

在大多數應用中,圖像的強度值分布在它們的最小值和最大值附近。 因此,當我們使用圖像中出現的最小值和最大值而不是可用范圍的最小最大值應用歸一化公式時,它將 output 在 0.0-1.0 范圍內得到更好看的圖像(在大多數情況下),這有效地做到了同時標准化數據和對比度。 此外,在 8/16/32 位圖像數據類型之間切換時,圖像編輯軟件會進行伽瑪校正或重新映射。

您可以使用np.ndarray.max跨多個軸收集最大值:此處axis=1axis=2 (即分別在每個圖像上)。 然后用它規范化初始數組。 為了避免自己廣播這個最大值數組,您可以使用keepdims選項:

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

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

雖然x.max(axis=(1,2))單獨會返回一個數組形狀(96108,) ...

這樣你就可以做到:

>>> 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)

編輯:我投票支持另一個答案,因為這是一種更清潔的方式(在我看來),但原則是相同的。

編輯 v2:我看到了評論,我看到了不同之處。 我將重寫我的代碼,使其“更干凈”,額外變量更少,但使用 min/max 仍然正確:

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

首先將最小值移動到零,然后可以取最大值以獲得特定圖像的全范圍(max-min)。

在這一步之后np.array_equal(data, scaled_data) = True

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM