OpenCV 內建了顯示圖片的功能,然而有時候,我們會想結合 Matplotlib 的功能來顯示圖片,然而若直接將 cv2.imread
傳回的陣列,透過 matplotlib.pyplot
的 imshow
顯示,會出現色彩不正確的問題。例如:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('caterpillar.jpg')
plt.imshow(img)
plt.show()
在〈OpenCV 與 NumPy〉中談過,cv2.imread
傳回的物件具有 NumPy 陣列的行為,若是讀取了圖片的 RGB,軸 2 用來指定像素的 BGR 欄位索引,也就是 RGB 的相反,之所以會使用 BGR,是歷史性的原因,早期一些相機或硬體使用的就是 BGR,而 OpenCV 就這麼一直用到現在了。
為了能在 Matplotlib 顯示正確的色彩,必須將 BGR 轉為 RGB,方式之一是將 BGR 拆分出來,再以 RGB 順序合併,這可以分別透過 cv2
的 split
與 merge
達到:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('caterpillar.jpg')
b, g, r = cv2.split(img)
plt.imshow(cv2.merge([r, g, b]))
plt.show()
或者是透過 cv2.cvtColor
指定 cv2.COLOR_BGR2RGB
,就可以專 BGR 轉為 RGB:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('caterpillar.jpg')
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.show()
如果你對〈NumPy 陣列索引〉夠熟悉,也可以透過範圍索引的方式來分離 BGR:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('caterpillar.jpg')
b = img[:,:,0]
g = img[:,:,1]
r = img[:,:,2]
plt.imshow(cv2.merge([r, g, b]))
plt.show()
既然如此,在最後一個範圍索引處,直接透過 -1 來反轉不就好了?
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('caterpillar.jpg')
plt.imshow(img[:,:,::-1])
plt.show()
以上四個範例,都可以得到正確的色彩顯示:
如果是用 OpenCV 以灰階方式讀入圖片,因為元素只有灰階值,應該就沒有什麼 BGR 轉 RGB 的問題了吧?!是沒錯,不過有另一個小問題:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('caterpillar.jpg', cv2.IMREAD_GRAYSCALE)
plt.imshow(img)
plt.show()
這會顯示以下的結果:
這是因為不指定 imshow
的 cmap
的話,會使用 rcParams["image.cmap"]
作為預設,自行指定 cmap
為 gray
就可以了:
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('caterpillar.jpg', cv2.IMREAD_GRAYSCALE)
plt.imshow(img, cmap = 'gray')
plt.show()