機械系エンジニアの備忘録

20代独身社会人。仕事では機械・機構の研究開発を行っているエンジニアが、自分の専門分野ではないpythonを扱って楽しむブログです。

MENU

【python】【OpenCV】OpenCVに標準で搭載されている関数で画像の二値化を行う

画像処理ライブラリであるOpenCVを使って、画像の二値化を簡単に行う

f:id:stjun:20200207001527p:plain

1. 誰に向けた記事か

pythonを勉強している人

OpenCVに興味がある初心者

・画像の二値化をやりたい人

※初心者向けにpythonの勉強法とその手順を記事にしました。

www.stjun.com

 

 

2. はじめに

前回、OpenCVのインストール方法、OpenCVによる画像の読み込み、画像の白黒化、リサイズ(画像の縮小化)などを行いました。

www.stjun.com

 今回は、OpenCVに標準で搭載されている関数を使って、簡単に画像の二値化を行ってみたいと思います。

二値化とは画像を白と黒の2つの色で表示することです。

画像処理の分野において、物体の境界線の抽出や物体の面積を求める際によく使われます。

 

3. コードと実行結果

3.1 コード
#画像の二値化
import cv2
import matplotlib
import matplotlib.pyplot as plt
%matplotlib inline

#画像の読み込み
img=cv2.imread('./test.jpg',0)
#①自分で閾値を決めて二値化
ret1,img_th=cv2.threshold(img,130,255,cv2.THRESH_BINARY)
#②自動で閾値を決めて二値化
ret2,img_otsu=cv2.threshold(img,0,255,cv2.THRESH_OTSU)
#③一部分の区域の中央値から閾値を自動で決めて二値化
img_ada=cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,3)
#④特定の範囲のGaussian分布から閾値を自動で決めて二値化
img_ga=cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,3)
#各画像の表示
cv2.imshow("OpenCV",img)
cv2.imshow("OpenCV_th",img_th)
cv2.imshow("OpenCV_otsu",img_otsu)
cv2.imshow("OpenCV_adaptive",img_ada)
cv2.imshow("OpenCV_adaptive_gaussian",img_ga)
cv2.waitKey(0)
cv2.destroyAllWindows()

今回はこのコーヒーカップの画像を二値化させたいと思います。

f:id:stjun:20200207002928p:plain

3.2 自分で閾値を決めて二値化

以下が元画像のヒストグラムです。

f:id:stjun:20200207002550p:plain

130あたりに緩やかなピークがあるので、今回130を閾値に設定しました。

#①自分で閾値を決めて二値化
ret1,img_th=cv2.threshold(img,130,255,cv2.THRESH_BINARY)

cv2.threshold()の引数は左から順に、二値化したい画像、閾値閾値を超えた場合いくつにするか、二値化の方法になります。

すると次のような画像が得られます。

うっすらと輪郭は見えますが、あまり綺麗な二値化ではないですね。

f:id:stjun:20200207003355p:plain

 

3.2 自動で閾値を判断して二値化(大津の二値化)

繰り返しになりますが、以下が元画像のヒストグラムです。

大津の二値化は以下のヒストグラムから自動で閾値を選んでいます。動作原理についてはここでは省略します。

f:id:stjun:20200207002550p:plain

#②自動で閾値を決めて二値化
ret2,img_otsu=cv2.threshold(img,0,255,cv2.THRESH_OTSU)

cv2.threshold()の引数は左から順に、二値化したい画像、閾値(自動で選んでくれるため0で固定です)、閾値を超えた場合いくつにするか、二値化の方法になります。

結果は以下になります。

f:id:stjun:20200207003930p:plain

先ほど自分で閾値を決めた場合とあまり変わりませんね。

大津の二値化は、ヒストグラムで見た時に大きな山が二つあるような画像だと上手く二値化してくれるみたいです。今回のような影や光の反射があるような場合だと難しそうです。

 

3.3 画像を細かく分割し、分割された場所ごとに計算した中央値を閾値として二値化

 今回の画像のように影がある場合、adaptiveThreshold()による二値化がお勧めです。

#③一部分の区域の中央値から閾値を自動で決めて二値化
img_ada=cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY,11,3)

cv2.adaptiveThreshold()の引数は左から順に、二値化したい画像、閾値を超えた場合いくつにするか、二値化の方法、何×何マスで中央値を計算するか、その中央値から値をどれだけ引くかになります。

今回の場合、11なので自身を含めた縦11個×横11個のピクセル群の中で中央値を計算し、その値から3引いた値を二値化の閾値として使用しています。

つまりこれまでは画像全体から選んだ1つの閾値を用いて二値化をしていたのに対し、場所ごとに閾値を変えて二値化をするのが本方法です。

平たくいれば明るい場所では明るい場所に適した閾値を、暗い場所では暗い場所に適した閾値を選んでいることになります。

結果は以下になります。adaptiveThreshold()を使うと先ほどよりコーヒーカップの輪郭がくっきり出ていますね。

f:id:stjun:20200207004930p:plain

引数の最後の数字を3から-5にすると黒っぽい画像になります。

f:id:stjun:20200207010031p:plain

引数の最後の数字が正だと白っぽい画像に、負だと黒っぽい画像になります。

 

3.4 画像を細かく分割し、分割された場所ごとにガウス分布に沿うよう重みづけされた平均値を閾値として二値化

さきほどは単純な中央値でしたが、ガウス分布に沿うように重みづけされた平均値を使って二値化する方法です。

#④特定の範囲のGaussian分布から閾値を自動で決めて二値化
img_ga=cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY,11,3)

cv2.adaptiveThreshold()の引数は先ほどと同じように、左から順に、二値化したい画像、閾値を超えた場合いくつにするか、二値化の方法、何×何マスで中央値を計算するか、その中央値から値をどれだけ引くかになります。

f:id:stjun:20200207004955p:plain

こちらもコーヒーカップの輪郭がしっかりと把握できますね。画像の中の明暗が大きい場合はこのようにadaptiveThreshold()を使うのが良さそうです。

 

自分が使ってるお得情報の紹介

私はAmazon kindle unlimitedというサービスを1年以上利用しています。

これは月額980円で 和書12万冊以上の電子書籍を読めるサービスです。

ビジネス本、雑誌、漫画、技術本など様々な本を読むことができます。10冊まで端末にダウンロードできるのでネット環境がなくても(オフラインでも)見れます。

なおkindle unlimitedは最初の30日間無料のため、気軽に登録してみて、あまり読みたい本が無ければすぐに解約しても問題ありません。

それか30日内に気になる本を全て読破すれば実質タダです。

ぜひ気になった方はチェックしてみて下さい。

なおkindleにない本等を買う時はamazonギフト券(amazonで使えるポイント)を買い、ポイントで数冊まとめて買った方がお得です。

ギフト券(ポイント)は買ったら10年も有効で、ポイントが付きます。さらに本をまとめ買い(2冊以上同時に)買うと、ポイントがもらえます。

https://www.amazon.co.jp/b?ie=UTF8&node=5431437051

学生さんであればkindle unlimitedよりも年2450円(月210円程度)で映画見放題、音楽聞き放題、本読み放題の「prime student」がおすすめです。

 

4.  最後に

次回もOpenCVを使って簡単な画像処理を行ってみたいと思います。