Каким образом Tensorflow.keras ImageDataGenerator.flow_from_directory масштабирует значения изображения?

У меня есть обученная модель тензорного потока, и при создании обучающей базы данных я использовал

from tensorflow.keras.preprocessing.image import ImageDataGenerator
ImageDataGenerator.flow_from_directory(organized_dir,
                                       target_size=(image_dim, image_dim),
                                       color_mode="grayscale",
                                       batch_size=20,
                                       shuffle=True,
                                       follow_links=True)

(Я просто показываю параметры, которые я выбрал для предоставления, такие переменные, как image_dim, определены в другом месте)

Когда я смотрю на один из пакетов, использующий next() в объекте DirectoryIterator, который возвращает функция, значения пикселей изображения кажутся масштабированными от их исходных значений rgb [0,255] до оттенков серого [0,1]. Я хочу, чтобы он был в оттенках серого, и я так понимаю, что модели машинного обучения лучше всего работают с числами от 0 до 1. Так что это здорово!

Однако теперь я хочу использовать модель на разных изображениях. Открытие их в cv2 и преобразование в оттенки серого не масштабирует значения пикселей так же, как это делает тензорный поток, он просто сохраняет значения цвета в [0,255] вместо [0,1]:

>>> z = cv2.imread("img.png")
>>> cv2.cvtColor(z, cv2.COLOR_BGR2GRAY)
array([[255, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255],
       ...,
       [255, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255],
       [255, 255, 255, ..., 255, 255, 255]], dtype=uint8)

Итак, я спрашиваю, как мне использовать то же преобразование, которое использует набор данных tensorflow, чтобы изображение использовало значения пикселей от [0,255] до [0,1]. Я обнаружил, что могу нормализовать изображения: Нормализация изображений в OpenCV. Но я хотел бы использовать точный алгоритм / параметры, которые использует тензорный поток, чтобы я мог максимизировать свою точность в реальном мире. спасибо ????


person Arjun    schedule 14.02.2021    source источник


Ответы (2)


Вы ошиблись в том, что ImageDataGenerator изменяет масштаб значений пикселей изображения. Согласно документации в генераторе есть параметр rescale. Для этого параметра в документации указано:

rescale: rescaling factor. Defaults to None. If None or 0, no rescaling is applied,
 otherwise we multiply the data by the value provided
 (after applying all other transformations).

поэтому, чтобы изменить масштаб значений от 0 до 1, используйте

rescale=1/255

Многие модели, используемые в трансферном обучении, требуют, чтобы значения пикселей были от -1 до +1. В этом случае используйте

rescale=1/127.5-1

Возможно, у изображений, которые вы читали, уже были изменены значения пикселей. Чтобы проверить, масштабируется ли ваше изображение, используйте

import numpy as np
import cv2
path_to_file=        #specify the full path to the file
img=cv2.imread(path_to_file,0)# read in image as grayscale
max_pixel_value=np.max(img) #  find maximum pixel value
min_pixel_value=np.min(img) # find minimum pixel value
print('max pixel value= ', max_pixel_value, '  min pixel value= ', min_pixel_value)
person Gerry P    schedule 15.02.2021
comment
Это имеет смысл, но почему cv2 imread() дает значения пикселей от 0 до 255? - person Arjun; 15.02.2021
comment
Кроме того, есть ли способ проверить, были ли уже масштабированы значения пикселей? - person Arjun; 15.02.2021
comment
см. обновленный ответ. Я проверил, что генератор НЕ изменяет масштаб значений пикселей, если вы не укажете значение параметра rescale. - person Gerry P; 15.02.2021
comment
@Vladimir Kulyashov кажется правым, что cv2 читает их как dtype=uint8, хотя у вас есть правильный ответ на то, что я спросил. - person Arjun; 16.02.2021

cv2.imread () считывает изображения как np.array с типом данных uint8. Вот почему у вас есть все значения от 0 до 255. Чтобы изменить масштаб до [0, 1], просто разделите их на 255.

In[1]: import cv2
  ...: import numpy as np
In[2]: img = cv2.imread('some_image.jpg')
In[3]: img
Out[3]: 
array([[[110,  89,  92],
        [110,  89,  92],
        [ 50,  29,  32],
        ...

In[4]: type(img)
Out[4]: numpy.ndarray

In[5]: img.dtype
Out[5]: dtype('uint8')

In[6]: img = (img / 255)
In[7]: np.min(img), np.max(img)
Out[7]: (0.0, 1.0)

In[8]: img
Out[8]: 
array([[[0.43137255, 0.34901961, 0.36078431],
        [0.43137255, 0.34901961, 0.36078431],
        [0.19607843, 0.11372549, 0.1254902 ],
        ...

In[9]: img.dtype
Out[9]: dtype('float64')

Вот цитата из строки документации ImageDataGenerator:

rescale: коэффициент масштабирования. По умолчанию Нет. Если None или 0, масштабирование не применяется, в противном случае мы умножаем данные на предоставленное значение (после применения всех других преобразований).

Итак, ответ на ваш вопрос: просто умножьте свой массив на 1/255, и вы получите тот же результат, что и ImageDataGenerator.

person Vladimir Kulyashov    schedule 15.02.2021