note.nkmk.me

Python, OpenCVで画像ファイルの読み込み、保存(imread, imwrite)

Date: 2018-01-12 / Modified: 2020-01-23 / tags: Python, OpenCV, 画像処理

PythonのOpenCVで画像ファイルを読み込み、保存するにはcv2.imread()cv2.imwrite()を使う。NumPy配列ndarrayとして読み込まれ、ndarrayを画像として保存する。

ここでは以下の内容について説明する。cv2.imread()の注意点や画像ファイルが読み込めない場合の確認事項などは後半にまとめて述べる。

  • カラー(BGR)で読み込み、保存
    • cv2.imread()で画像ファイルから読み込み
    • cv2.imsave()で画像ファイルに保存
  • グレースケール(白黒)で読み込み、保存
    • cv2.imread()で画像ファイルから読み込み
    • cv2.imsave()で画像ファイルに保存
  • cv2.imread()の注意点
    • cv2.imread()自体は例外を送出しない
    • JPEGの読み込み
  • cv2.imread()で画像が読み込めないとき
    • カレントディレクトリの確認
    • cv2.imread()の対応フォーマット

なお、OpenCVではなく画像処理ライブラリPillowを使って画像ファイルをndarrayとして読み込むこともできる。以下の記事を参照。ndarrayの処理例なども紹介している。

例として以下の画像を使用する。

lena

スポンサーリンク

カラー(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

lena red

BGRとRGBを変換したい場合は以下の記事を参照。

cv2.imsave()で画像ファイルに保存

ファイルのパスとndarrayオブジェクトを引数として指定する。ファイルのパスの拡張子から自動的にフォーマットが決定される。.jpgならJPEGで保存されるし、.pngならPNGで保存される。

cv2.imwrite('data/dst/lena_opencv_red.jpg', im)

lena red

第三引数にフォーマット固有のパラメータを指定可能。[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])

lena red low quality

100で保存した場合。

cv2.imwrite('data/dst/lena_opencv_red_high.jpg', im, [cv2.IMWRITE_JPEG_QUALITY, 100])

lena red high quality

なお、JPEGは非可逆圧縮なので、最高品質の100であっても保存した画像を再度読み込むと元の画素の値とは差分が生じる。元の画像をそのまま保存したい場合はPNGやBMPなどで保存する。

グレースケール(白黒)で読み込み、保存

cv2.imread()で画像ファイルから読み込み

cv2.imread()の第二引数にcv2.IMREAD_GRAYSCALEを指定することで、カラーの画像ファイルをグレースケール(白黒)で読み込むことができる。cv2.IMREAD_GRAYSCALE0なので、0を指定してもOK。

エッジを検出したりするなど、色情報が必要ないときに便利。

この場合、行(高さ) 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

カラーのまま読み込んでからcvtColor()でグレースケールに変換することもできる。

cv2.IMREAD_GRAYSCALEとしたcv2.imread()だとOpenCVで実装された変換処理ではなくコーデックに依存する変換処理が行われるため、プラットフォームによって結果が異なってしまう可能性がある。画素値を厳密に扱うような場合はcv2.cvtColor()を使うほうが安全。詳細は以下の記事を参照。

cv2.imsave()で画像ファイルに保存

保存するときはグレースケールでも特に指定する必要はなく、カラーの場合と同じくcv2.imsave()にファイルのパスとndarrayオブジェクトを引数として指定する。第三引数にフォーマット固有のパラメータを指定することも可能。

cv2.imwrite('data/dst/lena_opencv_gray.jpg', im_gray)

lena gray

なお、二次元配列(グレースケール)を保存したファイルを再度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が返される。ndarrayとして読み込まれていると思って何らかの操作をしたときにエラーが発生する。

im = cv2.imread('xxxxxxx')

print(im)
# None

# print(im.shape)
# AttributeError: 'NoneType' object has no attribute 'shape'

存在していてもOpenCVが対応していないファイルだと同様にNoneが返される。

im = cv2.imread('data/src/sample.csv')

print(im)
# None

NoneFalseとみなされるので、画像が正しく読み込めたかどうかは以下のように判定できる。

im = cv2.imread('xxxxxxx')

if im:
    print('Image is read.')
else:
    print('Image is not read.')
# Image is not read.
im = cv2.imread('xxxxxxx')

if not im:
    print('Image is not read.')
else:
    print('Image is read.')
# Image is not 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.0cv2.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

他のバージョンは以下を参照。

その他のバージョンの公式ドキュメントは以下のリンクから。所望のバージョンをドキュメントを開き検索ボックスから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

スポンサーリンク
シェア
このエントリーをはてなブックマークに追加

関連カテゴリー

関連記事