簡體   English   中英

Python:來自2D圖像的3D輪廓 - pylab和contourf

[英]Python: 3D contour from a 2D image - pylab and contourf

我有一個關於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

您的圖像可以在等高線圖中表示的原因是它顯然是偽彩色圖像 ,即使用完整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()

但是,正如我上面所建議的那樣,正確地做到這一點並不困難。

好的,一些研究和簡化代碼,關鍵是轉換('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()

在這里輸出

編輯 :對不起,我誤解了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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM