ここでは、画像の2値化処理についてまとめています。
画像の2値化とは?
画像の2値化と言うのは、「白黒画像」のことです。
以下の記事でグレースケールを紹介しました。
それぞれの画素の濃淡(強度)に応じて、「閾値」以下なら黒色、それ以外なら白色、
というように閾値処理を行います。
画像の2値化が行われていると、画像処理が高速に行うことができるため、
様々な実用シーンで利用されています。
OpenCV での 2値化処理(手動閾値)
それではさっそく、画像の2値化処理を行いましょう。
OpenCV では、標準APIである threshold() を使うことで簡単に実行できます。
ここでは、閾値を 100 として実行してみます。
1 2 3 4 5 6 7 8 9 10 11 12 |
import cv2 import matplotlib.pyplot as plt img = cv2.imread("src/sample.jpg", 0) threshold = 100 ret, img_th = cv2.threshold(img, threshold, 255, cv2.THRESH_BINARY) cv2.imshow("img", img) cv2.imshow("img_th", img_th) cv2.waitKey(0) cv2.destroyAllWindows() |
- 1~2行目:必要なパッケージを読み込みます
- 4行目:元画像を読み込んでいます
- 5行目:閾値を「100」として変数に格納しています
- 6行目:threshold() API を使って、2値化処理を行います。戻り値は、閾値と2値化画像の配列です
- 8~11行目:元の画像と2値化処理した画像を表示します
ポイント
元々白っぽい画像のため、全画素値の強度が閾値を上回っており、全白となってしまいました。
OpenCV での 2値化処理(自動閾値)
閾値を手動で設定すると、上手くいかない場合が多そうです。
そこで、OpenCV では THRESH_OTSU というオプションが用意されており、
これを使うと、閾値を自動で計算して2値化処理を実行してくれます。
1 2 3 4 5 6 7 8 9 10 11 |
import cv2 import matplotlib.pyplot as plt img = cv2.imread("src/sample.jpg", 0) ret, img_o = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU) # ret=207.0 cv2.imshow("img", img) cv2.imshow("otsu", img_o) cv2.waitKey(0) cv2.destroyAllWindows() |
- 5行目以外は、前述と同じです
- 5行目:threshold() API に THRESH_OTSU を指定し、2値化処理を実行します
今回はうまく2値化処理することができました。
OpenCV の API threshold() の戻り値 ret に、自動演算された閾値が返ってきます。
サンプル画像の場合は「207.0」が格納されていました。
自動計算された閾値は、元画像のヒストグラムを表示すると何となくわかります。
閾値には、全画素の中央値が使用されていそうですね。
参考
ヒストグラムの描き方は「【OpenCV】ヒストグラム均一化」をご覧ください。
OpenCV での近傍2値化処理
これまでの例で、2値化処理を行うことができるようになりました。
しかし、暗い部分は黒で塗りつぶされるため、モノの形が見えづらい部分もあるでしょう。
OpenCV では、adaptiveThreshold() という API を使用することで、
ある近傍領域の中で閾値を計算し、それぞれの領域で2値化処理を行うことができます。
1 2 3 4 5 6 7 8 9 10 11 12 |
import cv2 import matplotlib.pyplot as plt img = cv2.imread("src/sample.jpg", 0) ret, img_o = cv2.threshold(img, 0, 255, cv2.THRESH_OTSU) img_ada = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 3, 1) cv2.imshow("otsu", img_o) cv2.imshow("ada", img_ada) cv2.waitKey(0) cv2.destroyAllWindows() |
- 1~5行目、および8~11行目は前述と同じです
- 6行目:adaptiveThreshold() を使用して、近傍領域での2値化処理を実行しています
OpenCV の adaptiveThreshold() で 2値化した画像では、
影の部分もきれいに2値化できていることが分かります。