【OpenCV×Python】
画像の読み書きと加工 操作まとめ


(最終更新日:

記事イメージ

OpenCVは非常に多様な機能を備えるライブラリです。

本記事では、その中でも機械学習モデル開発などで役に立つ、Pythonによる基礎的な操作を紹介します。

OpenCVとは?

OpenCV(Open Source Computer Vision Library)はインテルにより開発されたオープンソースライブラリです。

画像処理に関する加工から始まり、図形、物体、エッジ検出等の様々な機能が織り込まれており、C++、Java、Pythonなど様々なプラットフォームでAPIが提供されています。

ライセンス

BSDライセンスが適用されます。BSDは、非コピーレフトかつ一定の条件(著作権表示等)の下で商用利用も可能なライセンスです。

参考:opencv/LICENSE(外部リンク)

実行環境へのインストール

通常環境


$ pip install opencv-python

conda環境の場合


$ conda install -c conda-forge opencv

importの指定

Python
import cv2

画像を開く~色彩変換~保存まで

ファイルを開いてnumpy.ndarray型(3次元配列)で取得

opencvでは、画像データはNumpy配列で取り扱いします。

Python
img = cv2.imread('/home/test.jpg')

3px四方に1行1pxずつ赤(R255 G0 B0)・緑(R0 G255 B0)・青(R0 G0 B255)のラインを配置した画像をペイントツールで作成。どのような配列になるか実験してみます。

テスト用の画像を作成。赤緑青を1行ずつ配置しています。3px四方。
テスト用の画像を作成

実際に読み込んでみると、結果は次の通りです。

横・縦・画素の3要素が1pxずつ3次元配列として表現されます。画素順番はBGRになっていることが分かります。

Python
#読み込み
img = cv2.imread('/home/rgb-test.png')
print(img)

#出力結果。BGRの順で1画素ずつ配列として並んでいます。
[[[  0   0 255], [  0   0 255], [  0   0 255]],
 [[  0 255   0], [  0 255   0], [  0 255   0]],
 [[255   0   0], [255   0   0], [255   0   0]]]

開いた画像の変換(グレースケール化、BGR→RGB等)

引き続き↑の3px四方のテスト画像(1行ずつ赤・緑・青を配置)を使用して、変換結果を見ていきます。

変換にはcv2.cvtColorを使用します。第1引数に画像配列、第2引数に変換コードを入れて実行します。

まず、グレースケール変換を行ってみます。カラー読み込みが3次元配列だったのが、2次元配列に変換されます。色情報が消失し、明るさのみの情報となっていることが分かります。

Python
#グレースケールに変換
img = cv2.imread('/home/rgb-test.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
print(img)

#出力結果
#色情報が消失し、明るさのみの情報(3次元配列→2次元配列)となりました。
[[ 76  76  76]
 [150 150 150]
 [ 29  29  29]]

続いて画素をBGR→RGBに変換します。

OpenCVはBGRがデフォルトですが、他のライブラリはRGBとなっている場合が多いので、組み合わせて使う場合は基本的に変換して使用することになります。

Python
#グレースケールに変換
img = cv2.imread('/home/rgb-test.png')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
print(img)

#出力結果
[[[255   0   0], [255   0   0], [255   0   0]],
 [[  0 255   0], [  0 255   0], [  0 255   0]],
 [[  0   0 255], [  0   0 255], [  0   0 255]]]

その他、cv2.cvtColorの第2引数のコードは多数用意されています。公式ドキュメントをご参照ください。

画像配列を画像ファイルとして保存

cv2.imwrite関数を使用します。BGR形式で保存されるので、RGB配列を保存する場合は事前に変換する必要があります。

尚、戻り値は保存の成否がBool値で返されます。

Python
#保存処理
result = cv2.imwrite('/home/rgb-test-new.png', img)
print(result)

#出力結果。保存成否がBool値で返される。
True

【社内PR】チーム・ウォーク

読み込んだ画像を表示する

ウィンドウで画像を表示

ローカル実行環境でウィンドウで画像を表示します。(Google Colaboratoryではこの表示方法は使えません。次のセクションで代替法を解説します。)

Python
cv2.imshow('window-name', img)

表示結果。ウィンドウで開きます。
表示結果

実行環境によっては、cv2.imshowでウィンドウが開いた後フリーズする場合があります。(Windowsなら「応答なし」となりますが、Macでも同様の現象が出ます)

この場合、次のコードのようにcv2.waitKey()を追加で実行することで解決します。画像表示中、キーの応答待ちとするコードです。

Python
cv2.imshow('window-name', img)
cv2.waitKey()

cv2.waitKey関数の有無で表示ができるかどうかが異なった結果。
cv2.waitKey関数の有無で表示ができるかどうかが異なった結果

Google Colaboratoryで画像を表示

Google Colaboratoryでは、imshow関数は使用できません。

代わりに標準出力に画像を表示するcv2_imshow関数を使用することができます。

Python
import cv2
from google.colab.patches import cv2_imshow
img = cv2.imread('2.png')
cv2_imshow(img)

cv2_imshow関数による表示結果。(Google Colaboratoryにて実行)
cv2_imshow関数による表示結果

複数の画像を同時に表示

cv2.hconcat(平行方向に画像を結合)またはcv2.vconcat(垂直方向に画像を結合)で画像を結合することで、複数の画像を同時に表示できます。

Python
import cv2
from google.colab.patches import cv2_imshow
img = cv2.imread('2.png')
img = cv2.hconcat([img, img, img])
cv2_imshow(img)

hconcatで複数画像を水平方向に結合することで、同時表示を実現する。
hconcatで複数画像を水平方向に結合することで、同時表示を実現する

画像の加工(リサイズ、トリミング、回転)

img変数はcv2.imread関数で読み込んだNumpy配列です。

画像のリサイズ

Python
#第2引数にリサイズ後のpxを指定
img = cv2.resize(img, (width, height))

画像のトリミング

Python
#順番に、起点y座標、終点y座標、起点x座標、終点x座標
img = img[y_from:y_to, x_from:x_to]

画像の向きと座標の関係、トリミング処理結果イメージ
画像の向きと座標の関係、トリミング処理結果イメージ

画像を90度・180度回転

cv2.rotate関数を使用します。90度・180度以外の任意の角度の回転については、次のセクションに掲載しています。

Python
#時計回りに90度回転
img = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
#半時計回りに90度回転
img = cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
#半時計回りに90度回転
img = cv2.rotate(img, cv2.ROTATE_180)

cv2.rotateの第2引数別の実行結果
cv2.rotateの第2引数別の実行結果

画像を反転(上下・左右)

cv2.flip関数を使用します。第2引数はInt値で指定し、0で上下反転、正の値(1以上)で左右反転、負の値(-1以下)で上下左右反転となります。

Python
#左右反転
img = cv2.flip(img, 1)
#上下反転
img = cv2.flip(img, 0)
#上下左右反転
img = cv2.flip(img, -1)

cv2.flipの第2引数別の実行結果
cv2.flipの第2引数別の実行結果

ちなみに、左右・上下反転であれば、尚、OpenCVの機能を使わずとも次のようにNumpyの次元組み換えを行うことでも実現可能です。

Python
#左右反転
img = img[:, ::-1]
#上下反転
img = img[::-1]

ここで使用した画像配列の次元組み換えテクニックは、例えば色素入替などにも使用可能です。

次のコードはBGRの順を5パターン(RGBの並び替えパターンは3!=6パターンなので、初期値を除く5パターン)に組み替えています。

Python
img = img[:, :, [2, 1, 0]]
img = img[:, :, [0, 1, 2]]
img = img[:, :, [1, 0, 2]]
img = img[:, :, [2, 0, 1]]
img = img[:, :, [1, 2, 0]]

色素入替結果(白はRGBを入れ替えても白のままですが、背景の色はシフトしています。
色素入替結果(白はRGBを入れ替えても白のままですが、背景の色はシフトしています

画像を任意の角度で回転

OpenCVに組み込まれているアフィン変換(行列計算に基づく座標変換)の計算ロジックを利用します。

Python
#変換行列を生成。引数は順にcenter(中心座標)、degree(回転角度0~360度)、scale(拡大比率)
matrix = cv2.getRotationMatrix2D((0, 0), 30, 1)

#変換実行。引数は順にsrc(画像配列)、M(変換行列)、dsize(出力画像width,height)、flags(補間方法)
img = cv2.warpAffine(img, matrix, (380, 380), cv2.INTER_LINEAR)

#尚、第4引数の補完方法の候補は次の通り。リサイズの仕上がりの質感に差が出る。
#デフォルトはcv2.INTER_LINEAR。まずデフォルトで試し、画像の性質によってチョイスすればよい。
cv2.INTER_NEAREST #最近傍内挿
cv2.INTER_LINEAR #線型内挿
cv2.INTER_CUBIC #3次畳み込み内挿
cv2.INTER_AREA #ピクセル領域の関係を用いたリサンプリング処理
cv2.INTER_LANCZOS4 #Lanczos内挿

上記コードの変換結果。(x, y)=(0, 0)=画像の左上を中心に、30度回転させた。
上記コードの変換結果

トラブルシューティング:ファイルが存在しているのエラー:にcan't open/read fileが発生

cv2.imreadコール時に"can't open/read file: check file path/integrity"という例外がスローされる場合があります。尚、このエラーは本来は指定されたパスにファイルが存在しない場合に発生しますが、ファイルが確かに存在するのにこのエラーが出る場合があります。

Python
img = cv2.imread('C:/Users/sakai/Desktop/画像.png')

エラー内容例:

[ WARN:0@4944.553] global D:\bld\libopencv_1641992799878\work\modules\imgcodecs\src\loadsave.cpp (239) cv::findDecoder imread_('C:/Users/sakai/Desktop/画像.png'): can't open/read file: check file path/integrity

結論としては、ファイルパス(ファイル名含む)に日本語文字を含んでいることが原因と思われます。

オープンする方法はなくはないですが、先ずは半角英数字のみのパスに移動することを検討しましょう。

記事筆者へのお問い合わせ、仕事のご依頼

当社では、IT活用をはじめ、業務効率化やM&A、管理会計など幅広い分野でコンサルティング事業・IT開発事業を行っております。

この記事をご覧になり、もし相談してみたい点などがあれば、ぜひ問い合わせフォームまでご連絡ください。

皆様のご投稿をお待ちしております。

記事筆者へ問い合わせする

※ご相談は無料でお受けいたします。

この記事へのコメント

ニックネーム(任意)

返信通知先Emailアドレス(任意)

本文


* 感想やご意見等、お気軽にコメントください。但し、公序良俗に反するコメントはお控えください。
* 管理者が承認したコメントはこの箇所に公開させていただく可能性がございます。
* 返信通知先Emailアドレスは、筆者のみに通知され、公開されることはありません。返信通知先Emailを入力された場合は、コメントへの返信をこちらに掲載した際に通知させていただきます。その他の目的には使用いたしません。
* スパム対策のため、コメントは日本語のみ受け付けております。

堺財経電算合同会社 小規模IT構築サービス