こんにちは、エピックです。
引き続きOpenCVを深堀りしてみたいを思います。
画像処理といえば、みなさん何を思い浮かべるでしょうか。
色を変えること?サイズを変えること?色々有ると思います。
が、個人的には2値化こそ画像処理だと考えています!
OpenCVでは、さまざまな2値化の手法があります。
今回はそれらについて紹介したいと思います。
2値化とは画像を2つの値(例えば、白:255、黒:0)のみで表現する方法です。
2値化とは何か
2値化とは、閾値を決めて画像を2つの値(例えば、白:255、黒:0)のみで表現する方法であり手法になります。
方法は単純であり、設定したが閾値より大きければ白を割り当て,そうでなければ黒を割り当てるというロジックになります。
この2値化ですが、他の画像処理と組み合わせて利用することが多く画像処理の幹ともいえると私は考えています。
OpenCVでの2値化
OpenCVでの2値化ですが、cv2.threshold () と記述することで実装することができます。
引数は下記の通りとなります。
第一引数 | 対象とする入力画像 |
第二引数 | 2値化の閾値 |
第三引数 | 閾値を超えた場合に適用する値 |
第四引数 | 2値化の手法 ※下記参照 |
第四引数の手法については、下記で説明しますので一旦読み流してください。
また、重要な点として、OpenCV で2値化を行う場合は事前にグレースケールに変換しておく必要があります。
では、コードとその結果を見てみましょう。
import cv2
def imgShow(name, img):
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 画像を読み込み
# cv2.imread() を利用した場合、読み込みは BGR となる
img = cv2.imread("color.png")
# BGR から(to) GRAY への変換
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 画像の2値化
ret,th = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
# 画像を表示
imgShow("th",th)
上記の画像が下記のように変換され表示されるはずです。
2値化の手法
先程はとばしてしまいましたが、OpenCVでは第四引数で指定可能な方法がいくつか用意されています。
それが下記になります。
cv2.THRESH_BINARY | 閾値を超えるピクセルは 第三引数で設定した値 に,それ以外のピクセルは 0 になります |
cv2.THRESH_BINARY_INV | 閾値を超えるピクセルは 0 に,それ以外のピクセルは第三引数で設定した値 になります |
cv2.THRESH_TRUNC | 閾値を超えるピクセルは 閾値に,それ以外のピクセルは変更されません |
cv2.THRESH_TOZERO | 閾値を超えるピクセルは変更されず,それ以外のピクセルは 0 になります |
cv2.THRESH_TOZERO_INV | 閾値を超えるピクセルは 0 に,それ以外のピクセルは変更されません |
基本的には、白と黒の2値化を行う場合が多いため、cv2.THRESH_BINARY および cv2.THRESH_BINARY_INV を覚えておけばよいかと思います。
先程の画像をベースにそれぞれの結果は下記のようになります。
大津(OTHU)により自動で閾値を決める
上記の手法の他に、大津の手法というものがあります。
大津の手法とは、自動的に閾値を決定して二値化を行う手法の1つです。
さきほどは閾値を自ら設定していましたが、大津の手法を利用することで閾値をその必要がなくなるというわけです。
結論から言えば、閾値を適当に設定したときのクラス(閾値を堺に分けられる2つの塊)間の分離度が最大となる値を求めます。
分離度は、クラス間分散とクラス内分散から求められます。
こちらのサイトが簡潔でわかりやすかったです。
西住工房(改)【画像処理】大津の二値化処理の原理・特徴・計算式
では実際にコードを書いてみます。
import cv2
def imgShow(name, img):
cv2.imshow(name, img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 画像を読み込み
# cv2.imread() を利用した場合、読み込みは BGR となる
img = cv2.imread("color.png")
# BGR から(to) GRAY への変換
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 画像の2値化
# 第二引数の閾値は自動で設定されるため0を指定
ret,th = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)
# 画像を表示
imgShow("th",th)
(画像が悪かったかもしれませんが)2分割できているのがわかるかと思います。
最後に
今回はOpenCVを利用したスタンダードな2値化の方法についてでした。
OpenCVを利用することで非常に簡単に2値化を行うことができましたね。
紹介した以外にもさまざまな手法があるので試してみてください。
今回も最後までお読みいただきありがとうございました。
では。