大津の手法を用いて3値化を行う

実現したいこと

前提

Pythonを用いて,大津の手法を実装しています。閾値の決定方法のみ,ライブラリを使わずにクラス間分散を最大にするやり方で行っています。参考論文はこちらにあります。https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=4310076

発生している問題

エラーは出ませんが,二つ目の閾値がうまく計算できていないようです。
一つ目の閾値はおそらく正しいです(二値化だけで実装した時と同じになったため)。結果を見たところ,画像を変えても二つ目の閾値がほぼ250付近のかなり高い画素値に設定されてしまっています。

該当のソースコード

Python

12import numpy as np 3import matplotlib.pyplot as plt 4import cv2 5 6def otsu_threshold(image):7 # グレースケール変換8 gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)9 10 # 画像の総画素数11 total_pixels = gray.shape[0] * gray.shape[1]12 13 # ヒストグラムの計算14 hist = np.histogram(gray, bins=256, range=[0, 256])[0] / total_pixels 15 #plt.figure()16 #plt.plot(hist)17 18 all_sum = np.sum(hist * np.arange(256))19 all_mean = all_sum / total_pixels 20 21 # クラス間分散と閾値の初期化22 max_variance = 023 threshold1 = 024 threshold2 = 025 26 # 0から255までの閾値を試す27 for t1 in range(256):28 for t2 in range(t1+1, 255):29 # クラス1とクラス2の画素数を計算(wに相当)30 class1_pixels = np.sum(hist[:t1])31 class2_pixels = np.sum(hist[t1:t2])32 class3_pixels = total_pixels - (class1_pixels + class2_pixels)33 34 # クラス1とクラス2の画素値の総和を計算35 class1_sum = np.sum(hist[:t1] * np.arange(t1))36 class2_sum = np.sum(hist[t1:t2] * np.arange(t1, t2))37 class3_sum = np.sum(hist[t2:] * np.arange(t2, 256))38 39 # クラス1とクラス2の平均を計算40 class1_mean = class1_sum / class1_pixels if class1_pixels > 0 else 041 class2_mean = class2_sum / class2_pixels if class2_pixels > 0 else 042 class3_mean = class3_sum / class3_pixels if class3_pixels > 0 else 043 44 # クラス間分散を計算45 #variance = class1_pixels * class2_pixels * ((class1_mean - class2_mean) ** 2)46 variance = class1_pixels * (class1_mean - all_mean)**2 + class2_pixels * (class2_mean - all_mean)**2 + class3_pixels * (class3_mean - all_mean)**247 48 # クラス間分散が最大となる閾値を更新49 if variance > max_variance:50 max_variance = variance 51 threshold1 = t1 52 threshold2 = t2 53 54 print("threshold = {0},{1}".format(threshold1, threshold2))55 # 3値化処理56 #binary_image = np.where(gray > threshold, 255, 0).astype(np.uint8)57 binary_image = np.zeros_like(gray)58 binary_image[gray <= threshold1] = 059 binary_image[(gray > threshold1) & (gray <= threshold2)] = 12760 binary_image[gray > threshold2] = 25561 62 return binary_image 63 64# 画像の読み込み65image = cv2.imread("const.jpg")66 67# 大津の二値化68binary_image = otsu_threshold(image)69 70# 結果の表示71plt.figure(figsize=(10, 5))72plt.subplot(1, 2, 1)73plt.imshow(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))74plt.title('Original Image')75plt.axis('off')76 77plt.subplot(1, 2, 2)78plt.imshow(binary_image, cmap='gray', vmin=0, vmax=255)79plt.title('Otsu Thresholding')80plt.axis('off')81 82plt.tight_layout()83plt.show()

試したこと

いろんな画像を入れてみましたが,どれも同じで,二つ目の閾値が非常に高い値になりました。
式の確認などは何度も行ってるので合っているとは思います。

お力添えいただけますと幸いです。よろしくお願い致します。

コメントを投稿

0 コメント