Web 上の画像をダウンロードして画像処理する場合など、バイナリ形式の画像データを直接 OpenCV で扱う方法について説明します。
一度バイナリデータをローカルに保存してから cv2.imread()
する方法ももちろんありますが、NumPy と OpenCV の関数を駆使すれば、保存にかかる処理を飛ばしてシンプルに画像を扱うことができます。
本記事のポイントは次の2点です。
np.frombuffer()
で画像のバイナリデータを NumPy 配列に変換しますcv2.imdecode()
で 配列の shape を整えますOpenCV と NumPy はインストールされているものとします。
まずは必要なモジュールを import します。
import urllib.request
import numpy as np
import cv2
画像をダウンロードします。urllib.request.Request()
の引数は所望の URL に置き換えてください。
body に画像のバイナリデータが格納されます。
req = urllib.request.Request('<画像の URL>')
with urllib.request.urlopen(req) as res:
body = res.read()
次に np.frombuffer()
でバイナリデータを NumPy 配列(ndarray
)に変換します。ただしこの段階では、配列の次元数が 1 となっており OpenCV で正常に扱える形ではないので、cv2.imdecode()
で次元数と shape を整えます。
arr = np.frombuffer(body, dtype=np.uint8)
img = cv2.imdecode(arr, flags=cv2.IMREAD_COLOR)
shape を確認してみると次のようになります(画像によって結果は異なります)。
print(arr.shape)
# (110882,)
print(img.shape)
# (700, 1000, 3)
なお、cv2.imdecode()
の引数 flags
についてですが、BGR のカラー画像として扱う場合は flags=cv2.IMREAD_COLOR
、グレースケール画像として扱う場合は flags=cv2.IMREAD_GRAYSCALE
を指定します(この flags
の指定は cv2.imread()
と同様です)。
これで OpenCV で扱える形になりました。試しに cv2.imshow()
を使って画像を表示してみます。
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
Web の情報を漁ると Pillow (PIL) を使っている方法も見かけましたが、上記のように NumPy と OpenCV だけで実現できるので、わざわざこれだけのために Pillow をインストールする必要はありません。
import urllib.request
import numpy as np
import cv2
req = urllib.request.Request('<画像の URL>')
with urllib.request.urlopen(req) as res:
body = res.read()
arr = np.frombuffer(body, dtype=np.uint8)
img = cv2.imdecode(arr, flags=cv2.IMREAD_COLOR)
cv2.imshow('image', img)
cv2.waitKey(0)
cv2.destroyAllWindows()