Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python - greyscale image to 3 channels

I have code that looks like this

from skimage import io as sio
test_image = imread('/home/username/pat/file.png')
test_image  = skimage.transform.resize(test_image, (IMG_HEIGHT, IMG_WIDTH), mode='constant', preserve_range=True)
print test_image.shape # prints (128,128)
print test_image.max(), test_image.min() # prints 65535.0 0.0
sio.imshow(test_image)

More importantly, I need to make this image be in 3 channels, so I can feed it into a neural network that expects such input, any idea how to do that?

I want to transform a 1-channel image into a 3-channel image that looks reasonable when I plot it, makes sense, etc. How?

I tried padding with 0s, I tried copying the same values 3 times for the 3 channels, but then when I try to display the image, it looks like gibberish. So how can I transform the image into 3 channels, even if it becomes something like, bluescale instead of greyscale, but still be able to visualize it in a meaningful way?

Edit: if I try

test_image = skimage.color.gray2rgb(test_image)

I get all white image, with some black dots.

I get the same all white, rare small black dots if I try

convert Test1_PC_1.tif -colorspace sRGB -type truecolor Test1_PC_1_new.tif

Before the attempted transform with gray2rgb

print type(test_image[0,0])
<type 'numpy.uint16'>

After

print type(test_image[0,0,0])
<type 'numpy.float64'>
like image 460
Baron Yugovich Avatar asked Aug 11 '18 20:08

Baron Yugovich


2 Answers

You need to convert the array from 2D to 3D, where the third dimension is the color.

You can use the gray2rgb function function provided by skimage:

test_image = skimage.color.gray2rgb(test_image)

Alternatively, you can write your own conversion -- which gives you some flexibility to tweak the pixel values:

# basic conversion from gray to RGB encoding
test_image = np.array([[[s,s,s] for s in r] for r in test_image],dtype="u1")

# conversion from gray to RGB encoding -- putting the image in the green channel
test_image = np.array([[[0,s,0] for s in r] for r in test_image],dtype="u1")

I notice from your max() value, that you're using 16-bit sample values (which is uncommon). You'll want a different dtype, maybe "u16" or "int32". Also, you may need to play some games to make the image display with the correct polarity (it may appear with black/white reversed).

One way to get there is to just invert all of the pixel values:

test_image = 65535-test_image ## invert 16-bit pixels

Or you could look into the norm parameter to imshow, which appears to have an inverse function.

like image 108
Brent Bradburn Avatar answered Nov 05 '22 22:11

Brent Bradburn


Your conversion from gray-value to RGB by replicating the gray-value three times such that R==G==B is correct.

The strange displayed result is likely caused by assumptions made during display. You will need to scale your data before display to fix it.

Usually, a uint8 image has values 0-255, which are mapped to min-max scale of display. Uint16 has values 0-65535, with 65535 mapped to max. Floating-point images are very often assumed to be in the range 0-1, with 1 mapped to max. Any larger value will then also be mapped to max. This is why you see so much white in your output image.

If you divide each output sample by the maximum value in your image you’ll be able to display it properly.

like image 22
Cris Luengo Avatar answered Nov 05 '22 23:11

Cris Luengo