Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
221 views
in Technique[技术] by (71.8m points)

python - How to decode color mapping in matplotlib's Colormap?

I know how to map a number to a color from this post: Map values to colors in matplotlib

But I don't know how to decode the mapping to get my original color, assuming this is a one-to-one mapping, which it must be I figure.

I am encoding an image for visualization purposes, but I need to be able to decode it and read the original data values.

For reference, here are the Colormap docs: http://matplotlib.org/api/cm_api.html

Here's my try to the main answer below, which still isn't working right.

from PIL import Image
import numpy as np
import matplotlib
import matplotlib.cm as cm
values = [670, 894, 582, 103, 786, 348, 972, 718, 356, 692]
minima = 103
maxima = 972
norm = matplotlib.colors.Normalize(vmin=minima, vmax=maxima, clip=True)
mapper = cm.ScalarMappable(norm=norm, cmap=cm.gist_rainbow_r)
c = []
for i in range(10):
    c.append(mapper.to_rgba(values[i], bytes=True))
print(c) # [(75, 255, 0, 255), (255, 77, 0, 255), (0, 255, 64, 255), (255, 0, 191, 255), (255, 250, 0, 255), (0, 72, 255, 255), (255, 0, 40, 255), (151, 255, 0, 255), (0, 83, 255, 255), (108, 255, 0, 255)]

def get_value_from_cm(color, cmap, colrange):
    # color = matplotlib.colors.to_rgba(color)
    r = np.linspace(colrange[0], colrange[1], 10) # there are 10 values
    norm = matplotlib.colors.Normalize(colrange[0], colrange[1])
    mapvals = cmap(norm(r))[:, :4] # there are 4 channels: r,g,b,a
    distance = np.sum((mapvals - color) ** 2, axis=1)
    return r[np.argmin(distance)]

decoded_colors = []
for i in range(10):
    decoded_colors.append(get_value_from_cm(c[i], cm.gist_rainbow_r, colrange=[minima, maxima]))
print(decoded_colors) # [778.88888888888891, 778.88888888888891, 489.22222222222223, 103.0, 778.88888888888891, 392.66666666666669, 103.0, 778.88888888888891, 392.66666666666669, 778.88888888888891]
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Inverting the colormapping is possible, if
(a) you know the data range it is mapping and
(b) if you know the colormap that has been used, and
(c) if the colormap is unambiguous.

The following function would return the value given a color, a colormap and the range over which the colormap has been used.

import numpy as np
import matplotlib.colors
import matplotlib.pyplot as plt

def get_value_from_cm(color, cmap, colrange=[0.,1.]):
    color=matplotlib.colors.to_rgb(color)
    r = np.linspace(colrange[0],colrange[1], 256)
    norm = matplotlib.colors.Normalize(colrange[0],colrange[1])
    mapvals = cmap(norm(r))[:,:3]
    distance = np.sum((mapvals - color)**2, axis=1)
    return r[np.argmin(distance)]


b = get_value_from_cm(plt.cm.coolwarm(0.5), plt.cm.coolwarm, [0.,1.])
c = get_value_from_cm(np.array([1,0,0]), plt.cm.coolwarm)

print b                   # 0.501960784314
print plt.cm.coolwarm(b)
# (0.86742763508627452, 0.86437659977254899, 0.86260246201960789, 1.0)
print plt.cm.coolwarm(0.5)
#(0.86742763508627452, 0.86437659977254899, 0.86260246201960789, 1.0)

Note that this method involves an error, so you only get the closest value from the colormap and not the value that has initially been used to create the color from the map.

In the updated code from the question, you have the color defined as integers between 0 and 255 for each channel. You therefore need to first map those to the range 0 to 1.

from PIL import Image
import numpy as np
import matplotlib
import matplotlib.cm as cm
values = [670, 894, 582, 103, 786, 348, 972, 718, 356, 692]
minima = 103
maxima = 972
norm = matplotlib.colors.Normalize(vmin=minima, vmax=maxima, clip=True)
mapper = cm.ScalarMappable(norm=norm, cmap=cm.gist_rainbow_r)
c = []
for i in range(10):
    c.append(mapper.to_rgba(values[i], bytes=True))
print(c) # [(75, 255, 0, 255), (255, 77, 0, 255), (0, 255, 64, 255), (255, 0, 191, 255), (255, 250, 0, 255), (0, 72, 255, 255), (255, 0, 40, 255), (151, 255, 0, 255), (0, 83, 255, 255), (108, 255, 0, 255)]

def get_value_from_cm(color, cmap, colrange):
    color = np.array(color)/255. 
    r = np.linspace(colrange[0], colrange[1], 256) 
    norm = matplotlib.colors.Normalize(colrange[0], colrange[1])
    mapvals = cmap(norm(r))[:, :4] # there are 4 channels: r,g,b,a
    distance = np.sum((mapvals - color) ** 2, axis=1)
    return r[np.argmin(distance)]

decoded_colors = []
for i in range(10):
    decoded_colors.append(get_value_from_cm(c[i], cm.gist_rainbow_r, colrange=[minima, maxima]))
print(decoded_colors)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...