下面是使用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
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陣列中(通過匯入或生成它)。在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")