PythonでOpenCVを使って画像入出力する方法について解説します。
Contents
OpenCVによる画像入出力
OpenCVは、有名なコンピュータービジョンのライブラリです。OpenCVのPythonバインドであるcv2
モジュールを使用することで、PythonでOpenCVの機能を使用することができます。
OpenCVでは、画像の入出力のための関数として、imread
関数とimwrite
関数を提供しています。これらの関数は様々なファイルフォーマット(BMP, PNG, JPEG, TIFF等)の画像をサポートしています。
この記事では、PythonでOpenCVを使って画像入出力する方法について紹介します。
cv2モジュールでの画像表現
OpenCVのPythonバインドであるcv2
モジュールでは、画像はNumpyの配列(ndarray
)を使って表現されています。NumPyは、Pythonで高速な数学的演算を可能にするライブラリで、特に大量のデータに対する効率的な操作と計算を提供します。
OpenCVにおいて、カラー画像は以下のようなデータ構造として表現されています。
img
という画像配列を作成したとしましょう。この時、水平(列)方向をx
、垂直(行)方向をy
、カラーチャンネルをchannel
とすると、各ピクセルにアクセスするための引数の位置としてはimg[y, x, channel]
となります。例えば、img[0, 1, 2]
とすると、0
行、1
列の赤(R
)チャンネルのピクセル値を表します。
OpenCVでは、BGRというカラー順が標準的な構造となっています。RGBという順番の方が感覚的に分かりやすい人がいると思いますが、これはOpenCVが開発され始めた当初、BGRの色順が一般的なハードウェアで採用されていたなどの背景によるもので、互換性を保つためにBGRが標準となっています。ただし、必要に応じてcv2.cvtColor(image, cv2.COLOR_BGR2RGB)
というようにRGB順に変換することも可能です。
実際のどのようなデータ構造になるか簡単な例で確認してみましょう。
import cv2 import numpy as np # NumPyのndarrayを生成 img = np.ones((5, 5), dtype=np.uint8) print(img) print(type(img)) print(img.dtype) print(img.shape, "\n") # グレースケール → カラー画像へ変換 img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) print(img) print(type(img)) print(img.dtype) print(img.shape)
【実行結果】 [[1 1 1 1 1] [1 1 1 1 1] [1 1 1 1 1] [1 1 1 1 1] [1 1 1 1 1]] <class 'numpy.ndarray'> uint8 (5, 5) [[[1 1 1] [1 1 1] [1 1 1] [1 1 1] [1 1 1]] [[1 1 1] [1 1 1] [1 1 1] [1 1 1] [1 1 1]] [[1 1 1] [1 1 1] [1 1 1] [1 1 1] [1 1 1]] [[1 1 1] [1 1 1] [1 1 1] [1 1 1] [1 1 1]] [[1 1 1] [1 1 1] [1 1 1] [1 1 1] [1 1 1]]] <class 'numpy.ndarray'> uint8 (5, 5, 3)
上記サンプルでは、NumPyでグレースケール画像を想定して5×5画像配列をones
関数を使用して作成しています。この配列は、NumPyのnumpy.ndarray
型の配列です。dtype
で型を確認するとuint8
となっています。また、配列形状はshape
を使って確認でき(5, 5)
であることが確認できます。dtype
やshape
は画像の情報を得るうえでよく使用するので覚えておきましょう。
このグレースケール画像をcv2.cvtColor
関数を使用して、カラー画像に変換しています。shape
を見てみると分かりますが(5, 5, 3)
です。最初に説明したように水平(列)方向をx
、垂直(行)方向をy
、カラーチャンネルをchannel
とすると(y, x, channel)
となっています。また、カラーチャンネルの順番はBGRであることに注意してください。
OpenCVでは、このように画像表現がされることをまずは理解しておいてください。以降では、imread
やimwrite
を使用した画像入出力の具体例を紹介します。
imread、imwriteによる画像の読み込み、書き込み
ここでは、imread
関数及びimwrite
関数を用いた画像の読み込みや書き込みについて紹介します。
基本的な使い方
imread
を使用して画像を読み込み、imwrite
を使用して別ファイルとして書き込みを行ってみましょう。imread
やimwrite
は、以下のように使用します。
import cv2 # 画像ファイルを読み込む img = cv2.imread("lena.jpg") print(img) print(type(img)) print(img.dtype) print(img.shape) # 画像ファイルを書き込む cv2.imwrite("lena_output.png", img)
【実行結果】 [[[128 138 225] [127 137 224] [126 136 224] ... [126 145 236] [110 129 220] [ 86 104 197]] ...(途中省略)... [[ 56 19 81] [ 58 21 83] [ 68 34 98] ... [ 81 68 176] [ 81 72 183] [ 84 74 188]]] <class 'numpy.ndarray'> uint8 (512, 512, 3)
まず、OpenCVの機能を使用するためにcv2
モジュールをインポートしておきます。
画像ファイルを読み込むには、cv2.imread("lena.jpg")
という形で、JPG画像ファイルのパスを指定します。今回の例では、画像処理でよく出てくるレナの画像を使用していますが、皆さんのお好きな任意の画像を指定してください。imread
で指定するパスは、絶対パスや相対パスで指定できます。
取得した画像のdtype
、shape
等を確認して見てみるとuint8
の(512, 512, 3)
のカラー画像となっていることが分かります。
上記の例では、読み込んだJPGファイルを別のPNGファイルへ保存しています。画像ファイルの書き込みの際には、cv2.imwrite("lena_output.png", img)
という形で、出力ファイルパスと画像データ(img
)を渡します。
imwrite
は、BGRまたはグレースケールの画像である必要があり、出力に指定する画像フォーマットに適した値である必要があります。例えば、BMP画像であれば1チャンネル 8bitといった形です。
オプションを指定する
imread
を使用する際に、読み込みのオプション指定をすることが可能です。例えば、元ファイルがカラーである画像をグレースケールで読み込む場合は、以下のようにします。
import cv2 # 画像ファイルを読み込む img = cv2.imread("lena.jpg", cv2.IMREAD_GRAYSCALE) print(img) print(type(img)) print(img.dtype) print(img.shape) # 画像ファイルを書き込む cv2.imwrite("lena_gray_output.png", img)
【実行結果】 [[163 162 161 ... 170 154 130] [162 162 162 ... 173 155 126] [162 162 163 ... 170 155 128] ... [ 43 42 51 ... 103 101 99] [ 41 42 55 ... 103 105 106] [ 42 44 57 ... 102 106 109]] <class 'numpy.ndarray'> uint8 (512, 512)
上記のように、cv2.IMREAD_GRAYSCALE
というオプション情報をファイルパスに続いて指定することでグレースケールで読み込むことができます。shape
で形状を見てみると(512, 512)
となっておりグレースケールの画像となっていることが分かります。imwrite
で出力した画像を見ていただければグレースケールに変換されていることが確認できます。
なお、デフォルトのオプションとしては、cv2.IMREAD_COLOR
となっています。他にも指定できるオプションがいくつかありますが、それらのオプションについては、OpenCVのドキュメントにあるImreadModesの部分を参照してください。
画像をbytearrayに変換する
画像データを扱う際にバイト列に変換して扱うと便利なケースがあります。例えばデータをシリアライズしての保存したり、ネットワーク越しに送受信したりする場合等です。ここでは、画像として読み込んだデータをbytearray
に変換する方法を紹介します。
import cv2 import numpy as np # 画像ファイルを読み込む img = cv2.imread("lena.jpg") img_shape = img.shape img_dtype = img.dtype # bytearrayに変換する bgr_bytearray = bytearray(img.tobytes()) print(bgr_bytearray) print(len(bgr_bytearray), "\n") # bytearrayからnumpy.ndarrayに戻す # bgr_img = np.array(bgr_bytearray, dtype=np.uint8).reshape(512, 512, 3) bgr_img = np.array(bgr_bytearray, dtype=img_dtype).reshape(img_shape) print(bgr_img) print(bgr_img.shape) # 画像ファイルを書き込む cv2.imwrite("lena_output_byte.png", bgr_img)
【実行結果】 bytearray(b'\x80\x8a\xe1\x7f\x89\xe0~\x88\xe0}\x87 ...(途中省略)... \x18b=\x1ddC#jI,uK0zM4~N8\x86[E\x97S@\x97VE\xa0YJ\xacSF\xacQD\xb0QH\xb7TJ\xbc') 786432 [[[128 138 225] [127 137 224] [126 136 224] ... [126 145 236] [110 129 220] [ 86 104 197]] ...(途中省略)... [[ 56 19 81] [ 58 21 83] [ 68 34 98] ... [ 81 68 176] [ 81 72 183] [ 84 74 188]]] (512, 512, 3)
上記例では、読み込んだ画像をPythonのbytearray
へ変換し、その後に元に戻して画像出力する一連の流れを実行しています。
bytearray
へ変換する際には「bgr_bytearray = bytearray(img.tobytes())
」というように読み込んだ画像(img
)を渡しています。ここで渡す際にはtobytes()
でバイト列にしてから渡しています。
bytearray
からNumPyのndarray
に戻す際には「bgr_img = np.array(bgr_bytearray, dtype=img_dtype).reshape(img_shape)
」というようにnumpy.array
を使用します。この際には、dtype
で適切なデータ型を渡すことが重要です。また、形状を戻すにはreshape
に形状を渡します。
今回の例では読み込み時に変数に情報を取得しておいて渡しましたが、コメントアウトしてある行のように「bgr_img = np.array(bgr_bytearray, dtype=np.uint8).reshape(512, 512, 3)
」というように指定していただいても構いません。
以上のようにすることで、必要に応じて画像データをbytearray
に変換して扱うことも可能です。
まとめ
PythonでOpenCVを使って画像入出力する方法について解説しました。
OpenCVでは、画像の入出力のための関数として、imread
関数とimwrite
関数を提供しています。これらの関数は様々なファイルフォーマット(BMP, PNG, JPEG, TIFF等)の画像をサポートしています。
この記事では、OpenCVにおける画像表現の基本を最初に説明した後に、imread
とimwrite
の基本的な使い方を紹介しました。また、必要に応じてバイト列のbytearray
に変換する方法についても説明しています。
OpenCVは、非常に強力なコンピュータビジョンのライブラリで、画像の入出力は画像を扱うにあたっての基本となります。しっかりと使い方を理解していただきたいと思います。