Converting 1-layer image to 3-layer image

Viewed 1101

I'm trying to convert a 1-layer (grey-scale) image to a 3-layer RGB image. Below is the code I'm using. This runs without error but doesn't create the correct result.

from PIL import Image  # used for loading images

def convertLToRgb(img):
    height = img.size[1]
    width = img.size[0]
    size = img.size
    mode = 'RGB'
    data = np.zeros((height, width, 3))
    for i in range(height):
        for j in range(width):
            pixel = img.getpixel((j, i))
            data[i][j][0] = pixel
            data[i][j][1] = pixel
            data[i][j][2] = pixel
    img = Image.frombuffer(mode, size, data)
    return img

What am I doing wrong here? I'm not expecting a color picture, but I am expecting a black and white picture resembling the input. Below are the input and output images:

enter image description here enter image description here

3 Answers

Depending on the bit depth of your image, change:

data = np.zeros((height, width, 3))

to:

data = np.zeros((height, width, 3), dtype=np.uint8)

For an 8-bit image, you need to force your Numpy array dtype to an unsigned 8-bit integer, otherwise it defaults to float64. For 16-bit, use np.uint16, etc.

What is your task? black-white image or RGB color image. If you want to convert the gray image to the black-white image. You can directly convert the image into a binary image. As for your code, two things you need to care. Firstly, the location of the pixel is right, the wrong location will make the image all black like your post. Secondly, you only can convert the RGB to grayscale image directly, but you can not convert the grayscale image to RGB directly, because it may be not accurate.

You can do it with the PIL.Image and PIL.ImageOps as shown below. Because of the way it's written, the source image isn't required to be one layer—it will convert it to one if necessary before using it:

from PIL import Image
from PIL.ImageOps import grayscale

def convertLToRgb(src):
    src.load()   
    band = src if Image.getmodebands(src.mode) == 1 else grayscale(src)
    return Image.merge('RGB', (band, band, band))

src = 'whale_tail.png'
bw_img = Image.open(src)
rgb_img = convertLToRgb(bw_img)
rgb_img.show()
Related