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)のラインを配置した画像をペイントツールで作成。どのような配列になるか実験してみます。
実際に読み込んでみると、結果は次の通りです。
横・縦・画素の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
読み込んだ画像を表示する
ウィンドウで画像を表示
ローカル実行環境でウィンドウで画像を表示します。(Google Colaboratoryではこの表示方法は使えません。次のセクションで代替法を解説します。)
Python
cv2.imshow('window-name', img)
実行環境によっては、cv2.imshowでウィンドウが開いた後フリーズする場合があります。(Windowsなら「応答なし」となりますが、Macでも同様の現象が出ます)
この場合、次のコードのようにcv2.waitKey()を追加で実行することで解決します。画像表示中、キーの応答待ちとするコードです。
Python
cv2.imshow('window-name', img)
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.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)
画像の加工(リサイズ、トリミング、回転)
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.flip関数を使用します。第2引数はInt値で指定し、0で上下反転、正の値(1以上)で左右反転、負の値(-1以下)で上下左右反転となります。
Python
#左右反転
img = cv2.flip(img, 1)
#上下反転
img = cv2.flip(img, 0)
#上下左右反転
img = cv2.flip(img, -1)
ちなみに、左右・上下反転であれば、尚、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]]
画像を任意の角度で回転
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内挿
トラブルシューティング:ファイルが存在しているのエラー:に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開発事業を行っております。
この記事をご覧になり、もし相談してみたい点などがあれば、ぜひ問い合わせフォームまでご連絡ください。
皆様のご投稿をお待ちしております。