Python, OpenCVで画像ファイルの読み込み、保存(imread, imwrite)
PythonのOpenCVで画像ファイルを読み込み・保存するにはcv2.imread()
, cv2.imwrite()
を使う。NumPy配列ndarray
として読み込まれ、ndarray
を画像として保存する。
ここでは、以下の内容について説明する。cv2.imread()
の注意点や画像ファイルが読み込めない場合の確認事項などは後半にまとめて述べる。
- カラー(BGR)で読み込み、保存
cv2.imread()
で画像ファイルから読み込みcv2.imwrite()
で画像ファイルに保存
- グレースケール(白黒)で読み込み、保存
cv2.imread()
で画像ファイルから読み込みcv2.imwrite()
で画像ファイルに保存
cv2.imread()
の注意点cv2.imread()
自体は例外を送出しない- JPEGの読み込み
cv2.imread()
で画像が読み込めないとき- カレントディレクトリの確認
cv2.imread()
の対応フォーマット
なお、OpenCVではなく画像処理ライブラリPillowを使って画像ファイルをndarray
として読み込むこともできる。以下の記事を参照。ndarray
の処理例なども紹介している。
静止画ではなく動画の読み込みについては以下の記事を参照。
例として以下の画像を使用する。
カラー(BGR)で読み込み、保存
cv2.imread()で画像ファイルから読み込み
カラー画像のファイルを読み込むと、行(高さ) x 列(幅) x 色(3)
の三次元のndarray
となる。
import cv2
im = cv2.imread('data/src/lena.jpg')
print(type(im))
# <class 'numpy.ndarray'>
print(im.shape)
# (225, 400, 3)
print(im.dtype)
# uint8
読み込まれたndarray
の色の順番はRGBではなくBGRなので注意。例として0番目(B:青)と1番目(G:緑)を0(黒)にしてみる。
im[:, :, (0, 1)] = 0
BGRとRGBを変換したい場合は以下の記事を参照。
cv2.imwrite()で画像ファイルに保存
ファイルのパスとndarray
オブジェクトを引数として指定する。ファイルのパスの拡張子から自動的にフォーマットが決定される。.jpg
ならJPEGで保存されるし、.png
ならPNGで保存される。
cv2.imwrite('data/dst/lena_opencv_red.jpg', im)
第三引数にフォーマット固有のパラメータを指定可能。[paramId_1, paramValue_1, paramId_2, paramValue_2, ...]
のように、リストで指定する。
パラメータのID(フラグ)は以下の公式ドキュメントを参照。
例えば、JPEGで保存する際の品質はcv2.IMWRITE_JPEG_QUALITY
で指定する。0
が最低で100
が最高、デフォルトは95
。
50
で保存した場合。
cv2.imwrite('data/dst/lena_opencv_red_low.jpg', im, [cv2.IMWRITE_JPEG_QUALITY, 50])
100
で保存した場合。
cv2.imwrite('data/dst/lena_opencv_red_high.jpg', im, [cv2.IMWRITE_JPEG_QUALITY, 100])
なお、JPEGは非可逆圧縮なので、最高品質の100
であっても保存した画像を再度読み込むと元の画素の値とは差分が生じる。元の画像をそのまま保存したい場合はPNGやBMPなどで保存する。
グレースケール(白黒)で読み込み、保存
cv2.imread()で画像ファイルから読み込み
cv2.imread()
の第二引数にcv2.IMREAD_GRAYSCALE
を指定すると、カラーの画像ファイルをグレースケール(白黒)で読み込むことができる。cv2.IMREAD_GRAYSCALE
は0
なので、0
を指定してもよい。
エッジを検出したりするような、色情報が必要ないときに便利。
この場合、行(高さ) x 列(幅)
の二次元のndarray
となる。
im_gray = cv2.imread('data/src/lena.jpg', cv2.IMREAD_GRAYSCALE)
# im_gray = cv2.imread('data/src/lena.jpg', 0)
print(type(im_gray))
# <class 'numpy.ndarray'>
print(im_gray.shape)
# (225, 400)
print(im_gray.dtype)
# uint8
カラーのまま読み込んでからcv2.cvtColor()
でグレースケールに変換することもできる。
cv2.IMREAD_GRAYSCALE
としたcv2.imread()
だとOpenCVで実装された変換処理ではなくコーデックに依存する変換処理が行われるため、プラットフォームによって結果が異なってしまう可能性がある。画素値を厳密に扱うような場合はcv2.cvtColor()
を使うほうが安全。詳細は以下の記事を参照。
cv2.imwrite()で画像ファイルに保存
行(高さ) x 列(幅)
の二次元のndarray
をcv2.imwrite()
の引数に指定すると、グレースケールの画像ファイルとして保存される。
cv2.imwrite('data/dst/lena_opencv_gray.jpg', im_gray)
カラー画像をグレースケールの画像ファイルとして保存したい場合は、cv2.cvtColor()
でグレースケールに変換してから保存すればよい。
なお、二次元配列(グレースケール)を保存したファイルを再度cv2.imread()
で読み込むと、各色(各チャンネル)が同じ値の三次元配列(カラー)として読み込まれる。自動的に二次元配列として読み込まれることはない。
im_gray_read = cv2.imread('data/dst/lena_opencv_gray.jpg')
print(im_gray_read.shape)
# (225, 400, 3)
import numpy as np
print(np.array_equal(im_gray_read[:, :, 0], im_gray_read[:, :, 1]))
# True
print(np.array_equal(im_gray_read[:, :, 1], im_gray_read[:, :, 2]))
# True
cv2.imread()の注意点
cv2.imread()自体は例外を送出しない
cv2.imread()
では存在しないパスを指定してもエラーにならずNone
が返される。OpenCV4.6.0
時点では警告は発せられる。
ndarray
として読み込まれていると思って何らかの操作をしたときにエラーが発生する。
im_not_exist = cv2.imread('xxxxxxx')
# [ WARN:[email protected]] global /tmp/opencv-20221012-82716-1q8maeo/opencv-4.6.0/modules/imgcodecs/src/loadsave.cpp (239) findDecoder imread_('xxxxxxx'): can't open/read file: check file path/integrity
print(im_not_exist)
# None
# print(im_not_exist.shape)
# AttributeError: 'NoneType' object has no attribute 'shape'
存在していてもOpenCVが対応していないファイルだと同様にNone
が返される。この場合は警告もなし。
im_not_supported = cv2.imread('data/src/sample.csv')
print(im_not_supported)
# None
画像が正しく読み込めたかどうかは以下のように判定できる。
if im_not_exist is not None:
print('Image is read.')
else:
print('Image is not read.')
# Image is not read.
if im_not_exist is None:
print('Image is not read.')
else:
print('Image is read.')
# Image is not read.
正しく読み込まれた場合。
im = cv2.imread('data/src/lena.jpg')
if im is not None:
print('Image is read.')
else:
print('Image is not read.')
# Image is read.
if im is None:
print('Image is not read.')
else:
print('Image is read.')
# Image is read.
JPEGの読み込み
以下のGitHubの回答にあるように、JPEGの処理に用いられるライブラリはOpenCVのバージョンやプラットフォームなどに依存するため、同じファイルを読み込んでも環境が異なると値に差分が生じる可能性がある。
Reading of JPEG images is not bit-exact operation. It depends on used library (libjpeg/libjpeg-turbo) and/or versions, platforms (x86/ARM), compiler options. imread and imwrite cause differences in image pixels · Issue #10887 · opencv/opencv
画素値を厳密に扱う場合は要注意。
cv2.imread()で画像が読み込めないとき
カレントディレクトリの確認
Pythonの組み込み関数open()
などと同様に、cv2.imread()
, cv2.imwrite()
では、ファイルのパスを、
- カレントディレクトリ(作業ディレクトリ)からの相対パス
- 絶対パス
のいずれかで指定する。
ファイルがあるはずなのに読み込めない場合、カレントディレクトリが想定と異なっているという単純なミスが原因であることが多い。
カレントディレクトリはos.getcwd()
で確認できる。
cv2.imread()の対応フォーマット
当然ながら、対応していないフォーマットの画像ファイルは読み込めない。
OpenCV4.2.0
のcv2.imread()
が対応しているフォーマットは以下の通り。リンク先のNotes
に書いてある注意事項も要確認。
- Windows bitmaps - .bmp, .dib (always supported)
- JPEG files - .jpeg, .jpg, *.jpe (see the Note section)
- JPEG 2000 files - *.jp2 (see the Note section)
- Portable Network Graphics - *.png (see the Note section)
- WebP - *.webp (see the Note section)
- Portable image format - .pbm, .pgm, .ppm .pxm, *.pnm (always supported)
- PFM files - *.pfm (see the Note section)
- Sun rasters - .sr, .ras (always supported)
- TIFF files - .tiff, .tif (see the Note section)
- OpenEXR Image files - *.exr (see the Note section)
- Radiance HDR - .hdr, .pic (always supported)
- Raster and Vector geospatial data supported by GDAL (see the Note section)
OpenCV: Image file reading and writing
他のバージョンは以下を参照。
- OpenCV 3.0.0: Image file reading and writing
- Reading and Writing Images and Video — OpenCV 2.4.13.0 documentation
その他のバージョンの公式ドキュメントは以下のリンクから。所望のバージョンをドキュメントを開き検索ボックスからimread
で検索すればヒットするはず。2.x.x
系は右側のSphinx HTML
の方が詳しい。
実際に実行している環境で使用されているライブラリなどの情報は、cv2.getBuildInformation()
で取得できるOpenCVのビルド情報のMedia I/O
の項目で確認できる。
なお、cv2.imread()
は拡張子ではなくファイルの中身からフォーマットを判定する。どうしても読み込めないという場合は、別のアプリケーションでそのファイルが正しく読み込めるかどうか(ファイルが壊れていないか)を確認してみるといいかもしれない。
The function determines the type of an image by the content, not by the file extension. OpenCV: Image file reading and writing