画像を二値化する

画像の二値化は大切です。物体の検出や加工にも二値化は基礎となります。今回は基礎となる二値化をグラフを使って説明します。

必要なモジュールをインポート

画像解析に必要なOpenCVとグラフ描写に必要なmatplotlib、%pylab inlineも入れておきましょう。

plt.gray()はグレースケール表示のためのメソッドです。

import cv2
import matplotlib.pyplot as plt
%pylab inline
plt.gray()

実行して、エラーがでなければOKです。

画像読み込み

画像を読み込む処理をします。詳しく書いた記事があるので詳細は過去記事(画像を読み込み、可視化する)をご覧ください。

今回もイラストやさんから頂いた画像を使わせていただくとします。

【使用する画像】

画像1

では、グレースケールで変数image_gの中に入れ込みます。

引数に『0』を加えると簡単にグレースケール画像になります。

image_g = cv2.imread("/irasutoya.jpg",0)
plt.imshow(image_g)
plt.show()

実行結果:

無題

同じ結果が出てますでしょうか。

グレースケールと二値化の違いって?

ここで、純粋な疑問。

グレースケールである白黒画像と二値化って何が違うの?

もう、その通りです。

グレースケールは1つの画素で白~灰色~黒までの256段階(8bit)の階調が表現できます。

白黒二値化は1つの画素に白か黒の2階調(1bit)しかなく、グレーの階調はたくさんの白の中に黒を点在させて表現します(コニカミノルタHPより)。

ということで、グレースケールの二値化の場合は、構成するピクセルが白もしくは黒というパキッと分かれるので、画像によって閾値が異なります。

この辺りを体感して頂きましょう。


二値化の作成

その画素値がしきい値より大きければある値(白)を割り当て,そうでなければ別の値(黒)を割り当てます.関数は cv2.threshold を使います.第1引数は入力画像で グレースケール画像でなければいけません (参考文献OpenCVチュートリアル).

関数の使い方は以下です。

ret, image = cv2.threshold(グレースケール画像,下の閾値,上の閾値,cv2.THRESH_BINARY)

戻り値のretには、下の閾値が入ります。imageには加工後の画像が入ります。

第四引数であるcv2.THRESH_BINARYは、他に6種類ほどありますが、ご興味がある方はOpenCVチュートリアルをご参考に。

では、グレースケール写真を下限を100とし、上限を255とした二値化で表現してみます。

ret, image_b = cv2.threshold(image_g,100,255,cv2.THRESH_BINARY)
plt.imshow(image_b)

実行結果:

無題1

あら。なんということでしょう。

全然ダメですね。

では、下限を150にしてみます。

ret, image_b = cv2.threshold(image_g,150,255,cv2.THRESH_BINARY)
plt.imshow(image_b)

実行結果:

無題1

ほほう。

もう一声というところでしょうか。思い切って、下限を230まで上げてみます。

ret, image_b = cv2.threshold(image_g,230,255,cv2.THRESH_BINARY)
plt.imshow(image_b)

実行結果:

無題1

よいですね。

くっきりしています。

ちなみに、最後の実行の後、

print(ret)

実行結果:

230.0

になります。戻り値retには、下限が入っていることが分かります。

最適な二値化へ

毎回、手動で下限と上限の閾値を指定するなんて、めんどくさいですよね。

ということで、自動化された二値化をしてみましょう。

第四引数にcv2.THRESH_OTSUを指定するのと、下限を0にすることで簡単にできます。

ret, image_otsu = cv2.threshold(image_g,0,255,cv2.THRESH_OTSU)
plt.imshow(image_otsu)

実行結果:

無題1

残念ながら、めちゃくちゃいいじゃないの!

という結果にはなりませんでしたが、OpenCVからみるとこれが最適なようです。ん?どういうこと?

cv2.THRESH_OTSUの方法で、ヒストグラムを描くと分かります。

hist = cv2.calcHist([image],[0],None,[256],[0,256])
plt.plot(hist)

実行結果:

無題

ヒストグラムで2つの山が出来ている状態だと、極端に明るい部分と暗い部分の山があるみなし、その中間に閾値を設定してくれます。

しかし、今回の画像の場合、山がありません。

この場合は上手く、閾値をとれていないようです。

ペイントした画像ではなく、写真だとヒストグラムに山が2つ見られ、上手に閾値が取れる場合があります。



この記事が気に入ったらサポートをしてみませんか?