Reputation: 199
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
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
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
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