Как сопоставить cv2.imread с выходом keras image.img_load

Я изучаю глубокое обучение. Создал алгоритм классификации изображений. Однако проблема заключается в том, что для обучения изображений я использовал:

test_image = image.load_img('some.png', target_size = (64, 64))
test_image = image.img_to_array(test_image)

Хотя для фактического применения я использую:

test_image = cv2.imread('trick.png')
test_image = cv2.resize(test_image, (64, 64))

Но я обнаружил, что они дают разные ndarray (разные данные):

Последние записи от load_image:

  [ 64.  71.  66.]
  [ 64.  71.  66.]
  [ 62.  69.  67.]]]

Последние записи cv2.imread:

  [ 15  23  27]
  [ 16  24  28]
  [ 14  24  28]]]

поэтому система не работает. Есть ли способ сопоставить результаты друг с другом?

Ответ 1

OpenCV считывает изображения в формате BGR, тогда как в keras он представлен в RGB. Чтобы версия OpenCV соответствовала ожидаемому заказу (RGB), просто измените каналы:

test_image = cv2.imread('trick.png')
test_image = cv2.resize(test_image, (64, 64))
test_image = test_image[...,::-1] # Added

Последняя строка меняет направление каналов в порядке RGB. Затем вы можете подать это в свою модель keras.

Еще один момент, который я хотел бы добавить, это то, что cv2.imread обычно читает изображения с точностью uint8. Изучая вывод загруженного изображения keras, вы можете видеть, что данные находятся в точности с плавающей точкой, поэтому вы также можете конвертировать в представление с плавающей запятой, например float32:

import numpy as np
# ...
# ...
test_image = test_image[...,::-1].astype(np.float32)

В качестве конечной точки, в зависимости от того, как вы обучили вашу модель, обычно принято нормализовать значения пикселей изображения в диапазоне [0,1]. Если вы сделали это с помощью своей модели keras, убедитесь, что вы разделили свои значения на 255 на вашем изображении, прочитав через OpenCV:

import numpy as np
# ...
# ...
test_image = (test_image[...,::-1].astype(np.float32)) / 255.0

Ответ 2

Помимо CV2, использующего формат BGR и Keras (используя PIL в качестве бэкэнд) с использованием формата RGB, также существуют значительные различия в методах изменения размера CV2 и PIL с использованием тех же параметров.

Несколько ссылок можно найти в Интернете, но общая идея заключается в том, что в пиксельных системах координат, используемых в двух алгоритмах изменения размера, есть тонкие различия, а также возможные проблемы с различными методами литья для плавания в качестве промежуточного шага в алгоритме интерполяции. Конечным результатом является визуально похожий образ, но тот, который слегка смещен/возмущен между версиями.

Прекрасный пример состязательной атаки, которая может вызвать огромные различия в точности, несмотря на небольшие различия в исходных данных.

Ответ 3

Недавно я столкнулся с той же проблемой. Я попытался преобразовать цветной канал и изменить размер изображения с помощью OpenCV. Тем не менее, PIL и OpenCV имеют очень разные способы изменения размера изображения. Вот точное решение этой проблемы.

Эта функция берет путь к файлу изображения, преобразует его в целевой размер и подготавливает для модели Keras -

import cv2
import keras
import numpy as np
from keras.preprocessing import image
from PIL import Image

def prepare_image (file):
    im_resized = image.load_img(file, target_size = (224,224))
    img_array = image.img_to_array(im_resized)
    image_array_expanded = np.expand_dims(img_array, axis = 0)
    return keras.applications.mobilenet.preprocess_input(image_array_expanded)

# execute the function
PIL_image = prepare_image ("lena.png")

Если у вас есть изображение OpenCV, функция будет выглядеть следующим образом -

def prepare_image2 (img):
    # convert the color from BGR to RGB then convert to PIL array
    cvt_image =  cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    im_pil = Image.fromarray(cvt_image)

    # resize the array (image) then PIL image
    im_resized = im_pil.resize((224, 224))
    img_array = image.img_to_array(im_resized)
    image_array_expanded = np.expand_dims(img_array, axis = 0)
    return keras.applications.mobilenet.preprocess_input(image_array_expanded)

# execute the function
img = cv2.imread("lena.png")
cv2_image = prepare_image2 (img)

# finally check if it is working  
np.array_equal(PIL_image, cv2_image)
>> True