3

我有一个关于 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()

image1.png

4

3 回答 3

5

您的图像可以在等高线图中表示的原因是它显然是伪彩色图像,即使用完整的 RGB 色谱来表示单个变量的图像。 等高线图还表示具有确定颜色的单个变量(即 Z 轴)的数据,因此您也可以将图像数据表示为等高线图。

这就是我建议您首先使用等高线图的原因。(但是,您在这个问题中实际要求的内容通常不存在:没有普遍有效的方法将彩色图像转换为等高线图,因为彩色图像通常具有三种独立的颜色,RGB 和等高线图只有一个(Z 轴),,这只适用于伪彩色图像。)

要专门解决您的问题:

1) 如果您有用于创建显示的伪彩色图像的 z 轴数据,只需在等高线图中使用此数据。这是最好的解决方案。

2)如果您没有 z 数据,那就更麻烦了,因为您需要将图像中的颜色反转为 z 值,然后将其放入等高线图中。您展示的图像几乎可以肯定是使用颜色图 matplotlib.cm.jet,我找不到比unubtu 在这里说的更好的方法来反转它。

最后,您需要了解等高线图和图像之间的区别才能使细节发挥作用。

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()

但是,正如我上面建议的那样,正确地做到这一点并不难。

于 2013-03-24T16:41:01.760 回答
4

OK,一些研究和简化代码,关键是convert('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()

在这里输出

于 2013-03-24T22:09:36.113 回答
2

编辑:对不起,我误解了 OP 的原始问题。要从 PILImage对象中获取 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()
于 2013-03-23T02:27:51.547 回答