简体   繁体   中英

Grayscale Heatmap to Color Gradient Heatmap

I am trying to take a set of 256x256px 8-bit grayscale .pngs (with transparency) and convert the grayscale .png to a color .png of the same size, still retaining transparency. The palette I want to use is Zissou1 from the R wesanderson package, which I have gotten into a Python dictionary where each key corresponds to a greyscale value and each value a HEX color.

import os
from PIL import Image, ImageColor

### dic = the dictionary containing the palette in format {grayscale pixel value: "HEX COLOR"},
###       created earlier in the script

with Image.open("3.png") as im:
    fin = Image.new("RGBA", im.size)
    px = im.load()
    px1 = fin.load()
    for x in range(0,256):
        for y in range(0,256):
            px1.putpixel(x,y,ImageColor.getcolor(dic[px.getpixel(x,y)[1]],"RGBA"))
    fin.show()

I am getting the error:

px1.putpixel(x,y,ImageColor.getcolor(dic[px.getpixel(x,y)[1]],"RGBA"))
AttributeError: 'PixelAccess' object has no attribute 'putpixel'

The first parameter to PIL's PixelAccess.putpixel method expects the pixel's coordinates to be passed as a (x,y) tuple:

px1.putpixel((x,y),ImageColor.getcolor(dic[px.getpixel(x,y)[1]],"RGBA"))

Alternatively, consider using the Image.point method which takes a look up table similar to the one you already created to map an image based on pixel values. See the answer at Using the Image.point() method in PIL to manipulate pixel data for more details

To extend on Jason's answer :

The lookup as given by PIL

With Image.point(lookup_table, mode = 'L') you can lookup and transpose the colors of your image.

lookup_table = ...
with Image.open("3.png") as orig:
    image = orig.point(lookup_table, mode = 'L')
    image.show()

To see an example for using the Image.point method with the lookup_table :

Your own implementation (fixed with improved naming)

or implement the lookup against your_dic yourself:

your_dic = ...
with Image.open("3.png") as orig:
    image = colored_from_map(orig, your_dic)
    image.show()

with this alternative function (you almost did):

def colored_from_map(orig, map_to_color):
    image_in = orig.load()
    image = Image.new("RGBA", im.size)
    image_out = image.load()

    for x in range(0,256):
        for y in range(0,256):
            coords = (x,y)
            greyscale = image_in.getpixel(x,y)[1]
            color_name = map_to_color[greyscale]
            image_out.putpixel(coords, ImageColor.getcolor(color_name,"RGBA"))

    return image

Preserving the alpha-channel (transparency)

See the source-code of ImageColor.getColor() at the begin and end of its method body:

    color, alpha = getrgb(color), 255  # default to no-transparency
    if len(color) == 4:  # if your mapped color has 4th part as alpha-channel
        color, alpha = color[0:3], color[3]  # then use it

    # omitted lines
    else:
        if mode[-1] == "A":  # if the last char of `RGBA` is `A`
            return color + (alpha,)  # then return with added alpha-channel
    return color

(comments mine)

So you could simply set the fourth element of the returned color-tuple to the previous value of the original gray-scale image:

            greyscale = image_in.getpixel(x,y)[1]  # containing original alpha-channel
            color_name = map_to_color[greyscale]  # name or hex
            mapped_color = ImageColor.getcolor(color_name,"RGB")  # removed the A
            transposed_color = mapped_color[:2] + (greyscale[3],)  # first 3 for RGB + original 4th for alpha-channel (transparency)
            image_out.putpixel(coords, transposed_color)

Note: because the A(lpha-channel) is provided from original image, I removed the A from the getColor invocation's last argument. Technically, you can also remove the slicing from mapped_color[:2] to result in mapped_color + (greyscale[3],) .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM