我对Python(pylab)和绘图有疑问 -
我能够加载并显示图像(下面的代码加载下面的图像),但是我无法将其绘制为3D中的轮廓,我知道pylab.contourf(x,y,z)
需要一个数组,尽管我不确定如何从加载的图像数据中实现这一点。
请提出任何建议和帮助。我的代码:
from PIL import Image
import pylab
fileName = "image1.png"
im = Image.open(fileName)
#pylab.contourf(im) # don't work - needs an array but how
pylab.axis('off')
pylab.imshow(im)
pylab.show()
答案 0 :(得分:5)
您的图像可以在等高线图中表示的原因是它显然是 pseudocolor image ,即使用完整RGB色谱表示单个变量的图像。 轮廓图也表示具有确定颜色(即Z轴)的单个变量的数据,因此您也可以将图像数据表示为等高线图。
这就是I suggested首先使用等高线图的原因。 (你在这个问题中实际要求的是,通常不存在:没有通常有效的方法将颜色图像转换成等高线图,因为彩色图像通常有三个独立颜色,RGB和等高线图只有一个(Z轴),即,这仅适用于伪彩色图像。)
专门解决您的问题:
1)如果您有用于创建所示伪彩色图像的z轴数据,只需在等高线图中使用此数据。这是最好的解决方案。
2)如果你没有z数据,那就更麻烦了,因为你需要将图像中的颜色反转为z值,然后将其放入等高线图中。您显示的图像几乎肯定使用了色图matplotlib.cm.jet,我看不到比unubtu says here更好的方法来反转它。
最后,您需要了解等高线图和图像之间的差异,以使细节发挥作用。
为什么convert
不起作用的演示:
在这里,我使用从左到右的z值斜坡来运行完整的测试用例。很明显,z值现在完全搞砸了,因为最大的值现在是最小的等等。
也就是说,目标是图。 2匹配图。 4,但他们是非常不同的。当然,问题是convert
没有正确地将jet
映射到原始的z值集。
import numpy as np
import matplotlib.pyplot as plt
import Image
fig, axs = plt.subplots(4,1)
x = np.repeat(np.linspace(0, 1, 100)[np.newaxis,:], 20, axis=0)
axs[0].imshow(x, cmap=plt.cm.gray)
axs[0].set_title('1: original z-values as grayscale')
d = axs[1].imshow(x, cmap=plt.cm.jet)
axs[1].set_title('2:original z-values as jet')
d.write_png('temp01.png') # write to a file
im = Image.open('temp01.png').convert('L') # use 'convert' on image to get grayscale
data = np.asarray(im) # make image into numpy data
axs[2].imshow(data, cmap=plt.cm.gray)
axs[2].set_title("3: 'convert' applied to jet image")
img = Image.open('temp01.png').convert('L')
z = np.asarray(img)
mydata = z[::1,::1] # I don't know what this is here for
axs[3].imshow(mydata,interpolation='nearest',cmap=plt.cm.jet)
axs[3].set_title("4: the code that Jake French suggests")
plt.show()
但是,正如我上面所建议的那样,正确地做到这一点并不是那么难。
答案 1 :(得分:3)
好的,一些研究和简化代码,关键是转换('L'),即rgb到灰度,然后Ali_m的代码工作:
from mpl_toolkits.mplot3d import Axes3D
from matplotlib import pylab as pl
from PIL import Image
import numpy as np
import pylab
img = Image.open('40.jpg').convert('L')
z = np.asarray(img)
mydata = z[::1,::1]
fig = pl.figure(facecolor='w')
ax1 = fig.add_subplot(1,2,1)
im = ax1.imshow(mydata,interpolation='nearest',cmap=pl.cm.jet)
ax1.set_title('2D')
ax2 = fig.add_subplot(1,2,2,projection='3d')
x,y = np.mgrid[:mydata.shape[0],:mydata.shape[1]]
ax2.plot_surface(x,y,mydata,cmap=pl.cm.jet,rstride=1,cstride=1,linewidth=0.,antialiased=False)
ax2.set_title('3D')
ax2.set_zlim3d(0,100)
pl.show()
答案 2 :(得分:2)
编辑:抱歉,我误解了OP的原始问题。要从PIL Image
对象获取numpy数组,通常只需调用np.array(im)
即可。但是,我使用了大量的显微镜数据,我发现对于某些图像格式(特别是16位TIFF),这种语法并不总是有效,在这种情况下我会使用np.asarray(im.getdata()).reshape(*im.shape[::-1])
。
以下是修改后的示例:
import numpy as np
from matplotlib import pylab as pl
from mpl_toolkits.mplot3d import Axes3D
from PIL import Image
def getimarray(path):
im = Image.open(path,'r')
return np.array(im)
def doplots(path='tmp/cell.png'):
mydata = getimarray(path)
mydata = mydata[::5,::5]
fig = pl.figure(facecolor='w')
ax1 = fig.add_subplot(1,2,1)
im = ax1.imshow(mydata,interpolation='nearest',cmap=pl.cm.jet)
ax1.set_title('2D')
ax2 = fig.add_subplot(1,2,2,projection='3d')
x,y = np.mgrid[:mydata.shape[0],:mydata.shape[1]]
ax2.plot_surface(x,y,mydata,cmap=pl.cm.jet,rstride=1,cstride=1,linewidth=0.,antialiased=False)
ax2.set_title('3D')
ax2.set_zlim3d(0,255)
return fig,ax1,ax2
if __name__ == '__main__':
doplots()