OpenCVで画像ファイルを開くとき、ファイル名やパスに日本語が含まれていると、画像ファイルを開いてくれません。
試しに以下のようなコードを実行すると、エラーが起き実行できません。
import cv2
# OpenCVで画像ファイルを開く(ファイル名が日本語)
img = cv2.imread("画像ファイル.bmp", cv2.IMREAD_UNCHANGED)
cv2.imshow("Image", img)
cv2.waitKey(0)
エラー情報
Message=OpenCV(4.5.3) C:\Users\runneradmin\AppData\Local\Temp\pip-req-build-sn_xpupm\opencv\modules\imgproc\src\color.cpp:182:
error: (-215:Assertion failed) !_src.empty() in function 'cv::cvtColor'
エラーそのものはimread関数で画像ファイルを開くのに失敗し、戻り値の画像データ(img)が空(None)になっているため、エラーが発生しています。
日本語の画像ファイルを開くためには、PillowもしくはNumPyで画像ファイルを開いてOpenCVの画像データであるNumPyのndarray形式に変換すれば、OpenCVで日本語の画像ファイルを扱えるようになります。
Pillowで画像ファイルを開き、OpenCV(NumPyのndarray)に変換する
import cv2
import numpy as np
from PIL import Image
# Pillowで画像ファイルを開く
pil_img = Image.open("画像ファイル.bmp")
# PillowからNumPyへ変換
img = np.array(pil_img)
# カラー画像のときは、RGBからBGRへ変換する
if img.ndim == 3:
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
cv2.imshow("Image", img)
cv2.waitKey(0)
Pillowで画像ファイルを開くと、カラー画像の場合、RGBの順でデータが格納されるので、cvtColorを用いて、OpenCVの形式(BGR)へ変換します。
PillowからNumPyの画像データへ変換する方法は下記ページを参照ください。
NumPyで画像ファイルを開き、OpenCV(NumPyのndarray)に変換する
import cv2
import numpy as np
from PIL import Image
import time
start = time.perf_counter()
# NumPyで画像ファイルを開く
buf = np.fromfile("画像ファイル.bmp", np.uint8)
img = cv2.imdecode(buf, cv2.IMREAD_UNCHANGED)
print((time.perf_counter() - start) * 1000)#, "msec")
cv2.imshow("Image", img)
cv2.waitKey(0)
NumPyのfromfileで画像ファイルをバイナリで開き、ファイルの中身をメモリ(buf)に格納します。
OpenCVのimdecodeでメモリ上の画像データをOpenCVの画像データ(NumPyのndarray)に変換します。
OpenCVからPillowへ変換し画像ファイルに保存する
import cv2
from PIL import Image
# OpenCVで画像ファイルを開く(ファイル名に日本語が無い場合)
img = cv2.imread("image_file.bmp", cv2.IMREAD_UNCHANGED)
# カラー画像のときは、BGRからRGBへ変換する
if img.ndim == 3:
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# NumPyからPillowへ変換
pil_image = Image.fromarray(img)
# Pillowで画像ファイルへ保存
pil_image.save("画像ファイル_pillow.bmp")
Pillowで画像ファイルを開いたときの逆の事をすると、日本語のファイル名でも画像ファイルに保存することができます。
OpenCVの画像データ(ndarray)を画像形式に変換しファイルに保存する
import cv2
import numpy as np
# OpenCVで画像ファイルを開く(ファイル名に日本語が無い場合)
img = cv2.imread("image_file.bmp", cv2.IMREAD_UNCHANGED)
# 画像データを画像ファイル形式のメモリ変換する
ret, buf = cv2.imencode(".bmp", img)
# NumPyで画像ファイルへ保存
with open("画像ファイル_numpy.bmp", mode='w+b') as f:
buf.tofile(f)
OpenCVの画像データ(NumPyのndarray)をimencodeで画像ファイル形式にメモリ上で変換し、NumPyのtofileで画像ファイルに書き込みます。
まとめ
日本語の画像ファイルの読込・保存をするのにPillowおよびNumPyを介して処理を行いましたが、それぞれの処理時間を比較しました。
処理時間は8192×8192画素のカラー画像を5回処理したときの平均時間です。
方法 | 平均処理時間(msec) |
Pillowで画像ファイルを開く | 513 |
NumPyで画像ファイルを開く | 210 |
Pillowで画像ファイルへ保存 | 337 |
NumPyで画像ファイルへ保存 | 1106 |
これを見ると、日本語ファイル名の画像を開くときは、NumPy、保存するときはPillowを使った方が速い結果になりました。
NumPyで保存するときが極端に遅かったので、関数ごとの処理時間を見てみたところ、imencodeに約100msec、tofileに約1000msecという時間でした。
画像の読込と保存でPillowとNumPyを使い分けるのは、少々面倒ですが、処理時間もそれなりに違うので、画像の読込はNumPy、保存はPillowを使った方がいいかもしれません。
コメント