前提・実現したいこと
xmeans法によるクラスタリングの精度向上
発生している問題・エラーメッセージ
任意のカラー画像を似通った画像ごとに分類したいのですが、ほとんどの場合クラスタ数が2になってしまいます。
例えば、ただのコピー画像同士は同じクラスタに分類されるのですが、クラスタ数が2であるゆえに他の画像と混ざってしまいます。
これをxmeans法である程度の精度で実現したいと考えております。xmeans法以外の手法は現時点では考えておりません。
念のためソースコードをすべて記載しますが、該当箇所は64行目以降(#クラスタ数の取得およびxmeansの実行 というサブタイトル)だと思われます。
該当のソースコード
python
1import shutil 2from skimage import data 3import os 4import glob 5from PIL import Image 6import numpy as np 7from sklearn.cluster import KMeans 8import matplotlib.pyplot as plt 9from sklearn.decomposition import IncrementalPCA 10from pyclustering.cluster.xmeans import xmeans, kmeans_plusplus_initializer 11from pyclustering.utils import draw_clusters 12 13 14# 入力画像の読み込み[リストの作成] 15img_paths = [] #リストの宣言 16for root, dirs, files in os.walk("C:\Users\user\python_VScode_cwd\画像が入っているフォルダ\"): 17 for file in files : 18 if file.endswith(".png"): 19 img_paths.append(file) 20img_num = len(img_paths) 21print("*************") 22print("入力画像の枚数 :", img_num) 23print("*************") 24 25 26# データセットの製作[画像データ→RGB値の2,3次元配列→平らにする(2次元にする)] 27plt.close("all") 28img_paths = img_paths[:600] 29def img_to_matrix(img): 30 img_array = np.asarray(img) 31 return img_array 32def flatten_img(img_array): 33 s = img_array.shape[0] * img_array.shape[1] * img_array.shape[2] #RGBカラー画像は3次元、白黒は2次元? 34 img_width = img_array.reshape(1, s) 35 return img_width[0] 36dataset = [] 37for i in img_paths: 38 a = "C:\Users\user\python_VScode_cwd\画像が入っているフォルダ\" + i 39 img = Image.open(a) 40 #img = img.resize((int(1232/4), int(1754/4)), Image.BICUBIC) 41 img = img_to_matrix(img) 42 #img_gray = 0.299 * img[:, :, 0] + 0.587 * img[:, :, 1] + 0.114 * img[:, :, 2] 43 img = flatten_img(img) 44 dataset.append(img) 45dataset = np.array(dataset) 46print(dataset.shape) 47print("データセットの作成完了") 48print("*************") 49 50 51# 次元数の圧縮 [主成分分析-PCA] 52# batch_size < len(dataset) && n_components < batch_size である必要がある 53n = dataset.shape[0] 54batch_size = img_num 55ipca = IncrementalPCA(n_components=batch_size-1) 56for i in range(n//batch_size): 57 r_dataset = ipca.partial_fit(dataset[i*batch_size:(i+1)*batch_size]) 58r_dataset = ipca.transform(dataset) 59print(r_dataset.shape) 60print("主成分分析(PCA)の完了") 61print("*************") 62 63#クラスタ数の取得およびxmeansの実行 64class XMeans(): 65 def fit(self,features): 66 #pyclusteringのxmeansで計算 67 initializer = kmeans_plusplus_initializer(data=features,amount_centers=2) 68 initial_centers = initializer.initialize() 69 xm = xmeans(data=features,initial_centers=initial_centers,kmax=50) #第三引数はkの最大値 70 xm.process() 71 # 72 #分類が出力される 73 #しかしこの出力の仕方がscikit-learnとは違うので厄介 74 # 75 clusters = xm.get_clusters() 76 #一次元配列flat_labelを用意 77 flat_label = np.array([]) 78 #sklearnでいうlabel_の大きさを調べる 79 for cluster in clusters: 80 flat_label = np.append(flat_label,cluster) 81 #正規のlabelを代入するための配列を確保 82 labels = np.zeros((1,flat_label.size)) 83 84 #pyclusteringのclustersはクラスター数次元配列があり、標本の名前がクラスターに分類され配列として返す。 85 #一方でsklearnのlabel_は標本と同様の順番に、その標本が属するクラスターの番号を配列で返す。 86 #下記のコードはその変換を行っている 87 # 88 for n,n_th_cluster in np.ndenumerate(clusters): 89 for img_num in n_th_cluster: 90 labels[0][img_num] = n[0] 91 #このままのラベルだと[[a........z]]の二重括弧になる。 92 #それはsklearnの仕様に沿わない。[a........z]の一重括弧にする。 93 # 94 self.labels_ = labels[0] 95 return self 96model = XMeans() 97x_means = model.fit(r_dataset) 98labels = x_means.labels_ 99print("X-means法によるクラスタリングの完了") 100print("*************") 101 102#ラベルの最大値=クラスタ数-1 103k_num_before=int(np.max(labels)) 104#Xmeansによって決まったk=最大値+1 105k_num=k_num_before+1 106 107# 保存 108n_clusters = k_num 109for i in range(n_clusters): 110 label = np.where(labels==i)[0] 111 num = i +1 112 if not os.path.exists("class"+str(num)): 113 os.makedirs("class"+str(num)) 114 for j in label: 115 img = Image.open("C:\Users\user\python_VScode_cwd\画像が入っているフォルダ\" + img_paths[j]) 116 fname = img_paths[j].split('/')[-1] 117 img.save("class"+str(num)+"/" + fname) 118print("新たなファイルとして保存完了") 119print("*************") 120print("すべての処理が終了しました")
試したこと
主成分分析の過程を飛ばす→成果なし
sklearnのk-meansとpyclusteringのx-meansの配列の返し方の違いを見直す→成果なし
補足情報(FW/ツールのバージョンなど)
pythonは最新版のものを使用しています
VScodeを使用しています
よろしくお願いいたします。
回答1件
あなたの回答
tips
プレビュー