Cannot read image successfully in tensorflow - python

I want to read the jpeg images into batch for image recognation. The images are in the /Image_p/ file and the image name are listed in the label.csv file, which are presented like 14634_right.
My question is how to fix my code to read the images into batch successfully?
To be more spcific, I don't know whether should I write a for loop and where to implement it.
For the original code, I got the error message on tf.train.shuffle_batch() function:
ValueError: All shapes must be fully defined: [TensorShape([Dimension(None), Dimension(None), Dimension(3)]), TensorShape([])]
My origin code:
# filepath
csv_filepath = r'C:\Users\Jeffy\OneDrive\Course\NMDA\retinaProject\label.csv'
# image parameter
pic_num = 100
pic_height = 64
pic_width = 64
batch_size = 10
# =============================================================================
# import library
import tensorflow as tf
import numpy as np
# =============================================================================
# read csv data
csv = np.loadtxt(open(csv_filepath,"rb"), delimiter=",", dtype='str')
pic_filename = ["" for x in range(pic_num)]
for i in range(pic_num):
pic_filename[i] = eval(csv[i,0]).decode("utf-8") +'.jpeg'
# read the data into batch
for i in range(pic_num):
# read and decode the image
image_contents = tf.read_file('Image_p/' + eval(csv[i,0]).decode("utf-8") +'.jpeg')
image = tf.image.decode_jpeg(image_contents, channels=3)
image = tf.to_float(image)
# Generate batch
batch = tf.train.shuffle_batch([image, float(eval(csv[i,1]))],
batch_size = batch_size,
num_threads = 1,
capacity = batch_size * 100,
min_after_dequeue = batch_size * 10)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
image_tensor = sess.run([batch])
print(batch)
coord.request_stop()
coord.join(threads)
Plus, I have also writen a new file which can read a image successfully (thanks for the help from martianwars).
My test code:
import tensorflow as tf
# read and decode the image
image_contents = tf.read_file('Image_p/11247_left.jpeg')
image = tf.image.decode_jpeg(image_contents, channels=3)
with tf.Session() as sess:
img = sess.run(image)
print(img)

image will have a (?, ?, 3) shape since it's not yet been read, but you have specified the channel in the decode_jpeg() function. Try to print this instead,
with tf.Session() as sess:
img = sess.run(image)
print(img)

Related

TensorFlow read and decode BATCH of images

Using tf.train.string_input_producer and tf.image.decode_jpeg I manage to read from disk and decode a single image.
This is the code:
# -------- Graph
filename_queue = tf.train.string_input_producer(
[img_path, img_path])
image_reader = tf.WholeFileReader()
key, image_file = image_reader.read(filename_queue)
image = tf.image.decode_jpeg(image_file, channels=3)
# Run my network
logits = network.get_logits(image)
# -------- Session
sess = tf.Session()
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
logits_output = sess.run(logits)
The thing is, that when I look at the shape of the logit_outputs I get only 1 value even though the queue is 2 images long.
How can I read and decode the entire queue?
tf.WholeFileReader(), along tf.train.string_input_producer() work as an iterator, and thus does not have an easy way to evaluate the size of the complete dataset it is handling.
To obtain batches of N samples out of it, you could instead use image_reader.read_up_to(filename_queue, N).
Note: you can achieve the same using the newer tf.data pipeline:
def _parse_function(filename):
image_string = tf.read_file(filename)
image_decoded = tf.image.decode_image(image_string)
return image_decoded
# A vector of filenames.
filenames = tf.constant([img_path, img_path])
dataset = tf.data.Dataset.from_tensor_slices((filenames))
dataset = dataset.map(_parse_function).batch(N)
iterator = dataset.make_one_shot_iterator()
next_image_batch = iterator.get_next()
logits = network.get_logits(next_image_batch)
# ...

Trying to expand working code to read multiple JPGs instead of just one into a tensor

I am trying to read in a whole directory into one tensor, with each file in the directory a 28x28 image that is flattened into one row, with each new row representing another image (images are titled 0001.jpg, etc). I have been able to successfully do this for one image but have had no luck creating any loop mechanism to load the files.
I realize this is probably a simple solution but I have no clue how to go about it. If anyone has an example to point me to, or any help would be incredibly appreciated. Thank you.
import numpy as np
import tensorflow as tf
filenames = tf.train.match_filenames_once("C:/train_data/*.jpg")
filename_queue = tf.train.string_input_producer(filenames)
image_reader = tf.WholeFileReader()
_, image_file = image_reader.read(filename_queue)
image_orig = tf.image.decode_jpeg(image_file)
images = tf.image.decode_jpeg(image_file)
images = tf.reshape(images, [-1, 784])
with tf.Session() as sess:
tf.global_variables_initializer().run()
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
image_tensor = sess.run([images])
coord.request_stop()
coord.join(threads)
To load multiple images into the same tensor, you can use tf.train.batch(). For example, to combine 32 images—which must have the same dimensions—into a single tensor, you can modify your program as follows:
filenames = tf.train.match_filenames_once("C:/train_data/*.jpg")
filename_queue = tf.train.string_input_producer(filenames)
image_reader = tf.WholeFileReader()
_, image_file = image_reader.read(filename_queue)
image_orig = tf.image.decode_jpeg(image_file)
images = tf.image.decode_jpeg(image_file)
# `image_batch` contains 32 consecutive images, packed into a single tensor.
image_batch, = tf.train.batch((images,), 32)
If your images might have different sizes, you can use an image-processing function like tf.image.resize_image_with_crop_or_pad() to convert each image to the same shape before passing it to tf.train.batch().

Tensorflow mixes up images and labels when making batch

So I've been stuck on this problem for weeks. I want to make an image batch from a list of image filenames. I insert the filename list into a queue and use a reader to get the file. The reader then returns the filename and the read image file.
My problem is that when I make a batch using the decoded jpg and the labels from the reader, tf.train.shuffle_batch() mixes up the images and the filenames so that now the labels are in the wrong order for the image files. Is there something I am doing wrong with the queue/shuffle_batch and how can I fix it such that the batch comes out with the right labels for the right files?
Much thanks!
import tensorflow as tf
from tensorflow.python.framework import ops
def preprocess_image_tensor(image_tf):
image = tf.image.convert_image_dtype(image_tf, dtype=tf.float32)
image = tf.image.resize_image_with_crop_or_pad(image, 300, 300)
image = tf.image.per_image_standardization(image)
return image
# original image names and labels
image_paths = ["image_0.jpg", "image_1.jpg", "image_2.jpg", "image_3.jpg", "image_4.jpg", "image_5.jpg", "image_6.jpg", "image_7.jpg", "image_8.jpg"]
labels = [0, 1, 2, 3, 4, 5, 6, 7, 8]
# converting arrays to tensors
image_paths_tf = ops.convert_to_tensor(image_paths, dtype=tf.string, name="image_paths_tf")
labels_tf = ops.convert_to_tensor(labels, dtype=tf.int32, name="labels_tf")
# getting tensor slices
image_path_tf, label_tf = tf.train.slice_input_producer([image_paths_tf, labels_tf], shuffle=False)
# getting image tensors from jpeg and performing preprocessing
image_buffer_tf = tf.read_file(image_path_tf, name="image_buffer")
image_tf = tf.image.decode_jpeg(image_buffer_tf, channels=3, name="image")
image_tf = preprocess_image_tensor(image_tf)
# creating a batch of images and labels
batch_size = 5
num_threads = 4
images_batch_tf, labels_batch_tf = tf.train.batch([image_tf, label_tf], batch_size=batch_size, num_threads=num_threads)
# running testing session to check order of images and labels
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)
print image_path_tf.eval()
print label_tf.eval()
coord.request_stop()
coord.join(threads)
Wait.... Isn't your tf usage a little weird?
You are basically running the graph twice by calling:
print image_path_tf.eval()
print label_tf.eval()
And since you are only asking for image_path_tf and label_tf, anything below this line is not even run:
image_path_tf, label_tf = tf.train.slice_input_producer([image_paths_tf, labels_tf], shuffle=False)
Maybe try this?
image_paths, labels = sess.run([images_batch_tf, labels_batch_tf])
print(image_paths)
print(labels)
From your code I'm unsure how your labels are encoded/extracted from the jpeg images. I used to encode everything in the same file, but have since found a much more elegant solution. Assuming you can get a list of filenames, image_paths and a numpy array of labels labels, you can bind them together and operate on individual examples with tf.train.slice_input_producer then batch them together using tf.train.batch.
import tensorflow as tf
from tensorflow.python.framework import ops
shuffle = True
batch_size = 128
num_threads = 8
def get_data():
"""
Return image_paths, labels such that label[i] corresponds to image_paths[i].
image_paths: list of strings
labels: list/np array of labels
"""
raise NotImplementedError()
def preprocess_image_tensor(image_tf):
"""Preprocess a single image."""
image = tf.image.convert_image_dtype(image_tf, dtype=tf.float32)
image = tf.image.resize_image_with_crop_or_pad(image, 300, 300)
image = tf.image.per_image_standardization(image)
return image
image_paths, labels = get_data()
image_paths_tf = ops.convert_to_tensor(image_paths, dtype=tf.string, name='image_paths')
labels_tf = ops.convert_to_tensor(image_paths, dtype=tf.int32, name='labels')
image_path_tf, label_tf = tf.train.slice_input_producer([image_paths_tf, labels_tf], shuffle=shuffle)
# preprocess single image paths
image_buffer_tf = tf.read_file(image_path_tf, name='image_buffer')
image_tf = tf.image.decode_jpeg(image_buffer_tf, channels=3, name='image')
image_tf = preprocess_image_tensor(image_tf)
# batch the results
image_batch_tf, labels_batch_tf = tf.train.batch([image_tf, label_tf], batch_size=batch_size, num_threads=num_threads)

Open and convert to tensor an image from CSV file in TensorFlow

I've got the below function, mostly from this question. That person is trying to read five columns that are all ints. I'm trying to read two columns: one an image file path and one an int. So I need to open the file and convert it into a tensor.
So my question is: how do I read the file and convert it into the necessary tensor?
I've tried quite a few different things like reading the file and converting that string to a tensor using .
def read_from_csv(filename_queue):
reader = tf.TextLineReader()
_, csv_row = reader.read(filename_queue)
record_defaults = [[""],[0]]
image_path, label = tf.decode_csv(csv_row, field_delim=" ", record_defaults=record_defaults)
# here's where I need to read the file somehow...
image = tf.read_file(image_path) # I probably need this somewhere
print(image) # Tensor("DecodeJpeg:0", shape=(?, ?, 3), dtype=uint8)
image = tf.image.decode_jpeg(image, channels=3)
return image, label
I also tried using numpy (can't recall exactly what) but that didn't work either.
Ok, here's what I was missing:
def read_from_csv(filename_queue):
reader = tf.TextLineReader()
key, value = reader.read(filename_queue)
record_defaults = [[""],[0]]
image_path, label = tf.decode_csv(value, field_delim=" ", record_defaults=record_defaults)
#following line contains the important change...
image = tf.image.decode_jpeg(tf.read_file(image_path), channels=3)
return image, label
def input_pipeline(batch_size, num_epochs=None):
filename_queue = tf.train.string_input_producer(["./28_dense.csv"], num_epochs=num_epochs, shuffle=True)
image, label = read_from_csv(filename_queue)
image = tf.reshape(image, [28,28,3])
min_after_dequeue = 5
capacity = min_after_dequeue + 3 * batch_size
image_batch, label_batch = tf.train.batch( [image, label], batch_size=batch_size, capacity=capacity)
return image_batch, label_batch
file_length = 1
examples, labels = input_pipeline(file_length, 1)
The step I was missing was simply reading the file with tf.read_file(image_path). I figured decode_jpeg would do that.
Also just a tip: to inspect values of TF stuff (I hesitate to say variables, etc.) create a session like the following:
with tf.Session() as sess:
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
real_value = sess.run([value]) # see value above
print(real_value)

Tensorflow image reading & display

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 -
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.
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.
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
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
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()
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.
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')
(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)
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()
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.
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.

Categories