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

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

MENU

【python】【OpenCV】画像の3値化を行う

画像のデータ構造を理解して3値化を行う

f:id:stjun:20200214162140p:plain

左が元画像、右が3値化後

 

1. 誰に向けた記事か

pythonを勉強している人

OpenCVに興味がある初心者

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

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

 

www.stjun.com

www.stjun.com

 

 

2. はじめに

以前、OpenCVに標準で搭載されている関数を使って、簡単に画像の二値化を行いました。

www.stjun.com

 今回、3値化を行っています。

OpenCVに3値化の標準関数はないので、自分で作ってみます。

 

3. コードと実行結果と説明

#画像の3値化_ブログ
import cv2

#元画像の読み込み
img=cv2.imread('./test.jpg',0)
#元画像を表示
cv2.imshow("original",img)

#画像の縦の画素数、横の画素数を取得
height,width=img.shape

#3値化に使う低い側の閾値を決める
th_low_value=100
#3値化に使う高い側の閾値を決める
th_high_value=150
#3値化の白黒以外の色
gray=100

#画像の3値化
for i in range(height):
    for j in range(width):
        if img[i,j]<th_low_value:
            img[i,j]=0
        elif th_low_value <= img[i,j] <=th_high_value:
            img[i,j]=gray
        else :
            img[i,j]=255

#3値化した画像の表示
cv2.imshow("OpenCV",img)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

3.1 3値化とは何か

3値化とは画像を白と黒と灰色の3つの色で表すことです。

2値化は白と黒だけで表す処理だったので、3値化はもう一つ色を増やしたと考えられます。

下の画像は左が元画像、中央が二値化、右が3値化です。

f:id:stjun:20200214164507p:plain

ヒストグラムで見ると何をしてるか分かりやすいです。

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

黒(=0)から白(=255)まで広く分布していることが分かります。

f:id:stjun:20200214165016p:plain

2値化すると以下のヒストグラムになります。

2値化とは画像を白と黒だけに変換する処理だったので、黒(=0)と白(=255)だけピークがあることが分かります。

f:id:stjun:20200214165345p:plain

3値化すると以下のヒストグラムになります。

3値化なので白(=255)と黒(=0)以外に灰色(=100)にもピークがあることが分かります。

なお灰色の画素値は自分で指定できます。私は今回100にしましたが70や150にしても問題ありません。

f:id:stjun:20200214165532p:plain

 

3.2 説明1:画像を読み込み大きさを取得
#画像の3値化_ブログ
import cv2

#元画像の読み込み
img=cv2.imread('./test.jpg',0)
#元画像を表示
cv2.imshow("original",img)

#画像の縦の画素数、横の画素数を取得
height,width=img.shape

まずこれまで通りcv2.imread()で画像を読み込みます。

また後ほど3値化の処理で使うので、shapeを使って画像の大きさを取得します。

shapeは画像の縦と横の大きさを返します。

今回は400×600の大きさの画像を使っているので、height=400、width=600になります。

 

3.3 説明2:3値化の閾値を決定
#3値化に使う低い側の閾値を決める
th_low_value=100
#3値化に使う高い側の閾値を決める
th_high_value=150
#3値化の白黒以外の色
gray=100

次に3値化の閾値を決めていきます。

今回は画素値が100以下は白(=0)に、画素値が100~150の間なら灰色(=100)に、画素値が100以上なら黒(=255)にします。

そのためのパラメータを上記コードで決めています。

 

3.4 説明3:3値化をする
#画像の3値化
for i in range(height):
    for j in range(width):
        if img[i,j]<th_low_value:
            img[i,j]=0
        elif th_low_value <= img[i,j] <=th_high_value:
            img[i,j]=gray
        else :
            img[i,j]=255

 次に3値化をしていきます。

まず画像のデータ構造について説明します。

imread()で画像を読みこんだ時に、pythonでどんな構造で取り込まれるかを以下の文で確認しましょう。

#画像のデータ構造を表示
img=cv2.imread('./test.jpg',0)
print(img)

結果は次のように行列になります。

f:id:stjun:20200214170611p:plain

この行列の見方ですが、行列の位置と画像の位置が対応しており、値は色になります。

つまり0行0列目の88は、画像の左上の画素値が88(=黒に近い灰色)ということになります。その横の0行1列目の87は、画像の左上から右に1つずれた画素の値が87(=黒に近い灰色)ということになります。

イメージは以下の画像です。

f:id:stjun:20200214172236p:plain

例えば左上の画素値が88、右上の画素値が66、左下の画素値が137、右下の画素値が221になります。このように画像内の全ての位置と画素値が行列で書かれています。

そこでfor文を使って左上から順番に全ての画素値に対して判定を行い、画素値が100以下は白(=0)に、画素値が100~150の間なら灰色(=100)に、画素値が100以上なら黒(=255)にしています。

 

4.  最後に

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