Tensorflow:如何打开PIL图像?

6

我有一个脚本,它会遮盖图片的一部分并通过预测网络运行它,以查看哪些部分最强烈地影响标签预测。为此,我使用PIL打开本地图像并调整大小,同时在各个间隔处添加黑色框。我使用Tensorflow打开我的模型,并想将图像传递给模型,但它不期望具有这种特定形状的值:

Traceback (most recent call last):
  File "obscureImage.py", line 55, in <module>
    originalPrediction, originalTag = predict(originalImage, labels)
  File "obscureImage.py", line 23, in predict
    {'DecodeJpeg/contents:0': image})
  File "C:\Users\User\AppData\Local\Programs\Python\Python35\lib\site-packages\tensorflow\python\client\session.py", line 766, in run
    run_metadata_ptr)
  File "C:\Users\User\AppData\Local\Programs\Python\Python35\lib\site-packages\tensorflow\python\client\session.py", line 943, in _run
    % (np_val.shape, subfeed_t.name, str(subfeed_t.get_shape())))
ValueError: Cannot feed value of shape (224, 224, 3) for Tensor 'DecodeJpeg/contents:0', which has shape '()'

这是我的代码:
def predict(image, labels):
    with tf.Session() as sess:
        #image_data = tf.gfile.FastGFile(image, 'rb').read() # What I used to use.

        softmax_tensor = sess.graph.get_tensor_by_name('final_result:0')
        predictions = sess.run(softmax_tensor,
                               {'DecodeJpeg/contents:0': image})
        predictions = np.squeeze(predictions)

        top_k = predictions.argsort()[-5:][::-1]  # Getting top 5 predictions

        return predictions[0], labels[top_k[0]] # Return the raw value of tag matching and the matching tag.

originalImage = Image.open(args.input).resize((args.imgsz,args.imgsz)).convert('RGB')
originalPrediction, originalTag = predict(originalImage, labels)

从磁盘打开并使用图像可以正常工作,但当然这不是我的修改后的图像。我尝试将 tf.image.decode_jpeg(image,0) 用作 softmax 张量的参数,但它会导致 TypeError: Expected string passed to parameter 'contents' of op 'DecodeJpeg', got <PIL.Image.Image image mode=RGB size=224x224 at 0x2592F883358> of type 'Image' instead.

5个回答

12
使用来自Keras的img_to_array函数:
import tensorflow as tf 
from PIL import Image
    
pil_img = Image.new(3, (200, 200))
image_array  = tf.keras.utils.img_to_array(pil_img)

1
tf.keras.preprocessing现已弃用。https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing。但是可以使用tf.keras.utils.img_to_array。 - Vladimir Visnovsky

3
“DecodeJpeg:0/contents:0”是一个旨在将base64字符串解码为原始图像数据的操作。您正在尝试提供原始图像数据。因此,您应该将其提供给“DecodeJpeg:0”的输出,该输出是“DecodeJpeg:0/contents:0”的输出,或者提供给图形的输入之一“Mul:0”。不要忘记调整大小,因为输入应该是(299,299,3)的形状。Mul接受(1,299,299,3)的输入。请按以下方式尝试:
image = Image.open("example.jepg")
image.resize((299,299), Image.ANTIALIAS)
image_array = np.array(image)[:, :, 0:3]  # Select RGB channels only.

prediction = sess.run(softmax_tensor, {'DecodeJpeg:0': image_array})
or
prediction = sess.run(softmax_tensor, {'Mul:0': [image_array]})

正如这个stackoverflow问题中所讨论的那样

为了更好地理解其操作:

 for i in sess.graph.get_operations():
            print (i.values())

希望这可以帮到您。

1

不确定为什么Maximilian的答案没有起作用,但这是对我有效的方法:

from io import BytesIO

def predict(image, labels, sess):
    imageBuf = BytesIO()
    image.save(imageBuf, format="JPEG")
    image = imageBuf.getvalue()

    softmax_tensor = sess.graph.get_tensor_by_name('final_result:0')
    predictions = sess.run(softmax_tensor,
                           {'DecodeJpeg/contents:0': image})
    predictions = np.squeeze(predictions)

    top_k = predictions.argsort()[-5:][::-1]  # Getting top 5 predictions

    return predictions[top_k[0]], labels[top_k[0]] # Return the raw value of tag matching and the matching tag.

我创建了一个字节缓冲区,将 PIL 图像保存在其中,获取其值并传递。我对 TensorFlow 和图像处理还很陌生,如果有人能给出具体原因为什么这样做有效而 Max 的方法则无效,那就会成为这个答案的好补充。

0

您可以使用PIL的getdata()

将图像内容作为包含像素值的序列对象返回。序列对象被压平,因此第一行的值直接跟在第零行的值后面,依此类推。

或者使用Tensorflow的gfile

from tensorflow.python.platform import gfile
image_data = gfile.FastGFile(image_filename, 'rb').read()

担心这两个都不起作用。将image.getdata()作为参数传递给sess.run会导致以下错误:ValueError: Cannot feed value of shape (50176, 3) for Tensor 'DecodeJpeg/contents:0', which has shape '()'。尝试使用image = tf.gfile.FastGFile(image,'rb').read()会导致TypeError: Expected binary or unicode string, got <PIL.Image.Image image mode=RGB size=224x224 at 0x28C3F772898>。对我来说,它期望一个形状为()的东西似乎有点奇怪... - IronWaffleMan
@IronWaffleMan:FastGFile期望一个文件名的字符串,而不是图像本身。我更新了问题以避免混淆。 - Maximilian Peters
我知道它会这样做,但我没有传递文件名。我正在传递一个我用PIL修改过的图像。 - IronWaffleMan

0

我已经尝试过这个方法,对我来说效果很好。你可以随意更改参数以调整你的解决方案。图像是作为输入的PIL图像。

def read_tensor_from_image(image, input_height=224, input_width=224,
            input_mean=0, input_std=255):

  float_caster = tf.cast(image, tf.float32)
  dims_expander = tf.expand_dims(float_caster, 0);
  resized = tf.image.resize_bilinear(dims_expander, [input_height, input_width])
  normalized = tf.divide(tf.subtract(resized, [input_mean]), [input_std])
  sess = tf.Session()
  result = sess.run(normalized)

  return result

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接