今回はOpenCV で画像の閾値処理をしていきます。閾値処理とはグレースケールの白黒画像において、白黒はっきりさせるということです(?)。
例を挙げれば、明度に閾値を設けて、ある明度以上(または以下)の部分はすべて真っ白にし、それ以外は真っ黒にするといったような処理です
言葉だけでは伝わらないと思うので、実際に図を示しながら解説していきます。もちろんPythonのコードも。
はじめに
まずは以下の画像を見てください。
数字が書いてあるのがわかりますが、何個の数字が見えますか?
かろうじて「10」が見えて、10個の数字が確認できるのではないでしょうか。
ところが、以下の画像を見てください。
これは、上の画像にある処理を加えたものです。なんと、上の画像では全く見えなかった「5」が浮かび上がってきました。
ここで行った処理が閾値処理です。画像に書かれた数字は、その数字の明度を示しています。この場合、明度が5以上の部分を明度「255(白)」に変換しています(それ以外の部分は「0(黒)」)。
このような閾値処理は、画像の2値化とも呼ばれます。画像の2値化はあらゆる画像処理の前処理として重要です。
Pythonで実装する
ここからは実際にPythonで閾値処理を実装していきます。画像には、上記の数字が書かれた白黒画像を用います。
import cv2
#白黒で画像読込
src = cv2.imread("input/thresh.jpg", cv2.IMREAD_GRAYSCALE)
注意: 画像の閾値処理は白黒画像でしか行えません。
基本構文
閾値処理にはcv2.threshold()を用います。
cv2.threshold(src, thresh, maxValue, thresholdType )
- src:インプットの画像(白黒)
- thresh:閾値となる値
- maxValue:閾値条件を満たした場合の値
- thresholdType:閾値処理のタイプ
threshに指定した値を基準に閾値判定が行われます。スタンダードな閾値処理の場合、threshを超えたピクセルにはmaxValueで指定した値が割り当てられます。処理の種類によっては、threshを下回った部分にmaxValueが割り当てられる場合もあります(反転処理時等)。
maxValueが割り当てられなかったピクセルには0(黒)が割り当てられます(反転時は白)。
閾値処理の種類
閾値処理の種類はいくつかあります。各特徴を1つ1つ紹介していきます。
cv2.THRESH_BINARY
バイナリ閾値は閾値処理のなかで最もスタンダードな手法です。threshで指定した値以上のピクセルはmaxValueに、それ以外は0に変換されます。
th, dst = cv2.threshold(src, 3, 255, cv2.THRESH_BINARY)
cv2.imshow("opencv-threshold-example.jpg", dst)
戻り値は2つありますが、変換後の画像は第2引数(dst)です。
cv2.THRESH_BINARY_INV
cv2.THRESH_BINARY_INVは、 cv2.THRESH_BINARY の逆です。つまり、threshの値以下のピクセルはmaxValueの値に変換され、それ以外(thresh以上)は0に変換されます。
INVはInverted等のことで、逆とか反転といった意味です。
th, dst = cv2.threshold(src,115,255, cv2.THRESH_BINARY_INV)
cv2.imshow("opencv-thresh-binary-inv.jpg", dst)
cv2.THRESH_TRUNC
この方法では閾値による切り捨て処理を行います。threshの値以上のピクセルはthreshの値に変換され、thresh以下の値のピクセルは元の値のままになります。maxValueは指定しても意味がありません。
th, dst = cv2.threshold(src,120,255, cv2.THRESH_TRUNC)
cv2.imshow("opencv-thresh-trunc.jpg", dst)
120以上の数字はすべて120に変換されています。一方それ以下の数値は元のままです。
cv2.THRESH_TOZERO
この方法ではthreshの値以上のピクセルはもとの値のまま、それ以外は0に変換します。maxValueは指定しても意味がありません。
th, dst = cv2.threshold(src,120,255, cv2.THRESH_TOZERO)
cv2.imshow("opencv-thresh-tozero.jpg", dst)
cv2.THRESH_TOZERO_INV
cv2.THRESH_TOZEROの逆で、 threshの値以下のピクセルはもとの値のまま、それ以外は0に変換します。
th, dst = cv2.threshold(src,120,255, cv2.THRESH_TOZERO_INV);
cv2.imshow("opencv-thresh-to-zero-inv.jpg", dst)
120以下の部分はそのまま残っています。
150以上の数値の輪郭が見えますが、これは画像の問題です^^;
輪郭部分に閾値以下の値があるみたいです。
OpenCVの学習におすすめ書籍
PythonでOpenCV始めてみようという方におすすめなのが以下書籍です。実装例も豊富なので、1からコードを書かずとも学習を進めることができます。
オライリーの1冊は読み物というより辞書としての利用におすすめです。お値段結構しますが、細かい情報までしっかりと詰め込まれています。
まとめ
OpenCVでの閾値処理について解説しました。閾値処理は画像処理各種の前処理として活用されます。
今回紹介したように、閾値処理にも様々な方法があります。どういった処理をしたいかに応じて使い分ける必要があります。
1つ1つを覚える必要はないと思いますが、色々方法があるんだなということは頭に入れておいていいかもしれません。
OpenCVの基礎を身につけるためのロードマップは以下を参考にしてください。
ではでは👋