当使用 OpenCV 完成图像加载和调整大小时,Resnet50 会产生不同的预测

Joe*_*Joe 8 python opencv machine-learning keras tensorflow

我想使用使用 OpenCV 的 Keras Resnet50 模型来读取和调整输入图像的大小。我正在使用来自 Keras 的相同预处理代码(使用 OpenCV,我需要转换为 RGB,因为这是 preprocess_input() 期望的格式)。我使用 OpenCV 和 Keras 图像加载得到的预测略有不同。我不明白为什么预测不一样。

这是我的代码:

import numpy as np
import json
from tensorflow.keras.applications.resnet50 import ResNet50
from tensorflow.keras.preprocessing import image
from tensorflow.keras.applications.resnet50 import preprocess_input, decode_predictions
import cv2

model = ResNet50(weights='imagenet')

img_path = '/home/me/squirle.jpg'

# Keras prediction
img = image.load_img(img_path, target_size=(224, 224))
x = image.img_to_array(img)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
preds = model.predict(x)
print('Predicted Keras:', decode_predictions(preds, top=3)[0])

# OpenCV prediction
imgcv = cv2.imread(img_path)
dim = (224, 224)
imgcv_resized = cv2.resize(imgcv, dim, interpolation=cv2.INTER_LINEAR)
x = cv2.cvtColor(imgcv_resized , cv2.COLOR_BGR2RGB)
x = np.expand_dims(x, axis=0)
x = preprocess_input(x)
preds = model.predict(x)
print('Predicted OpenCV:', decode_predictions(preds, top=3)[0])

Predicted Keras: [('n02490219', 'marmoset', 0.28250763), ('n02356798', 'fox_squirrel', 0.25657368), ('n02494079', 'squirrel_monkey', 0.19992349)]
Predicted OpenCV: [('n02356798', 'fox_squirrel', 0.5161952), ('n02490219', 'marmoset', 0.21953616), ('n02494079', 'squirrel_monkey', 0.1160824)]

Run Code Online (Sandbox Code Playgroud)

如何使用 OpenCVimread()resize()获得与 Keras 图像加载相同的预测?

Tim*_*lin 6

# Keras prediction
img = image.load_img(img_path, target_size=(224, 224))

   # OpenCV prediction
imgcv = cv2.imread(img_path)
dim = (224, 224)
imgcv_resized = cv2.resize(imgcv, dim, interpolation=cv2.INTER_LINEAR)
Run Code Online (Sandbox Code Playgroud)
  1. 如果仔细看,你在 cv2 的情况下指定的插值是cv2.INTER_LINEAR(双线性插值);但是,默认情况下, image.load_img()使用INTER_NEAREST插值方法。

  2. img_to_array(img). dtype这里的论点是:无

默认为 None,在这种情况下使用全局设置 tf.keras.backend.floatx() (除非你改变它,它默认为“float32”)

因此,img_to_array(img)您有一个由float32值组成的图像,而cv2.imread(img)返回一个 numpyuint8值数组。

  1. 确保从 BGR 转换为 RGB,因为 OpenCV 直接加载为 BGR 格式。您可以使用image = image[:,:,::-1]image = cv2.cvtColor(image,cv2.COLOR_BGR2RGB); 否则,您将颠倒 R 和 B 通道,从而导致不正确的比较。

由于您应用的预处理在两种情况下都是相同的,唯一的区别是我上面提到的那些;调整这些变化应确保可重复性。

我想做出一个观察:假设一个库(cv2在这种情况下)自动(并且可以说只加载整数)而不是浮点数,唯一正确的方法是将第一个预测数组(Keras)转换为,uint8因为通过将后者强制转换为float32,信息中可能存在的差异将丢失。例如,当cv2您加载到uint8,并通过强制转换而不是233获取233.0. 然而,也许初始像素值是233,3但由于第一次转换而丢失了。