Python/OpenCVを使った画像処理において、最も簡単な二値化処理をすることで画像処理プログラミングの基本を学びます。この処理を通して、画像読み込み→処理→表示→保存の一連のプロセスを習得します。
こんにちは。wat(@watlablog)です。
Python/OpenCVで画像処理を学んでいます。本日は簡単な二値化処理で画像処理の基本を習得します!
PythonでOpenCVを使うための詳細説明は「Pythonで画像処理!OpenCVのメリットとインストール法」をご覧下さい。
画像処理の基本を二値化で学ぶ
コンピュータにおける画像データ
実際に画像処理をする前に、コンピュータで扱う画像データの概要を説明します。
以下の図にビットマップファイル等における一般的な画像データの座標の考え方を示します。画像は横軸が\(x\)軸, 縦軸が\(y\)軸で、その多くが昔のコンソール時代の名残で\(y\)は下の方に増分していく形式をとります。
※ここでは代表的な形式のみ説明しています。座標系や軸の方向は異なる画像フォーマットもあります。
この\((x, y)\)で表された位置にはそれぞれピクセル(Pixel)があります。
このピクセルは日本語で画素という意味であり、この1つ1つのピクセルに輝度が与えられることで全体の画像を構成します。
輝度はカラー画像やグレースケール画像でも基本的な考え方は同じで、色の濃さを意味しています。
色の濃さには階調と呼ばれる尺度を用います。下の図はコンピュータで色を表現するための階調とビットの関係を示しています。
階調は表現できる色の個数で分類でき、白と黒の2値しか表現できないものを2階調、表現度を高め256個の色を段階的に表現可能にしたものを256階調と呼びます。
コンピュータは0と1で全てを表現するため、2進数で表します。2階調であれば0と1の2つなので\(2=2^{1}\)から桁数は1つあれば足ります。この桁数がビット(bit)数を意味し、2階調であれば1ピクセル当り1bit、256階調であれば\(256=2^{8}\)から1ピクセル当り8bit(1byte)必要です。
二値化とは?
二値化とは、グレースケールで表された画像を0(黒)と1(白)のみに変換することを指します。
以下の図は256階調画像の二値化処理概要図です。
元画像を二値化するためには閾値(Threshold)を設ける必要があります。閾値を境に0と1に各ピクセルの輝度が振り分けられたものが二値化画像です。
Python/OpenCVの二値化処理コード
importするパッケージ
import文でOpenCV(cv2)とmatplotlibをインポートします。
matplotlibは画像表示にも便利なパッケージですので使ってみます。
1 2 |
import cv2 from matplotlib import pyplot as plt |
画像の読み込み
元画像はコードが走る場所と同じ階層に入れています。画像のパスを設定して、imread関数で読み込みます。
1 2 |
path = 'lena.jpg' # 画像のパス i = cv2.imread(path, 0) # 画像読み込み |
imread関数の第2引数が0になっていますが、これは画像をグレースケールで読み込むという指示をしています。
この値を1にするとカラー画像になります。しかし、二値化処理にはグレースケール画像が必要なので、この引数は0にしておく必要があります。
コラム:レナ(画像データ)とは?
本ページではlena.jpgという画像ファイルを使っています。このlenaとはレナ・ソーダバーグ(Lena Soderberg)さんのことで、デジタル画像処理分野では頻繁に標準テストイメージとして使われています。この画像は通称レナと呼ばれています。
元々はPLAYBOY誌(1950年代頃のアメリカで発行されていた成人向け雑誌)に掲載されていたヌード写真でしたが、人の顔があり、帽子の麻部分や装飾が高周波成分を多く含む、背景がぼやけている、鏡に人物の後ろ姿が映っている、美人である、といった様々な理由から広く画像処理の分野で使われているそうです。
当時は著作権の関係で一悶着あったそうですが、最終的には公共の利用のため、PLAYBOY社が画像の使用を許可したとのことです。
ちなみに、全身画像じゃないのは512×512のサイズが欲しかったからなんだって。ほんとかな?
二値化処理
二値化処理は以下のコードを使います。cv2.thresholdの
第1引数はグレースケール画像、
第2引数は閾値、
第3引数は画像輝度の最大値、
第4引数は二値化のタイプ
をそれぞれ意味しています。このcv2.threshold関数の第1戻り値retはこの処理では単純に設定した閾値が返ってきます。この値はより高度な閾値処理のために使われるとのことなので、ここでは説明を省きます。
1 2 3 |
th = 127 # 閾値 i_max = 255 # 最大輝度値 ret, i_binary = cv2.threshold(i, th, i_max, cv2.THRESH_BINARY) # 二値化処理 |
以下が元画像から二値化処理までの段階毎の処理を示した図です。
第4引数は以下の図の(b)-(f)に記載の文に変更することで、様々な変換を行うことが出来ます。
画像の保存
画像保存はcv2.imwriteで出力先のパスと画像データを指定します。
1 2 |
path_o = 'lena_binary.jpg' # 出力画像のパス cv2.imwrite(path_o, i_binary) # 画像保存 |
表示設定
画像の表示にはグラフプロットでお馴染みのmatplotlibを使います。
詳しくは「Pythonのmatplotlibをオブジェクト指向で使う!」を参照下さい。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#ここからグラフ設定 fig = plt.figure() ax1 = fig.add_subplot(111) # 画像をプロット ax1.imshow(i_binary, cmap = 'gray') # 軸を消す設定 ax1.tick_params(labelbottom = False, bottom = False) ax1.tick_params(labelleft = False, left = False) fig.tight_layout() plt.show() plt.close() |
画像データなので軸の目盛やラベルはわざと消しています。何も書かないとデフォルトでは横軸と縦軸にはピクセルの座標値が表示されます。
ちなみに、imshowは「Pythonで音のSTFT計算を自作!スペクトログラム表示する方法」の補足でも説明しましたが、cmapの値を変更することで色々なカラーマップの見せ方に変更することができます。
以下の図は、cmap = 'jet'を指定した場合です。jetのカラーバーの最大と最小で二値化されています。しかしこれはあくまでmatplotlibの表示上の色なので、実際にcv2.imwriteで保存されるデータは白黒になります。
まとめ
このページではWATLABブログで初めての画像処理プログラミングということもあり、前半に簡単な画像データの取り扱い、概要を学んだ結果を載せました。
次にPythonでOpenCVを使い、画像の二値化処理を行いました。この二値化処理はおそらくデジタル画像処理の中では最も簡単で、かつピクセルや輝度値、階調といった概念が学べるので、画像処理プログラムのHello World的な存在です。
また、二値化処理を通して画像ファイルの読み込みから処理、保存、表示までの一連のプロセスを学習しました。
画像処理の第一歩を踏み出しました!これでこの分野もどんどん進んで行けそうです。
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!
コメント