Convert PythonMagick Image object to numpy array (for OpenCV) and then to PIL image object

389 Views Asked by At

I want to convert a PythonMagick Image Object to a NumPy array that can be used in OpenCV, and then I want to convert it into a PIL image object. I have searched Google but cannot find any sources explaining how to do this. Can someone show me how to convert image objects between these different modules?

1

There are 1 best solutions below

0
On

The fastest way that I've found consist in saving and opening it:

import PythonMagic
import cv2

# pm_img is a PythonMagick.Image
pm_img.write('path/to/temporary/file.png')
np_img = cv2.imread('path/to/temporary/file.png')

I haven't found any satisfactory way to convert PythonMagick images to NumPy arrays without saving them, but there is a slow way that involves using python loops:

import PythonMagick
import numpy as np

pm_img = PythonMagick.Image('path/to/image.jpg')
h, w = pm_img.size().height(), pm_img.size().width()
np_img = np.empty((h, w, 3), np.uint16) # PythonMagick opens images with 16 bit depth
                                        # It seems to store the same byte twice (weird)

for i in range(h):
    for j in range(w):
        # OpenCV stores pixels as BGR
        np_img[i, j] = (pm_img.pixelColor(j, i).quantumBlue(),
                        pm_img.pixelColor(j, i).quantumGreen(),
                        pm_img.pixelColor(j, i).quantumRed())
np_img = np_img.astype(np.uint8)

Converting NumPy arrays to PIL images is easier:

from PIL import Image

pil_img = Image.fromarray(np_img[:, :, ::-1].astype(np.uint8))

Since PIL stores images in RGB but OpenCV stores them in BGR it's necessary to change the order of the channels ([:, :, ::-1]).

Image.fromarray() takes a NumPy array with dtype np.uint8.