注意
前往結尾以下載完整的範例程式碼。
圖片教學#
使用 Matplotlib 繪製圖片的簡短教學。
啟動命令#
首先,讓我們啟動 IPython。它是標準 Python 提示符的絕佳增強功能,並且與 Matplotlib 特別搭配。直接在 shell 中或使用 Jupyter Notebook(其中 IPython 作為執行中的核心)啟動 IPython。
啟動 IPython 後,我們現在需要連接到 GUI 事件迴圈。這會告訴 IPython 在哪裡(以及如何)顯示繪圖。若要連接到 GUI 迴圈,請在您的 IPython 提示符下執行 %matplotlib magic。關於這確切做了什麼的更多詳細資訊,請參閱 IPython 關於 GUI 事件迴圈的文件。
如果您正在使用 Jupyter Notebook,則可以使用相同的命令,但人們通常會對 %matplotlib magic 使用特定的引數
In [1]: %matplotlib inline
這會開啟內嵌繪圖,其中繪圖圖形將會出現在您的 notebook 中。這對互動性有重要的影響。對於內嵌繪圖,在輸出繪圖的儲存格下方的儲存格中的命令將不會影響繪圖。例如,無法從建立繪圖的儲存格下方的儲存格變更色彩圖。然而,對於其他後端,例如 Qt,它會開啟一個單獨的視窗,在建立繪圖的儲存格下方的儲存格將會變更繪圖 - 它是一個記憶體中的即時物件。
本教學將使用 Matplotlib 的隱式繪圖介面 pyplot。此介面會維護全域狀態,並且對於快速且輕鬆地試驗各種繪圖設定非常有用。替代方案是顯式,它更適合大型應用程式開發。有關隱式和顯式介面之間權衡的說明,請參閱 Matplotlib 應用程式介面 (API) 和 快速入門指南,以開始使用顯式介面。現在,讓我們繼續使用隱式方法
from PIL import Image
import matplotlib.pyplot as plt
import numpy as np
將影像資料匯入 Numpy 陣列#
Matplotlib 依賴 Pillow 函式庫來載入影像資料。
這是我們將要使用的圖片

它是一個 24 位元 RGB PNG 圖片(R、G、B 各 8 位元)。根據您取得資料的位置,您最有可能遇到的其他種類的圖片是 RGBA 圖片,允許透明度,或是單通道灰階(亮度)圖片。下載 stinkbug.png 到您的電腦,以供本教學的其餘部分使用。
我們使用 Pillow 開啟圖片(使用 PIL.Image.open
),並立即將 PIL.Image.Image
物件轉換為 8 位元 (dtype=uint8
) numpy 陣列。
img = np.asarray(Image.open('../../doc/_static/stinkbug.png'))
print(repr(img))
array([[[104, 104, 104],
[104, 104, 104],
[104, 104, 104],
...,
[109, 109, 109],
[109, 109, 109],
[109, 109, 109]],
[[105, 105, 105],
[105, 105, 105],
[105, 105, 105],
...,
[109, 109, 109],
[109, 109, 109],
[109, 109, 109]],
[[107, 107, 107],
[106, 106, 106],
[106, 106, 106],
...,
[110, 110, 110],
[110, 110, 110],
[110, 110, 110]],
...,
[[112, 112, 112],
[111, 111, 111],
[110, 110, 110],
...,
[116, 116, 116],
[115, 115, 115],
[115, 115, 115]],
[[113, 113, 113],
[113, 113, 113],
[112, 112, 112],
...,
[115, 115, 115],
[114, 114, 114],
[114, 114, 114]],
[[113, 113, 113],
[115, 115, 115],
[115, 115, 115],
...,
[114, 114, 114],
[114, 114, 114],
[113, 113, 113]]], dtype=uint8)
每個內部清單代表一個像素。在這裡,使用 RGB 圖片,有 3 個值。由於它是黑白圖片,R、G 和 B 都相似。RGBA(其中 A 是 alpha 或透明度)每個內部清單有 4 個值,而簡單的亮度圖片只有一個值(因此只是一個 2 維陣列,而不是 3 維陣列)。對於 RGB 和 RGBA 圖片,Matplotlib 支援 float32 和 uint8 資料類型。對於灰階,Matplotlib 僅支援 float32。如果您的陣列資料不符合這些描述之一,則需要重新調整其比例。
將 numpy 陣列繪製為圖片#
因此,您的資料在 numpy 陣列中(透過匯入或產生)。讓我們來渲染它。在 Matplotlib 中,這是使用 imshow()
函數執行的。在這裡,我們將抓取繪圖物件。此物件讓您可以輕鬆地從提示符操作繪圖。
imgplot = plt.imshow(img)

您也可以繪製任何 numpy 陣列。
將假色方案套用至圖片繪圖#
假色可以是增強對比度和更輕鬆地視覺化資料的有用工具。當使用投影機簡報您的資料時,這特別有用 - 它們的對比度通常相當差。
假色僅與單通道、灰階、亮度圖片相關。我們目前有一個 RGB 圖片。由於 R、G 和 B 都相似(請自行參閱上方或您的資料),我們可以使用陣列切片來選擇資料的一個通道(您可以在 Numpy 教學中閱讀更多內容)
lum_img = img[:, :, 0]
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')

注意
然而,請記住,在使用內嵌後端的 Jupyter Notebook 中,您無法變更已渲染的繪圖。如果您在一個儲存格中建立 imgplot,則無法在後續儲存格中對其呼叫 set_cmap() 並預期較早的繪圖會變更。請確保您在一個儲存格中一起輸入這些命令。plt 命令不會變更先前儲存格中的繪圖。
還有許多其他可用的色彩圖方案。請參閱色彩圖的清單和圖片。
色彩比例參考#
了解顏色代表的值會很有幫助。我們可以透過在您的圖形中新增色彩列來做到這一點

檢查特定的資料範圍#
有時,您想要增強圖片中的對比度,或擴展特定區域的對比度,同時犧牲色彩變化不大或不重要的細節。尋找有趣區域的好工具是直方圖。若要建立圖片資料的直方圖,我們使用 hist()
函數。

通常,圖片的「有趣」部分在峰值附近,而且您可以透過剪輯峰值上方和/或下方的區域來獲得額外的對比度。在我們的直方圖中,看起來高檔中沒有太多有用的資訊(圖片中沒有太多白色的東西)。讓我們調整上限,以便我們有效地「放大」直方圖的一部分。我們透過設定 clim(色彩圖限制)來做到這一點。
這可以透過在對 imshow
的呼叫中傳遞 clim 關鍵字引數來完成。
plt.imshow(lum_img, clim=(0, 175))

這也可以透過呼叫返回的圖片繪圖物件的 set_clim()
方法來完成,但請確保在使用 Jupyter Notebook 時在與繪圖命令相同的儲存格中執行此操作 - 它不會變更先前儲存格中的繪圖。
imgplot = plt.imshow(lum_img)
imgplot.set_clim(0, 175)

陣列插補方案#
插補會根據不同的數學方案計算像素的顏色或值「應該」是什麼。發生這種情況的一個常見位置是當您調整圖片大小時。像素數量會變更,但您想要相同的資訊。由於像素是離散的,因此存在遺失的空間。插補是您填補該空間的方式。這就是為什麼您的圖片在放大時有時會出現像素化的原因。當原始圖片和擴大圖片之間的差異較大時,效果會更明顯。讓我們取得我們的圖片並縮小它。我們有效地捨棄像素,僅保留少數幾個。現在,當我們繪製它時,該資料會擴大到螢幕上的大小。舊像素不再存在,電腦必須繪製像素以填補該空間。
我們將使用我們用於載入圖片的 Pillow 函式庫來調整圖片大小。
img = Image.open('../../doc/_static/stinkbug.png')
img.thumbnail((64, 64)) # resizes image in-place
imgplot = plt.imshow(img)

在這裡,我們使用預設插補 ("nearest"),因為我們沒有給 imshow()
任何插補引數。
讓我們嘗試一些其他的。這是 "bilinear"
imgplot = plt.imshow(img, interpolation="bilinear")

和 bicubic
imgplot = plt.imshow(img, interpolation="bicubic")

雙立方插補通常用於放大照片 - 人們傾向於喜歡模糊而不是像素化。
指令碼的總執行時間:(0 分鐘 9.582 秒)