PythonでOpenCVとPillowを使って画像を読み込む方法

2020年3月11日

画像ファイルの読み込み

大きく2つの方法があります。

ひとつは OpenCV を使う方法。もうひとつは Pillow を使う方法です。

順に説明して行きます。

OpenCVを使う場合

OpenCV で画像を読み込むには cv2. imread() を使います。

読み込んだ画像データは ndarray(N-dimensional array の略)型になります。

ndarray 型のデータなら NumPy を使うことができるので高速な画像処理が可能です。

ちなみに、画像処理(image processing)とは、与えられた画像に対して、色や明るさを変えたり、回転、拡大、縮小などの何らかの処理を行って、入力した画像とは異なる画像を出力することです。

例を示します。

まずはソースコードを見てください。

import cv2

img_1 = cv2.imread('./test_photo/hana/001_800px.jpg')

cv2.imshow('img_1', img_1)
cv2.waitKey(0)
cv2.destroyAllWindows()

cv2.imread() で 「001_800px.jpg」という画像ファイルを読み込みます。

その後、cv2.imshow()で画像を出力します。

なお、cv2.waitKey(0) を書かないと画像が一瞬だけ表示されてすぐに消えてしまいます。

出力される画像は例えばこんな感じです。

このとき、img_1 は ndarray 型になっています。

データ型を確認するには以下のように書きます。

import cv2

img_1 = cv2.imread('./test_photo/hana/001_800px.jpg')

print(type(img_1))

実行すると以下が表示されます。

 <class 'numpy.ndarray’>

つまり、img_1 は、ndarray 型 になっていることが分かります。

Pillowを使う場合

Pillowで画像を読み込む場合には、Image.open() を使います。

読み込んだ画像データは JpegImageFile というイメージファイルで ndarray 型ではありません。

画像をPillowで読み込んで NumPy で画像処理したいなら ndarray 型に変換する必要があります。

変換は以下のように行います。

from PIL import Image
import numpy as np

img_2 = Image.open('./test_photo/hana/001_800px.jpg')
img_3 = np.asarray(img_2)  # 入力画像をndarray型に変換する

cv2.imshow('img_3', img_3)
cv2.waitKey(0)
cv2.destroyAllWindows()

実行すると以下の画像が出力されます。

色が変ですね。

実は、Pillow で読み込んだ画像ファイルの色順番は「RGB」ですが、cv2.imshow() を使って出力すると「BGR」の色順番で出力されます。

このため、青ざめた画像になっています。

色順番を「RGB」のまま出力する方法を紹介します。

色順番を「RGB」のまま出力する方法:その1

from PIL import Image
import numpy as np

img_2 = Image.open('./test_photo/hana/001_800px.jpg')
img_3 = np.asarray(img_2)  # 入力画像をndarray型に変換する
img_4 = cv2.cvtColor(img_3, cv2.COLOR_RGB2BGR)  # 色をRGBからBGRに変換

cv2.imshow('img_4', img_4)
cv2.waitKey(0)
cv2.destroyAllWindows()

入力画像を ndarray 型に変換した後、cv2.cvtColor() 関数の第二引数(カッコ内で2番目に記載されているもの)を 「cv2.COLOR_RGB2BGR」として色順番を 「RGB」から「BGR」に変換するやり方です。

実行すると以下になります。

色が正常になりました。

色順番を「RGB」のまま出力する方法:その2

from PIL import Image
import numpy as np

img_2 = Image.open('./test_photo/hana/001_800px.jpg')
img_3 = np.asarray(img_2)  # 入力画像をndarray型に変換する
img_4 = img_3[:,:,::-1]    # 色順番をRGBからBGRに変換する

cv2.imshow('img_4', img_4)
cv2.waitKey(0)
cv2.destroyAllWindows()

img_3 で ndarray 型に変換されているので NumPy が使えます。

img_3の色順番を入れ替える操作を行えばよいので img_4 のように書きます。

これはスライシングという小技です。

[:, :, ::-1] の意味は、[H, W, C](高さ, 幅, チャンネル(RGB))に対して 、高さ方向の全範囲 [:] と幅方向の全範囲 [:] のピクセルに対して、チャンネル(RGB)を逆に(:-1)して(BGR)にしなさいという指示です。

「:」は全範囲を意味し、「:-1」は逆にするを意味します。

簡単な例で言うと、a[:] は a の全範囲、a[::-1] は a の全範囲を逆順にする、という意味です。

上記プログラムを実行すると以下の画像が表示されます。

NumPy の威力。すばらしい。

色順番を「RGB」のまま出力する方法:その3

from PIL import Image
from matplotlib import pyplot as plt

img_2 = Image.open('./test_photo/hana/001_800px.jpg')

plt.imshow(img_2)
plt.show()

matplotlib を使う方法です。

これはグラフを可視化する際によく使われるモジュールです。

matplotlib は、Python上で使われているMATLAB(数値解析ソフトウェア)が持つグラフ描画機能をNumPyに持たせることを目的として作られています。

この方法では、画像を ndarray 型にしなくとも良いし、色順番も「RGB」のままでOKです。

実行すると以下になります。

いままでの画像との違いは目盛りが付いていることです。

先ほども言ったように、グラフを描画する機能を使っているので、単純に実行するとこうなります。

もし目盛りがいらないなら以下のように書きます。

from PIL import Image
from matplotlib import pyplot as plt

img_2 = Image.open('./test_photo/hana/001_800px.jpg')

plt.axis('off')
plt.imshow(img_2)
plt.show()

plt.axis('off’) と書くと目盛りが表示されなくなります。

実行すると以下になります。

目盛りが消えましたね。

ただし、matplotlib を使って画像表示すると画像の周りに余白が付きます。

余白を小さくする方法もありますが、今日はこの辺にしておきます。

最後に、じゃあ実際どの方法が一番良いの?と思うかもしれません。

これはケースバイケースです。

どんなタスクに使うかによって方法も変わってきます。

みなさんの一番使いやすい方法で使っていただければと思います。