johni07
johni07

Reputation: 771

Tensorflow / Keras mean image subtraction

During training data generation a mean image (not mean pixel values per channel) is calculated.

In order to improve the learning process, I would like to apply a simplified method to zero-center and normalize my network input data, which mainly consists of RGB images:

image = (image - meanImage + 1.0) / 2.0

As DL Framework, I'm using Keras - to load the training data tfrecords files like described here are used.

At some point of my loading pipeline, I've the input (X) and output (Y) tensors:

def datasetLoader(dataSetPath, batchSize):
   dataset = tf.data.TFRecordDataset(dataSetPath)

   dataset = dataset.map(_ds_parser, num_parallel_calls=8)

   # This dataset will go on forever
   dataset = dataset.repeat()

   # Set the batchsize
   dataset = dataset.batch(batchSize)

   # Create an iterator
   iterator = dataset.make_one_shot_iterator()

   # Create your tf representation of the iterator
   X, Y = iterator.get_next()  

   # Bring the date back in shape
   X = tf.reshape(I, [-1, 66, 198, 3])
   Y = tf.reshape(Y,[-1,1])

   return X, Y

The variables X and Y are just tensors which get populated during a tensorflow session later on.

The question is: How can I use my local png mean image to perform the zero-center and normalize task? .

Upvotes: 4

Views: 3583

Answers (2)

Samer Ayoub
Samer Ayoub

Reputation: 1001

import cv2
import numpy as np

img = img.astype(np.float32)
img -= img.mean()
img /= img.std()

Upvotes: 0

Dmytro Prylipko
Dmytro Prylipko

Reputation: 5064

Tensor subtraction

To subtract your mean image from a batch of your image data, you can simply use the minus operator (which is just a syntax sugar for tf.subtract):

In [28]: x = tf.zeros((2, 3, 3))

In [29]: x
Out[29]: 
<tf.Tensor: id=38, shape=(2, 3, 3), dtype=float32, numpy=
array([[[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.]],

       [[0., 0., 0.],
        [0., 0., 0.],
        [0., 0., 0.]]], dtype=float32)>

In [30]: mean = tf.eye(3)

In [31]: mean
Out[31]: 
<tf.Tensor: id=42, shape=(3, 3), dtype=float32, numpy=
array([[1., 0., 0.],
       [0., 1., 0.],
       [0., 0., 1.]], dtype=float32)>

In [32]: x - mean
Out[32]: 
<tf.Tensor: id=44, shape=(2, 3, 3), dtype=float32, numpy=
array([[[-1.,  0.,  0.],
        [ 0., -1.,  0.],
        [ 0.,  0., -1.]],

       [[-1.,  0.,  0.],
        [ 0., -1.,  0.],
        [ 0.,  0., -1.]]], dtype=float32)>

Reading an image into tensor

To get your PNG image as a TensorFlow tensor, just wrap a numpy array with tf.constant:

import cv2

mean_img = cv2.imread('/path/to/the/image')
mean_img_tensor = tf.constant(mean_img)

Pay attention that OpenCV will read the image into BGR color space by default. You may want to convert it into RGB then:

mean_img = cv2.cvtColor(mean_img, cv2.COLOR_BGR2RGB))

Or use Python image library:

from PIL import Image
import numpy as np
mean_img = Image.open('/path/to/image')
mean_img_tensor = tf.constant(np.array(mean_img))

Putting it all together

Since you use TF Dataset API, I believe map_and_batch must be a better solution for performance:

def datasetLoader(dataSetPath, batchSize, mean_image_path):
   dataset = tf.data.TFRecordDataset(dataSetPath)
   mean_img = cv2.cvtColor(cv2.imread(mean_image_path), cv2.COLOR_BGR2RGB)
   mean = tf.constant(mean_img)

   dataset = dataset.map(_ds_parser, num_parallel_calls=8)

   # This dataset will go on forever
   dataset = dataset.repeat()

   def preprocess(X, Y):
        # Bring the date back in shape
        X = tf.reshape(X, [-1, 66, 198, 3])
        Y = tf.reshape(Y,[-1,1])
        X = X - mean
        return X, Y

   # Set the batchsize
   dataset = dataset.apply(tf.contrib.data.map_and_batch(map_func=preprocess, batch_size=batchSize, num_parallel_calls=8))

   return dataset.make_one_shot_iterator().get_next()

Upvotes: 4

Related Questions