5

My network takes images of size 100 x 100 pixels. Therefore I have to resize the images of my dataset which are of different size. I want to be able to extract the largest central square region from a given image and then resize it to 100 x 100.

To be more precisely, let's say an image has a width of 200 pixels and a height of 50 pixels. Then I want to extract the largest central square region which is in this example 50 x 50 followed by resizing the image to 100 x 100 pixels.

What is the right way to do that using Tensorflow? Right now I am using tf.image.resize_images() which distorts the image and I want to get rid of that.

2
  • What is the shape of your tensors? That is, is it (batch_size, height, width, channels) or something else? Commented Feb 25, 2019 at 12:17
  • @jdehesa Every image is of shape (width, height, channels). I can not present my dataset as (batch_size, height, width, channels) since height and width of each image can vary. Commented Feb 25, 2019 at 12:25

4 Answers 4

5

Sounds like crop_to_bounding_box is doing what you need:

import tensorflow as tf

def crop_center(image):
    h, w = image.shape[-3], image.shape[-2]
    if h > w:
        cropped_image = tf.image.crop_to_bounding_box(image, (h - w) // 2, 0, w, w)
    else:
        cropped_image = tf.image.crop_to_bounding_box(image, 0, (w - h) // 2, h, h)
    return tf.image.resize_images(cropped_image, (100, 100))
Sign up to request clarification or add additional context in comments.

3 Comments

Is there a solution where I do not have to provide any other information than the image? Your solution works only for images of size 200 x 50 right?
@Samuel Well, of course you have to plug in other numbers than 200 and 50 if your dimensions are different ;) I updated my answer. I'm not aware of any function doing exactly what you want in one step.
I can not get the correct shape, image.shape returns (None, None, 3). I am mapping this function into a tf.data.Dataset. How can I do that?
1

I think this does what you want:

import tensorflow as tf

def crop_center_and_resize(img, size):
    s = tf.shape(img)
    w, h = s[0], s[1]
    c = tf.minimum(w, h)
    w_start = (w - c) // 2
    h_start = (h - c) // 2
    center = img[w_start:w_start + c, h_start:h_start + c]
    return tf.image.resize_images(img, [size, size])

print(crop_center_and_resize(tf.zeros((80, 50, 3)), 100))
# Tensor("resize_images/Squeeze:0", shape=(100, 100, 3), dtype=float32)

There is also tf.image.crop_and_resize, which can do both things in one go, but you have to use normalized image coordinates with that:

import tensorflow as tf

def crop_center_and_resize(img, size):
    s = tf.shape(img)
    w, h = s[0], s[1]
    c = tf.minimum(w, h)
    wn, hn = h / c, w / c
    result = tf.image.crop_and_resize(tf.expand_dims(img, 0),
                                      [[(1 - wn) / 2, (1 - hn) / 2, wn, hn]],
                                      [0], [size, size])
    return tf.squeeze(result, 0)

Comments

1
import tensorflow as tf


def central_square_crop(image):                                                                                                                                                                                                                                       
    h, w = image.get_shape()[0].value, image.get_shape()[1].value                                                                                                                                                                                                     
    side = tf.minimum(h, w)                                                                                                                                                                                                                                           
    begin_h = tf.maximum(0, h - side) // 2                                                                                                                                                                                                                            
    begin_w = tf.maximum(0, w - side) // 2                                                                                                                                                                                                                            
    return tf.slice(image, [begin_h, begin_w, 0], [side, side, -1])                                                                                                                                                                                                   


def main():                                                                                                                                                                                                                                                           
    image_t = tf.reshape(tf.range(5 * 7), [5, 7])                                                                                                                                                                                                                     
    image_t = tf.transpose(tf.stack([image_t, image_t, image_t]), [1, 2, 0])                                                                                                                                                                                          
    cropped_image_t = central_square_crop(image_t)                                                                                                                                                                                                                    
    with tf.Session() as sess:                                                                                                                                                                                                                                        
        image, cropped_image = sess.run([image_t, cropped_image_t])                                                                                                                                                                                                   
        print(image[:, :, 0])                                                                                                                                                                                                                                         
        print(cropped_image[:, :, 0])                                                                                                                                                                                                                                 


if __name__ == '__main__':                                                                                                                                                                                                                                            
    main() 

Output before crop:

[[ 0  1  2  3  4  5  6]
 [ 7  8  9 10 11 12 13]
 [14 15 16 17 18 19 20]
 [21 22 23 24 25 26 27]
 [28 29 30 31 32 33 34]]

After crop:

[[ 1  2  3  4  5]
 [ 8  9 10 11 12]
 [15 16 17 18 19]
 [22 23 24 25 26]
 [29 30 31 32 33]]

Then, apply resizing as usual.

Comments

1

How about this?

import tensorflow as tf
import pathlib

data_root_orig = tf.keras.utils.get_file(
    origin="https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz",
    fname="flower_photos",
    untar=True,
)
data_root = pathlib.Path(data_root_orig)
print(data_root)
for item in data_root.iterdir():
    print(item)

import random

all_image_paths = list(data_root.glob("*/*"))
all_image_paths = [str(path) for path in all_image_paths]
image_count = len(all_image_paths)
print(image_count)

def preprocess_image(img: tf.Tensor):
    img = tf.image.decode_jpeg(img, channels=3)
    shapes = tf.shape(img)
    h, w = shapes[-3], shapes[-2]
    small = tf.minimum(h, w)
    img = tf.image.resize_with_crop_or_pad(img, small, small)
    img = tf.image.resize(img, [192, 192])
    img /= 255.0
    return img

@tf.function
def load_and_preprocess_image(path: str):
    image = tf.io.read_file(path)
    return preprocess_image(image)

import matplotlib.pyplot as plt

image_path = all_image_paths[0]
plt.imshow(load_and_preprocess_image(image_path))
plt.grid(False)
plt.show()

orignal original resized [output image2

2 Comments

What does @tf.function stand for? Where do you use the random module? What did the input image look like?
random is for augumentation. you can remove it. @tf.function is for compile the function into tensorflow's byte code.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.