Как сопоставить 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