Search code examples
pythonnumpyimage-processingpython-imaging-library

Create 12 multichannel image starting from single RBG pictures


I have 12, three channels, RGB pictures (.jpeg). I would like to merge them in a unique 12 channels image using python.

I tried the following code converting each picture in a numpy array. I successfully create a 3D array with 12 arrays on axes 2 but it seems that PIL does not support saving multichannel images:

from PIL import Image
import numpy as np

# Load the first image
path = 'test_img_0000_Ch1.jpeg'
img = Image.open(path)
arr = np.array(img.convert('L'))

for x in range(2, 13):
    path = '_test_img_0000_Ch{x}.jpeg'
    img = Image.open(path)
    array_stack = np.array(img.convert('L'))
    arr = np.dstack((arr, array_stack))

image = Image.fromarray(arr)
image.save("multichannel.jpeg")

Solution

  • You can create a "multi-page" TIFF with 12 images, each 640px wide and 480px tall like this:

    from tifffile import imwrite
    import numpy as np
    
    # Create stack of 12 images, each 640x480 pixels
    data = np.zeros((12,480,640), np.uint8)
    
    # Make first image fully black, 2nd image grey(20), 3rd image grey(40)
    for i in range(12):
        data[i, :, :] = 20 * i
    
    # Save as 12 image multi-page TIFF
    imwrite('result.tif', data, photometric='minisblack')
    

    If you now open it in macOS Preview image viewer, you will see the single TIFF file contains 12 images, each one successively lighter than the previous one:

    enter image description here

    And if you check its content with ImageMagick, you will find 12 individual images within the singe TIFF:

    identify result.tif
    
    result.tif[0] TIFF 640x480 640x480+0+0 8-bit Grayscale Gray 3.51761MiB 0.000u 0:00.000
    result.tif[1] TIFF 640x480 640x480+0+0 8-bit Grayscale Gray 0.000u 0:00.000
    result.tif[2] TIFF 640x480 640x480+0+0 8-bit Grayscale Gray 0.000u 0:00.000
    result.tif[3] TIFF 640x480 640x480+0+0 8-bit Grayscale Gray 0.000u 0:00.000
    result.tif[4] TIFF 640x480 640x480+0+0 8-bit Grayscale Gray 0.000u 0:00.000
    result.tif[5] TIFF 640x480 640x480+0+0 8-bit Grayscale Gray 0.000u 0:00.000
    result.tif[6] TIFF 640x480 640x480+0+0 8-bit Grayscale Gray 0.000u 0:00.000
    result.tif[7] TIFF 640x480 640x480+0+0 8-bit Grayscale Gray 0.000u 0:00.000
    result.tif[8] TIFF 640x480 640x480+0+0 8-bit Grayscale Gray 0.000u 0:00.000
    result.tif[9] TIFF 640x480 640x480+0+0 8-bit Grayscale Gray 0.000u 0:00.000
    result.tif[10] TIFF 640x480 640x480+0+0 8-bit Grayscale Gray 0.000u 0:00.000
    result.tif[11] TIFF 640x480 640x480+0+0 8-bit Grayscale Gray 0.000u 0:00.000
    

    If you now want to read it back in, and take channels 0, 6 and 11 as R, G and B:

    from tifffile import imread
    from PIL import Image
    
    im = imread('result.tif')
    # Take channels 0, 6 and 11 as R, G and B
    rgb = np.dstack((im[0], im[6], im[11]))
    Image.fromarray(rgb).save('result.jpg')
    

    The red channel is zero, the green channel is 120 and the blue channel is 220, so the result is largely blueish.

    enter image description here