Pervaiz Niazi
Pervaiz Niazi

Reputation: 199

Copy Gray Scale Image Content to 3 Channels

I am loading gray scale images in batches using ImageDataGenerator. I need to copy the content of every gray scale image into 3 channels. I have tried following code but it seems it is not working:

def grayscale_to_rgb(images, channel_axis=-1):
images= K.expand_dims(images, axis=channel_axis)
tiling = [1] * 4    # 4 dimensions: B, H, W, C
tiling[channel_axis] *= 3
images= K.tile(images, tiling)
return images




train_images_orign= grayscale_to_rgb(train_images_orign)
valid_images_orign= grayscale_to_rgb(valid_images_orign)
test_images_orign= grayscale_to_rgb(test_images_orign)

x_train, y_train = next(train_images_orign)
x_valid, y_valid = next(valid_images_orign)
x_test, y_test = next(test_images_orign)

In which direction I should look to accomplish this?

Upvotes: 3

Views: 6566

Answers (3)

today
today

Reputation: 33410

Update: It turns out that load_img function in Keras has been implemented in such a way that if the color mode of the image being loaded and the given color_mode argument (which by default is 'RGB'), differs then the image will be converted to given color_mode. As a result, in this case the grayscale image would be automatically converted to RGB.


You can use the preprocessing_function argument of ImageDataGenerator as well (assuming you are using color_mode='grayscale', otherwise the note above applies):

import numpy as np

def gray_to_rgb(img):
    return np.repeat(img, 3, 2)

generator = ImageDataGenerator(..., preprocessing_function=gray_to_rgb)
train_gen = generator.flow_from_directory(color_mode='grayscale', ...)

Just note that this function is applied after any image augmentation:

preprocessing_function: function that will be implied on each input. The function will run after the image is resized and augmented. The function should take one argument: one image (Numpy tensor with rank 3), and should output a Numpy tensor with the same shape.

Upvotes: 7

devssh
devssh

Reputation: 1186

I don't have a direct way to convert it using ImageDataGenerator but I had the same problem a few days back and indirectly you can use opencv2 to convert it to rgb then I read it using imageio to numpy.

import cv2
cv2.imread('path/to/img/a.png') # look at glob for reading from folder
cv2.cvtColor(gray,cv2.COLOR_GRAY2RGB)
cv2.imwrite('path/to/output/a.png')

import imageio
import skimage.transform as transform

image_size = 64
dimensions=4
array = []
for image_path in glob.glob("path/to/output/*.png"):
    try:
        im = imageio.imread(image_path)
        array = [*array, transform.resize(im, (image_size, image_size, dimensions))]
        array_names = [*array_names, image_path.split("output/")[1].split(".png")[0]]
    except ValueError:
        ""

np.array(array).shape

The expand_dims can be used as follows with tensorflow 1.10.1 helper methods which are closely tied to ImageDataGenerator to directly do the same but you will have to convert it from gray2rgb somehow which can improve this answer.

preprocess_input = tf.keras.applications.resnet50.preprocess_input
preds = model.predict(preprocess_input(np.expand_dims(array[0], axis=0))) # where model is some keras model

You will need the following to decode the output

decode_predictions = tf.keras.applications.resnet50.decode_predictions
decode_predictions(preds, top=3)

If this does not solve your problem or at least provide a template for solutions please leave a comment and i'll update it accordingly :)

Upvotes: 0

pitfall
pitfall

Reputation: 2621

I think I have a better solution, which is to write a wrapper layer

class MyPreprocess( Layer ) :
    def call( self, inputs ) :
        # expand your input from gray scale to rgb
        # if your inputs.shape = (None,None,1)
        fake_rgb = K.concatenate( [inputs for i in range(3)], axis=-1 ) 
        fake_rgb = K.cast( fake_rgb, 'float32' )
        # else use K.stack( [inputs for i in range(3)], axis=-1 ) 
        # preprocess for uint8 image
        x = preprocess_input( fake_rgb )
        return x
    def compute_output_shape( self, input_shape ) :
        return input_shape[:3] + (3,)


gray_in = Input(shape=(None,None,1), name='gray_uint8')
tensor_in = MyPreprocess(name='preproc')( gray_in )
pred_out = PretrainedModel( tensor_in )
new_model = Model( inputs=gray_in, outputs=pred_out )

In this way, the new_model can be directly used to predict a unit8 image.

Upvotes: 0

Related Questions