OpenCV

【OpenCV/Python】日本語の画像ファイル読込・保存

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の画像データへ変換する方法は下記ページを参照ください。

【Python】画像データ(NumPy,Pillow(PIL))の相互変換
Pythonで画像処理をしていると、画像データの扱いは各ライブラリによって、NumPyのndarrayかPillowのPIL.Imageのどちらかになる場合が多いかと思います。 そこで NumPyとPillowの画像データの相互変換をまとめ...

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を使った方がいいかもしれません。

コメント

タイトルとURLをコピーしました