Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Read in an indexed color image in Python

An indexed color image is an image with pixels that are integers (1,2, .. N), and for each integer, an associated color maps to this pixel from a given color map. In MATLAB, reading in an indexed color image can be done in the following way:

[im, colormap] = imread('indexed.png');

How can I do the same thing in Python? I have tried OpenCV, scikit-image but they all convert to RGB automatically.

like image 288
Dzung Nguyen Avatar asked Oct 08 '15 18:10

Dzung Nguyen


People also ask

What is an indexed color image?

In computing, indexed color is a technique to manage digital images' colors in a limited fashion, in order to save computer memory and file storage, while speeding up display refresh and file transfers.

How many colors An indexed image can use?

The pixels in the image contain index numbers that point to the RGB value in the color lookup table. The RGB values are the ones used by the display system. Indexed color images can look nearly identical to their 24-bit originals, because the 256 most frequently used colors are identified.

What is an indexed color space and what is it used for?

Indexed colorspaces are a very useful way of reducing the amount of memory and space needed when they only have a certain number of repeating colour values. You define a limited set number of colour values (usually 2,4, 16 or 256) and define a color value for each.

What is index of an image?

An indexed image uses direct mapping of pixel values to colormap values. The color of each image pixel is determined by using the corresponding value of X as an index into map . A colormap is often stored with an indexed image and is automatically loaded with the image when you use the imread function.


Video Answer


1 Answers

After some research, this is what I came up with. You can use the Python Imaging Library - specifically the Pillow fork: https://python-pillow.github.io/

Install the package, then you can use the Image.open method from the Image class to open up the image. If your image has a colour map, then the image will automatically load in as an indexed image. To make this usable, use NumPy and use the numpy.array constructor. I'm assuming you can use NumPy because scikit-image and OpenCV both use NumPy as the fundamental backbone to image manipulations:

from PIL import Image
import numpy as np
im = Image.open("image.png") # Replace with your image name here
indexed = np.array(im) # Convert to NumPy array to easier access

Finally, if you want the colour map / palette that was actually used for the image, use the Image.getpalette method that's part of the Image class. However, this will give you a num_colours x 3 element list. Therefore, to determine how many colours you have, simply divide the length of this list by 3. However, the colour map that is loaded in MATLAB is normalized whereas getpalette does not normalize this and defaults to the type of the image loaded in. As such, you'll have to infer on what the image type is by looking at the converted NumPy image version, then use this to normalize your colour map:

As such:

# Get the colour palette
palette = im.getpalette()

# Determine the total number of colours
num_colours = len(palette)/3

# Determine maximum value of the image data type
max_val = float(np.iinfo(indexed.dtype).max)

# Create a colour map matrix
map = np.array(palette).reshape(num_colours, 3) / max_val

To demonstrate that we have this correct, here's an indexed image from a question that I helped solve a while ago:

Using MATLAB to load in this image:

[indexed, map] = imread('http://i.stack.imgur.com/OxFwB.png');

I get this when I focus on rows 280 to 290 and columns 400 to 410 in the indexed image as a double check:

>> indexed(280:290, 400:410)

ans =

   59   60   61   62   65   64   59   56   56   53   49
   61   61   64   65   65   60   60   57   58   53   53
   67   62   67   56   60   62   60   61   51   59   55
   65   60   62   61   58   58   53   55   57   55   54
   66   58   56   59   56   56   52   55   52   55   52
   68   68   61   61   61   56   56   55   55   57   59
   66   59   59   66   68   62   62   60   60   60   53
   70   68   64   58   61   63   67   61   67   56   59
   69   67   63   64   62   65   63   68   67   64   58
   61   68   68   72   71   73   70   66   63   64   64
   68   67   70   71   71   69   64   64   65   64   58

Here's what I get in Python when I run the equivalent code to get the indexed image. Note that I physically downloaded the image onto my computer and loaded it in from disk. Take note that NumPy starts indexing at 0 and not 1, so I had to subtract the ranges by 1. Also note that the end of the range operator is exclusive:

In [29]: indexed[279:290, 399:410]
Out[29]: 
array([[59, 60, 61, 62, 65, 64, 59, 56, 56, 53, 49],
       [61, 61, 64, 65, 65, 60, 60, 57, 58, 53, 53],
       [67, 62, 67, 56, 60, 62, 60, 61, 51, 59, 55],
       [65, 60, 62, 61, 58, 58, 53, 55, 57, 55, 54],
       [66, 58, 56, 59, 56, 56, 52, 55, 52, 55, 52],
       [68, 68, 61, 61, 61, 56, 56, 55, 55, 57, 59],
       [66, 59, 59, 66, 68, 62, 62, 60, 60, 60, 53],
       [70, 68, 64, 58, 61, 63, 67, 61, 67, 56, 59],
       [69, 67, 63, 64, 62, 65, 63, 68, 67, 64, 58],
       [61, 68, 68, 72, 71, 73, 70, 66, 63, 64, 64],
       [68, 67, 70, 71, 71, 69, 64, 64, 65, 64, 58]], dtype=uint8)

That matches... now what about the colour maps? Let's take a look at the first 10 rows of the colour maps between MATLAB and Python:

MATLAB

>> format long g;
>> map(1:10,:)

ans =

                         0                         0                         0
        0.0156862745098039       0.00392156862745098        0.0274509803921569
        0.0313725490196078       0.00784313725490196        0.0588235294117647
        0.0470588235294118        0.0117647058823529        0.0901960784313725
        0.0627450980392157        0.0156862745098039          0.12156862745098
        0.0784313725490196        0.0196078431372549         0.152941176470588
        0.0941176470588235        0.0235294117647059         0.184313725490196
         0.109803921568627        0.0274509803921569         0.215686274509804
         0.125490196078431        0.0313725490196078         0.247058823529412
         0.141176470588235        0.0352941176470588          0.27843137254902

Python

In [30]: map[:10,:]
Out[30]: 
array([[ 0.        ,  0.        ,  0.        ],
       [ 0.01568627,  0.00392157,  0.02745098],
       [ 0.03137255,  0.00784314,  0.05882353],
       [ 0.04705882,  0.01176471,  0.09019608],
       [ 0.0627451 ,  0.01568627,  0.12156863],
       [ 0.07843137,  0.01960784,  0.15294118],
       [ 0.09411765,  0.02352941,  0.18431373],
       [ 0.10980392,  0.02745098,  0.21568627],
       [ 0.1254902 ,  0.03137255,  0.24705882],
       [ 0.14117647,  0.03529412,  0.27843137]])

... looks like it matches!

like image 92
rayryeng Avatar answered Oct 19 '22 01:10

rayryeng