How to retrieve with and height of an image tensor returned by tf.image.decode_jpeg?

Question:

I try to setup an images pipeline that builds an images dataset for Tensorflow that crops the images.
I followed this tutorial but I want to crop the file to a square and not resize it without preserving the aspect ratio.
I can’t figure out how to get their dimensions.

#
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
#

import glob


AUTOTUNE = tf.data.experimental.AUTOTUNE
IMAGE_SIZE = 192


def preprocess_image(path):
    img_raw = tf.io.read_file(path)
    img_tensor = tf.image.decode_jpeg(img_raw, channels=3)
    print("img_tensor")
    print(img_tensor)
    height = img_tensor.shape[0]
    print("height")
    print(height)
    return img_tensor


files_path = glob.glob('./images/*.jpeg')
image_count = len(files_path)
path_ds = tf.data.Dataset.from_tensor_slices(files_path)
path_ds.map(preprocess_image, num_parallel_calls=AUTOTUNE)

The tensor shape returned by tf.image.decode_jpeg is :

Tensor("DecodeJpeg:0", shape=(None, None, 3), dtype=uint8)

How can I access the size of the jpg image ?

When I access it this way it works :

#
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
#

image = tf.io.read_file('./images/4c34476047bcbbfd10b1fd3342605659.jpeg/')
image = tf.image.decode_jpeg(image, channels=3)

print("image.shape")
print(image.shape)


It prints :

image.shape
(700, 498, 3)
Asked By: Ant1

||

Answers:

You are facing this issue because the dataset is loaded lazily (only evaluated as it’s needed).

Inherently, tf can only ‘know’ the size of the image if it either reads the file or we, as the developer, tell it. That may seem like an obvious point but it is worth bearing in mind.

So, given that a tf Dataset object can represent arbitrarily large sequences of data (in fact, it’s perfectly reasonable to represent infinite datasets this way), by design it doesn’t read the files up front. Rather it reads them each time our downstream code needs a new example or batch.

I’m afraid it’s really on us to either know the size of the images or to code against all possible sizes up front.

P.S. The reason you can get the second method to work is that it is eagerly evaluating the (single) tensor example.

P.P.S. You perhaps already know that you can “evaluate” the shape of any tensor at execution time with tf.shape() (and use the results of this in your dataset pre-processing pipeline) but you can’t inspect it up front

Answered By: Stewart_R

We can do it. The key is to cast the return of tf.shape(), which appears to be None until the tensorflow graph is executed.

The following code resizes the images preserving the aspect ratio so that the height or width, whichever is shorter, is 256, and then randomly crops it to be 224x224.

def preprocess(filename, label):

    image = tf.image.decode_jpeg(tf.io.read_file(filename), channels=3)

    # Resize the image by converting the smaller edge to 256 
    shape = tf.shape(image)
    _h, _w = shape[0], shape[1] 
    _h, _w = tf.cast(_h, tf.float32), tf.cast(_w, tf.float32)
    ratio = tf.math.divide(tf.constant(256.), tf.math.minimum(_h, _w))
    ratio = tf.cast(ratio, tf.float32)

    image = tf.image.resize(
        image, tf.cast([_h*ratio, _w*ratio], tf.int32)
    )   

    image = tf.image.random_crop(image, [224,224,3])
    return image, label

I use this for ImageNet.

Answered By: fx29351
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.