非线性缩放色图以增强对比度

8 投票
1 回答
6607 浏览
提问于 2025-04-16 20:22

以下这段Python代码可以创建一个热图,热图中包含的是正态分布的数值。

import numpy as np
from matplotlib import pylab as plt


np.random.seed(123) #make sure we all have same data
m = np.random.randn(200).reshape(10, 20)
plt.imshow(m, cmap='RdYlGn', interpolation='nearest')
plt.colorbar()

这是运行这段代码后得到的结果。

example 1

我想通过“淡化”接近零的数值来增强这个图像的对比度。 我可以通过对原始数据进行双曲正切缩放来轻松实现这一点,代码如下:

def disigmoidScaling(values, steepnessFactor=1, ref=None):
    ''' Sigmoid scaling in which values around a reference point are flattened
    arround a reference point

    Scaled value y is calculated as 
        y = sign(v - d)(1 - exp(-((x - d)/s)**2)))
    where v is the original value,  d is the referenc point and s is the 
    steepness factor
    '''
    if ref is None:
        mn = np.min(values)
        mx = np.max(values)
        ref = mn + (mx - mn) / 2.0

    sgn = np.sign(values - ref)
    term1 = ((values - ref)/steepnessFactor) ** 2
    term2 = np.exp(- term1) 
    term3 = 1.0 - term2 
    return sgn * term3


plt.imshow(disigmoidScaling(m, 4), cmap='RdYlGn', interpolation='nearest')
plt.colorbar()

这是新的输出结果。

example 2

我对这个结果很满意,但有一点让我不太高兴,就是在这个版本中,原始的数值被缩放后的数值替代了。

有没有办法可以对数值进行非线性映射,以便更好地应用到颜色图上呢?

1 个回答

4

一个颜色映射表就像一个字典,里面存储了红色、绿色和蓝色的值,这些值的范围在0到1之间。线性分段颜色映射的文档中给出了一个例子。

cdict = {'red':   [(0.0,  0.0, 0.0),
               (0.5,  1.0, 1.0),
               (1.0,  1.0, 1.0)],

     'green': [(0.0,  0.0, 0.0),
               (0.25, 0.0, 0.0),
               (0.75, 1.0, 1.0),
               (1.0,  1.0, 1.0)],

     'blue':  [(0.0,  0.0, 0.0),
               (0.5,  0.0, 0.0),
               (1.0,  1.0, 1.0)]}

在这个例子中,表格中每种颜色的每一行都是一组(x, y0, y1)的元组。在每组中,x的值必须从0到1逐渐增加。对于任何在x[i]和x[i+1]之间的输入值z,输出的颜色值会在y1[i]和y0[i+1]之间线性插值,也就是说会根据这两个值之间的比例来计算。

比如,RdYlGn这个颜色映射表有11个x值,从0到1.0,每隔0.1一个值。你可以通过调用

plt.cm.RdYlGn._segmentdata

来获取cdict的值。然后你可以把x值改成你想要的任何步长(只要它们是逐渐增加的,并且在0到1之间),再通过调用matplotlib.colors.LinearSegmentedColormap来生成一个新的颜色映射表。关于这方面有很多很好的例子,可以在Matplotlib Cookbook中找到。

撰写回答