下麵是使用Matplotlib繪製圖像的簡短教程。
啟動命令
首先啟動IPython。它是標準Python提示的最佳增強,它與Matplotlib特別相關。現在可以在shell或IPython Notebook上啟動IPython。
隨著IPython的啟動,我們現在需要連接到GUI事件迴圈。這告訴IPython在哪里(以及如何)顯示圖。要連接到GUI迴圈,請在IPython提示符下執行%matplotlib magic
。關於它在IPython的GUI事件迴圈文檔中的確切內容有更詳細的說明。
如果正在使用IPython Notebook,則可以使用相同的命令,但人們通常使用%matplotlib
魔法的特定參數:
In [1]: %matplotlib inline
這將打開內聯繪圖,其中繪圖圖形將出現在筆記本中。這對交互性具有重要意義。對於內聯繪圖,輸出繪圖的單元格下方單元格中的命令不會影響繪圖。例如,無法從創建繪圖的單元格下方的單元格更改顏色貼圖。但是,對於其他後端,例如Qt5,打開一個單獨的窗口,創建繪圖的下麵的單元格將改變繪圖 - 它是記憶體中的活動對象。
本教程將使用matplotlib的命令式繪圖介面pyplot。該介面保持全局狀態,對於快速輕鬆地試驗各種繪圖設置非常有用。另一種選擇是面向對象的介面,它也非常強大,通常更適合大型應用程式開發。如果想瞭解面向對象的介面,一個很好的開始是學習使用指南。現在繼續使用命令式方法:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
將圖像數據導入Numpy數組
Pillow庫支持加載圖像數據。在本機,Matplotlib僅支持PNG圖像。如果本機讀取失敗,下麵顯示的命令將回退到Pillow。
此示例中使用的圖像是PNG檔,但請記住您自己的數據的Pillow要求。
下麵是要使用的圖像:
它是一個24位RGB PNG圖像(R,G,B各有8位)。根據獲取數據的位置,最有可能遇到的其他類型的圖像是RGBA圖像,它們允許透明度,或單通道灰度(亮度)圖像。您可以右鍵單擊它並選擇“將圖像另存為”以將其下載到您的電腦以完成本教程的其餘部分。
現在就開始操作了…
img = mpimg.imread('../../doc/_static/stinkbug.png')
print(img)
執行上面示例代碼,得到以下結果 -
[[[0.40784314 0.40784314 0.40784314]
[0.40784314 0.40784314 0.40784314]
[0.40784314 0.40784314 0.40784314]
...
[0.42745098 0.42745098 0.42745098]
[0.42745098 0.42745098 0.42745098]
[0.42745098 0.42745098 0.42745098]]
[[0.4117647 0.4117647 0.4117647 ]
[0.4117647 0.4117647 0.4117647 ]
[0.4117647 0.4117647 0.4117647 ]
...
[0.42745098 0.42745098 0.42745098]
[0.42745098 0.42745098 0.42745098]
[0.42745098 0.42745098 0.42745098]]
[[0.41960785 0.41960785 0.41960785]
[0.41568628 0.41568628 0.41568628]
[0.41568628 0.41568628 0.41568628]
...
[0.43137255 0.43137255 0.43137255]
[0.43137255 0.43137255 0.43137255]
[0.43137255 0.43137255 0.43137255]]
...
[[0.4392157 0.4392157 0.4392157 ]
[0.43529412 0.43529412 0.43529412]
[0.43137255 0.43137255 0.43137255]
...
[0.45490196 0.45490196 0.45490196]
[0.4509804 0.4509804 0.4509804 ]
[0.4509804 0.4509804 0.4509804 ]]
[[0.44313726 0.44313726 0.44313726]
[0.44313726 0.44313726 0.44313726]
[0.4392157 0.4392157 0.4392157 ]
...
[0.4509804 0.4509804 0.4509804 ]
[0.44705883 0.44705883 0.44705883]
[0.44705883 0.44705883 0.44705883]]
[[0.44313726 0.44313726 0.44313726]
[0.4509804 0.4509804 0.4509804 ]
[0.4509804 0.4509804 0.4509804 ]
...
[0.44705883 0.44705883 0.44705883]
[0.44705883 0.44705883 0.44705883]
[0.44313726 0.44313726 0.44313726]]]
注意dtype
- float32
。Matplotlib已將每個通道的8位數據重新調整為0.0
到1.0
之間的浮點數據。Pillow可以使用的唯一數據類型是uint8。Matplotlib繪圖可以處理float32和uint8,但是除PNG之外的任何格式的圖像讀/寫都限於uint8數據。為什麼8位?大多數顯示器每個通道只能渲染8位顏色等級。為什麼他們只能渲染8位/通道?因為那是人眼所能看到的。
每個內部列表代表一個像素。這裏,對於RGB圖像,有3個值。由於它是黑白圖像,因此R,G和B都相似。RGBA(其中A是alpha或透明度)每個內部列表具有4個值,並且簡單亮度圖像僅具有一個值(因此僅是2-D陣列,而不是3-D陣列)。對於RGB和RGBA圖像,matplotlib支持float32和uint8數據類型。對於灰度,matplotlib僅支持float32。如果您的陣列數據不符合這些描述之一,則需要重新調整它。
將numpy數組繪製為圖像
將數據放在一個numpy數組中(通過導入或生成它)。在Matplotlib中,這是使用imshow()
函數執行的。在這裏,繪圖對象提供了一種從提示中操作繪圖的簡便方法。
imgplot = plt.imshow(img)
將偽彩色方案應用於圖像圖
Pseudocolor可以成為增強對比度和更容易可視化數據的有用工具。這在使用投影儀進行數據演示時尤其有用 - 它們的對比度通常非常差。
偽彩色僅與單通道,灰度,亮度圖像相關。我們目前有一個RGB圖像。由於R,G和B都是相似的(請參閱上面或數據),我們可以選擇一個數據通道:
lum_img = img[:, :, 0]
# This is array slicing. You can read more in the `Numpy tutorial
# <https://docs.scipy.org/doc/numpy/user/quickstart.html>`_.
plt.imshow(lum_img)
`
執行上面示例代碼,得到以下結果 -
現在,使用亮度(2D,無顏色)圖像,應用默認色圖(也稱為查找表,LUT)。默認名稱為viridis
,還有很多其他選擇。
plt.imshow(lum_img, cmap="hot")
請注意,還可以使用set_cmap()
方法更改現有繪圖對象上的顏色映射:
imgplot = plt.imshow(lum_img)
imgplot.set_cmap('nipy_spectral')
注意 - 在具有內聯後端的IPython Notebook中,無法更改已經呈現的繪圖。如果在一個單元格中創建
imgplot
,則不能在稍後的單元格中調用set_cmap()
並期望更早的繪圖。確保在一個單元格中一起輸入這些命令。plt
命令不會更改早期單元格的圖形。
imgplot = plt.imshow(lum_img)
plt.colorbar()
這會為現有的圖形添加一個顏色條。如果更改切換到不同的色彩映射,則不會自動更改 - 必須重新創建繪圖,然後再次添加顏色欄。
檢查特定數據範圍
有時,希望增強圖像的對比度,或者擴大特定區域的對比度,同時犧牲顏色的細節,這些顏色不會有太大變化,或者無關緊要。找到有趣區域的好工具是直方圖。要創建圖像數據的直方圖,我們使用hist()
函數。
plt.hist(lum_img.ravel(), bins=256, range=(0.0, 1.0), fc='k', ec='k')
大多數情況下,圖像的“有趣”部分位於峰值周圍,可以通過剪切峰值上方和/或下方的區域來獲得額外的對比度。在我們的直方圖中,看起來高端沒有太多有用的資訊(圖像中的白色東西不多)。我們調整上限,以便有效地“放大”直方圖的一部分。通過將攀登論證傳遞給imshow
來做到這一點。也可以通過調用圖像繪圖對象的set_clim()
方法來完成此操作,但在使用IPython Notebook時,請確保在與繪圖命令相同的單元格中執行此操作 - 它不會更改早期單元格中的繪圖。
可以在繪圖調用中指定clim -
imgplot = plt.imshow(lum_img, clim=(0.0, 0.7))
還可以使用返回的對象指定clim
-
fig = plt.figure()
a = fig.add_subplot(1, 2, 1)
imgplot = plt.imshow(lum_img)
a.set_title('Before')
plt.colorbar(ticks=[0.1, 0.3, 0.5, 0.7], orientation='horizontal')
a = fig.add_subplot(1, 2, 2)
imgplot = plt.imshow(lum_img)
imgplot.set_clim(0.0, 0.7)
a.set_title('After')
plt.colorbar(ticks=[0.1, 0.3, 0.5, 0.7], orientation='horizontal')
陣列插值方案
根據不同的數學方案,插值計算像素“應該”的顏色或值。發生這種情況的一個常見地方是調整圖像大小。像素數會發生變化,但您需要相同的資訊。由於像素是離散的,因此缺少空間。插值就是填充那個空間的方式。這就是為什麼當把它們炸掉時,圖像有時看起來像是像素化的原因。當原始圖像和擴展圖像之間的差異更大時,效果更明顯。拍攝照片並縮小它,有效地丟棄像素,只保留少數像素。現在,當我們繪製它時,數據會被炸成螢幕上的大小。舊像素不再存在,電腦必須以像素繪製以填充該空間。
加載圖像的Pillow
庫來調整圖像大小。
from PIL import Image
img = Image.open('../../doc/_static/stinkbug.png')
img.thumbnail((64, 64), Image.ANTIALIAS) # resizes image in-place
imgplot = plt.imshow(img)
這裏有默認的插值,雙線性,因為沒有給imshow()
插值參數。
imgplot = plt.imshow(img, interpolation="nearest")