通过将不透明度设置为数据渐变,在Matplotlib imshow中创建地图着色的问题

时间:2015-05-18 18:02:19

标签: python matplotlib gradient opacity pixel-shading

我试图通过计算数据的梯度并使用它来设置alpha值来为某些数据的地图添加阴影。 我开始加载我的数据(遗憾的是我不能共享数据,因为它正在准备中用于许多手稿,但我正在添加我的整个代码和屏幕截图):

import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
from pylab import imread, imshow, gray, mean
import matplotlib.colors as cl
%matplotlib inline 

data = np.loadtxt('data.txt')
plt.imshow(data, cmap='cubehelix')
plt.show()

给我一​​个数据图: data

然后我计算总水平梯度并将其标准化以用于着色:

dx,dy = np.gradient(data, 1, 1)
tdx=np.sqrt(dx*dx + dy*dy)
tdx_n=(tdx-tdx.min())/(tdx.max()-tdx.min())
tdx_n=1-tdx_n

看起来像我预期的那样:

plt.imshow(tdx_n[4:-3,4:-3],  cmap='bone')
plt.show()

gradient

要创建着色效果,我想我会从数据图中获取颜色,然后用渐变替换不透明度,使暗色阴影与渐变成比例,如下所示:

img_array = plt.get_cmap('cubehelix')(data[4:-3,4:-3])
img_array[..., 3] = (tdx_n[4:-3,4:-3]) 
plt.imshow(img_array)
plt.show()

但结果不是我的预期: shading

这就是我要找的东西(在Matlab中创建,色彩映射是不同的): shading Matlab

有关如何修改我的代码的任何建议吗?

更新

使用Ran Novitsky的方法,使用titusjan的答案中建议的代码,我得到了这个结果: pegtop

给出了我正在寻找的效果。在阴影方面我虽然喜欢titusjan自己建议使用HSV,但结果如下: titusjans

然而,即使我要求它,我也无法将色彩映射作为cubehelix:

from matplotlib.colors import rgb_to_hsv, hsv_to_rgb
hsv = rgb_to_hsv(img_array[:, :, :3])
hsv[:, :, 2] = tdx_n
rgb = hsv_to_rgb(hsv)
plt.imshow(rgb[4:-3,4:-3], cmap='cubehelix')
plt.show()

1 个答案:

答案 0 :(得分:2)

首先,Matplotlib包含Amazon's example Dockerfile实现。这通过将梯度与特定角度的光源进行比较来计算强度。所以它并不完全是你所实现的,但是接近甚至可能会产生更好的结果。

Ran Novitsky已经将hill shading与Matplotlib的不同之处在于如何合并颜色和强度值。我不知道哪个更好,但值得一看。

结合颜色和强度的最佳方法可能是使用 gouraud着色,它用于3D计算机图形。我过去实现的自己的方法是将强度放在图像的HSV颜色的层中。

我认为我不同意您在图像的alpha图层中放置强度(tdx_n)的方法。这意味着在渐变较低的情况下,图像将是透明的,您将看到之前绘制的数据。我认为这就是你的屏幕截图中发生的事情。

此外,我认为您需要在将数据传递到cmap之前对其进行规范化,就像规范化强度一样:

data_n=(data-data.min())/(data.max()-data.min())
img_array = plt.get_cmap('cubehelix')(data_n)

然后我们可以使用Ran Novitsky的方法将颜色与强度合并:

rgb = img_array[:, :, :3]

# form an rgb eqvivalent of intensity
d = tdx_n.repeat(3).reshape(rgb.shape)

# simulate illumination based on pegtop algorithm.
rgb = 2 * d * rgb + (rgb ** 2) * (1 - 2 * d)

plt.imshow(rgb[4:-3,4:-3])
plt.show()

或者您可以按照我过去的方法将强度放在HSV三联体的层中。

from matplotlib.colors import rgb_to_hsv, hsv_to_rgb

hsv = rgb_to_hsv(img_array[:, :, :3])
hsv[:, :, 2] = tdx_n
rgb = hsv_to_rgb(hsv)
plt.imshow(rgb[4:-3,4:-3])
plt.show()

修改2015-05-23:

你的问题促使我完成了一年前开始的山坡阴影实施。我把它放在Github another hill shading implementation上。

它使用类似于Gouraud着色的混合机制,用于3D计算机图形。它在下面标有 RGB混合。我认为这是最好的混合算法,当颜色接近黑色时,HSV混合会产生错误的结果(注意HSV图像中心的蓝色,这在非阴影数据中不存在)。

RGB混合也是最简单的算法,它只是将强度与RGB三元组相乘(它增加了长度为1的额外维度以允许在乘法中进行广播)。

rgb = img_array[:, :, :3]
tdx_n_exp = np.expand_dims(tdx_n, axis=2) 
result = tdx_n_exp * rgb
plt.imshow(result[4:-3,4:-3])

blending comparison results