それが僕には楽しかったんです。

僕と MySQL と時々 MariaDB

判別分析法

判別分析法

判別分析法とはざっくり言えば2値化の手法の一つで
分離度という値が最大になる値を見つけ、自動的に2値化する手法

分離度はクラス間分散とクラス内分散の比で求めることができる

具体的な仕組み

今、しきい値
{\displaystyle
t,(0 \leqq t \leqq 255)
}
として
{\displaystyle
0 \leqq tの範囲を黒クラスとし \\
画素数:\omega_1 \\
平均:m_1 \\
分散:\delta_1 \\
と定義する \\
\\
同様に t \leqq 255の範囲を白クラスとし \\
画素数:\omega_2 \\
平均:m_2 \\
分散:\delta_2 \\
とする \\

さらにtにおける全画像を \\
画素数:\omega_t \\
平均:m_t \\
分散:\delta_t \\
とする \\
}

これがまず判別分析法を使う上でのデータの定義

そして次がクラス内分散とクラス間分散、全分散の定義

{\displaystyle
クラス内分散\delta_w^2は以下のように定義する \\
\large\delta_w^2 = \frac{\omega_1\delta_1^2+\omega_2\delta_2^2}{\omega_1+\omega_2} \\
\\
クラス間分散\delta_b^2は以下のように定義する \\
\large\delta_b^2 = \frac{\omega_1\omega_2(m_1-m_2)^2}{(\omega_1+\omega_2)^2} \\
\\
全分散\delta_tは \\
\delta_t = \delta_b^2 + \delta_w^2\\
と定義する
}

ここまでが判別分析法で扱う定義の部分
これら与えられた条件を元に分離度を算出する

{\displaystyle
分離度は以下のように表す\\
\large\frac{\delta_b^2}{\delta_w^2} = \frac{\delta_b^2}{\delta_t^2 - \delta_b^2}\\
}

そしてこれが最大になるしきい値tを求めることで2値化する
しかし全分散はしきい値に関係なく一定なのでクラス間分散の分子
{\displaystyle
\large\omega_1\omega_2(m_1 - m_2)^2
}
が最大になるしきい値tを求めることになる

なので0~255の間で上の式が最大になるようなtを求めていけばいい

そしてそれらの条件を満たすtを見つけたら
それを元に2値化処理をすることで、判別分析法が実装できる

実装コード

今回もいつもどおりPythonOpenCVを使用

#coding:utf-8

import numpy as np
import cv2

img = cv2.imread("lenna256.png")
#画像をグレースケールに変換
gray = cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)

#ヒストグラムを作成
histgram = [0]*256
for i in range(0,len(gray)):
	for j in range(0,len(gray[0])):
		histgram[gray[i][j]] += 1

#print histgram

max_t = max_val = 0

#判別分析法を使って2値化
for t in range(0,256):

	#画素数
	w1 = w2 = 0

	#クラス別合計値
	sum1 = sum2 = 0

	#クラス別平均
	m1 = m2 = 0.0

	for i in range(0,t):
		w1 += histgram[i]
		sum1 += i*histgram[i]

	for j in range(t,256):
		w2 += histgram[j]
		sum2 += j*histgram[j]

	#0除算を防ぐ
	if w1 == 0 or w2 == 0:
		continue
	
	#クラス別平均の算出
	m1 = sum1/w1
	m2 = sum2/w2

	#結果を算出
	result = w1*w2*(m1-m2)*(m1-m2)

	if max_val < result:
		max_val = result
		max_t = t


for i in range(0,len(gray)):
	for j in range(0,len(gray[0])):

		if(gray[i][j] < max_t):
			gray[i][j] = 0
		else:
			gray[i][j] = 255

#print max_val
#cv2.imwrite("binary_lenna.png",gray)
cv2.imshow("binary",gray)
cv2.waitKey(0)
cv2.destroyAllWindow()

せっかくなので今回はヒストグラムも自作してみた

結果

使用した画像はいつものLenna.png

f:id:RabbitFoot141:20160219022220p:plain

そして判別分析法で2値化処理したbinary_lenna.png

f:id:RabbitFoot141:20160219234518p:plain

結果はまぁまぁ


そして参考サイトがこれ↓
ithat.me