35

I've got a bunch of images in a format similar to Cifar10 (binary file, size = 96*96*3 bytes per image), one image after another (STL-10 dataset). The file I'm opening has 138MB.

I tried to read & check the contents of the Tensors containing the images to be sure that the reading is done right, however I have two questions -

  1. Does the FixedLengthRecordReader load the whole file, however just provide inputs one at a time? Since reading the first size bytes should be relatively fast. However, the code takes about two minutes to run.
  2. How to get the actual image contents in a displayable format, or display them internally to validate that the images are read well? I did sess.run(uint8image), however the result is empty.

The code is below:

import tensorflow as tf
def read_stl10(filename_queue):
  class STL10Record(object):
    pass
  result = STL10Record()

  result.height = 96
  result.width = 96
  result.depth = 3
  image_bytes = result.height * result.width * result.depth
  record_bytes = image_bytes

  reader = tf.FixedLengthRecordReader(record_bytes=record_bytes)
  result.key, value = reader.read(filename_queue)
  print value
  record_bytes = tf.decode_raw(value, tf.uint8)

  depth_major = tf.reshape(tf.slice(record_bytes, [0], [image_bytes]),
                       [result.depth, result.height, result.width])
  result.uint8image = tf.transpose(depth_major, [1, 2, 0])
  return result
# probably a hack since I should've provided a string tensor

filename_queue = tf.train.string_input_producer(['./data/train_X'])
image = read_stl10(filename_queue)

print image.uint8image
with tf.Session() as sess:
  result = sess.run(image.uint8image)
  print result, type(result)

Output:

Tensor("ReaderRead:1", shape=TensorShape([]), dtype=string)
Tensor("transpose:0", shape=TensorShape([Dimension(96), Dimension(96), Dimension(3)]), dtype=uint8)
I tensorflow/core/common_runtime/local_device.cc:25] Local device intra op parallelism threads: 4
I tensorflow/core/common_runtime/local_session.cc:45] Local session inter op parallelism threads: 4
[empty line for last print]
Process finished with exit code 137

I'm running this on my CPU, if that adds anything.

EDIT: I found the pure TensorFlow solution thanks to Rosa. Apparently, when using the string_input_producer, in order to see the results, you need to initialize the queue runners. The only required thing to add to the code above is the second line from below:

...
with tf.Session() as sess:
    tf.train.start_queue_runners(sess=sess)
...

Afterwards, the image in the result can be displayed with matplotlib.pyplot.imshow(result). I hope this helps someone. If you have any further questions, feel free to ask me or check the link in Rosa's answer.

mttk
  • 890
  • 2
  • 10
  • 11
  • It looks to me that you are reading just one image (based on the `[Dimension(96), Dimension(96), Dimension(3)]`) and not all of them. – Salvador Dali Nov 11 '15 at 10:17
  • That's what I wanted to do, read one image and display it, however I was not sure if TensorFlow still loads the whole file, since the reading takes a couple of minutes (and this seems like a relatively simple operation that should not take that long) – mttk Nov 11 '15 at 10:21
  • Is there a reason you do not want to read the file in numpy as 3d array and feed it into tensorFlow variable? – Salvador Dali Nov 11 '15 at 10:23
  • 2
    None other than using pure TensorFlow. Since it's supposed to parallelize reading, it seems useful to know. I can do it in numpy if all fails :) – mttk Nov 11 '15 at 10:31

8 Answers8

46

Just to give a complete answer:

filename_queue = tf.train.string_input_producer(['/Users/HANEL/Desktop/tf.png']) #  list of files to read

reader = tf.WholeFileReader()
key, value = reader.read(filename_queue)

my_img = tf.image.decode_png(value) # use png or jpg decoder based on your files.

init_op = tf.global_variables_initializer()
with tf.Session() as sess:
  sess.run(init_op)

  # Start populating the filename queue.

  coord = tf.train.Coordinator()
  threads = tf.train.start_queue_runners(coord=coord)

  for i in range(1): #length of your filename list
    image = my_img.eval() #here is your image Tensor :) 

  print(image.shape)
  Image.fromarray(np.asarray(image)).show()

  coord.request_stop()
  coord.join(threads)

Or if you have a directory of images you can add them all via this Github source file

@mttk and @salvador-dali: I hope it is what you need

Ibos
  • 72
  • 9
Hamed MP
  • 5,443
  • 3
  • 39
  • 37
  • 1
    Shouldn't everything after sess.run(init_op) also be indented by 2 spaces? I'm getting an: ValueError: Cannot evaluate tensor using eval(): No default session is registered. (for image = my_image.eval()) – NumesSanguis Dec 18 '15 at 12:38
  • @NumesSanguis Yes, You are right, I think it was problem when copy and pasting here. Did you tried indenting and see what's the result? – Hamed MP Dec 18 '15 at 13:18
  • Yes, we didn't have an error anymore, but nothing happened either. It might be that our image is not properly loaded, http://stackoverflow.com/questions/34356828/tensorflow-image-reading-empty. @Salvador Dali works though, however we want to make use of the reader object. – NumesSanguis Dec 18 '15 at 13:28
  • 1
    Actually I'm getting 2 errors: Image.show(), AttributeError: 'module' object has no attribute 'show' and I tensorflow/core/kernels/fifo_queue.cc:154] Skipping cancelled enqueue attempt – NumesSanguis Dec 18 '15 at 14:22
  • @NumesSanguis I'm concerned that this may be an issue with the code not having set the `capacity` arg for `string_input_producer`, which is important for setting the maximum length of the `FIFOQueue` returned from that method. I'm still playing around with it, but this could mean that you're dropping some input entries (though I'm uncertain). – GJStein Dec 23 '15 at 08:31
  • @HamedMP I tried to launch your code, but I have the following error: `ValueError: Cannot start queue runners: No default session is registered. Use "with sess.as_default()" or pass an explicit session to tf.start_queue_runners(sess=sess)` – Kyrol Apr 20 '16 at 15:48
  • @HamedMP I put session=sess here `image = my_img.eval(session=sess)` and now it works. – Kyrol Apr 20 '16 at 16:24
  • 1
    @GJStein I think you are correct. I was using this code to load around 10,000 images (a total size of only 10MB), but was getting erros like "Node not found" for some random images each time I ran the program. Also, the program takes more than 30 minutes to load those images. I wonder why. – goluhaque May 05 '16 at 01:40
  • I get name Image is not defined – Kong Jan 01 '17 at 17:45
  • Heads-up: if you want **deterministic** behaviour in the order of the images, pass **`shuffle=False`** as parameter to `tf.train.string_input_producer`. – Joppe Geluykens Aug 20 '17 at 11:37
  • 9
    Where is `Image.fromarray(np.asarray(image)).show()` coming from? – Soerendip Dec 16 '17 at 12:41
  • 1
    If it's PIL's Image, then it won't work with latest version of TensorFlow 0.1.15. Since that uses Python 3.6, which does not support PIL... :/ – poetyi Feb 20 '18 at 20:54
15

According to the documentation you can decode JPEG/PNG images.

It should be something like this:

import tensorflow as tf

filenames = ['/image_dir/img.jpg']
filename_queue = tf.train.string_input_producer(filenames)

reader = tf.WholeFileReader()
key, value = reader.read(filename_queue)

images = tf.image.decode_jpeg(value, channels=3)

You can find a bit more info here

Squanchy
  • 147
  • 1
  • 9
Rosa Gronchi
  • 1,828
  • 15
  • 25
11

After speaking with you in the comments, I believe that you can just do this using numpy/scipy. The ideas is to read the image in the numpy 3d-array and feed it into the variable.

from scipy import misc
import tensorflow as tf

img = misc.imread('01.png')
print img.shape    # (32, 32, 3)

img_tf = tf.Variable(img)
print img_tf.get_shape().as_list()  # [32, 32, 3]

Then you can run your graph:

init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)
im = sess.run(img_tf)

and verify that it is the same:

import matplotlib.pyplot as plt
fig = plt.figure()
fig.add_subplot(1,2,1)
plt.imshow(im)
fig.add_subplot(1,2,2)
plt.imshow(img)
plt.show()

enter image description here

P.S. you mentioned: Since it's supposed to parallelize reading, it seems useful to know.. To which I can say that rarely in data-analysis reading of the data is the bottleneck. Most of your time you will spend training your model.

Salvador Dali
  • 214,103
  • 147
  • 703
  • 753
  • 2
    Agreed for the data reading not being the bottleneck, however I know that there should be a way to do this via pure TensorFlow, so I wanted to know what was I missing. Other than that, thanks for your answer, it helped :) – mttk Nov 11 '15 at 12:08
  • Salvador the reason may we want pure TF solution is: As TF compile procedures and run them in it's own environment, it's better to do it all TF stuff to minimize the time to go back and forth between python and TF native computation stuff( C ). I'm not sue about but I think it makes a different. Do you agree? – Hamed MP Nov 16 '15 at 13:26
  • @HamedMP I would also like to see a TF solution and I also believe that it would be better. The problem is that I do not know how to do this in TF and therefore wrote the one I know. I also believe that the overhead will be small in comparison to time required by training a model. – Salvador Dali Nov 16 '15 at 19:13
  • @GayalKuruppu sure. Thx – Salvador Dali Apr 29 '20 at 09:04
3

Load names with tf.train.match_filenames_once get the number of files to iterate over with tf.size open session and enjoy ;-)

import tensorflow as tf
import numpy as np
import matplotlib;
from PIL import Image

matplotlib.use('Agg')
import matplotlib.pyplot as plt


filenames = tf.train.match_filenames_once('./images/*.jpg')
count_num_files = tf.size(filenames)
filename_queue = tf.train.string_input_producer(filenames)

reader=tf.WholeFileReader()
key,value=reader.read(filename_queue)
img = tf.image.decode_jpeg(value)

init = tf.global_variables_initializer()
with tf.Session() as sess:
    sess.run(init)
    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(coord=coord)
    num_files = sess.run(count_num_files)
    for i in range(num_files):
        image=img.eval()
        print(image.shape)
        Image.fromarray(np.asarray(image)).save('te.jpeg')
Julien
  • 3,613
  • 2
  • 23
  • 25
Ivan Jacobs
  • 178
  • 1
  • 9
2

(Can't comment, not enough reputation, but here is a modified version that worked for me)

To @HamedMP error about the No default session is registered you can use InteractiveSession to get rid of this error: https://www.tensorflow.org/versions/r0.8/api_docs/python/client.html#InteractiveSession

And to @NumesSanguis issue with Image.show, you can use the regular PIL .show() method because fromarray returns an image object.

I do both below (note I'm using JPEG instead of PNG):

import tensorflow as tf
import numpy as np
from PIL import Image

filename_queue = tf.train.string_input_producer(['my_img.jpg']) #  list of files to read

reader = tf.WholeFileReader()
key, value = reader.read(filename_queue)

my_img = tf.image.decode_jpeg(value) # use png or jpg decoder based on your files.

init_op = tf.initialize_all_variables()
sess = tf.InteractiveSession()
with sess.as_default():
    sess.run(init_op)

# Start populating the filename queue.

coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)

for i in range(1): #length of your filename list
  image = my_img.eval() #here is your image Tensor :) 

Image.fromarray(np.asarray(image)).show()

coord.request_stop()
coord.join(threads)
curiouscat
  • 91
  • 2
  • 7
2

You can use tf.keras API.

import tensorflow as tf
import numpy as np
from tensorflow.keras.preprocessing.image import load_img, array_to_img

tf.enable_eager_execution()

img = load_img("example.png")
img = tf.convert_to_tensor(np.asarray(img))
image = tf.image.resize_images(img, (800, 800))
to_img = array_to_img(image)
to_img.show()
Alex-zhai
  • 311
  • 3
  • 3
  • While this works, it's a little bit slow because load_img just uses PIL. (https://github.com/keras-team/keras-preprocessing/blob/master/keras_preprocessing/image.py#L508) Instead of that solution you should use cv2.imread which is faster or the described answers above – Fabian Oct 23 '18 at 19:38
2

First of all scipy.misc.imread and PIL are no longer available. Instead use imageio library but you need to install Pillow for that as a dependancy

pip install Pillow imageio

Then use the following code to load the image and get the details about it.

import imageio
import tensorflow as tf

path = 'your_path_to_image' # '~/Downloads/image.png'

img = imageio.imread(path)
print(img.shape) 

or

img_tf = tf.Variable(img)
print(img_tf.get_shape().as_list()) 

both work fine.

desertnaut
  • 57,590
  • 26
  • 140
  • 166
Gayal Kuruppu
  • 1,261
  • 1
  • 17
  • 29
0

I used CIFAR10 format instead of STL10 and code came out like

filename_queue = tf.train.string_input_producer(filenames)
read_input = read_cifar10(filename_queue)
with tf.Session() as sess:       
    tf.train.start_queue_runners(sess=sess)
    result = sess.run(read_input.uint8image)        
img = Image.fromarray(result, "RGB")    
img.save('my.jpg')

The snippet is identical with mttk and Rosa Gronchi, but Somehow I wasn't able to show the image during run-time, so I saved as the JPG file.

Cloud Cho
  • 1,594
  • 19
  • 22