#author("2025-07-02T12:13:16+09:00","default:kouzouken","kouzouken")
#author("2025-07-02T12:56:27+09:00","default:kouzouken","kouzouken")
**7/2 [#j417c702]
様々なCNNモデル(の組み合わせ4パターンは以下に記載)を試したが学習時間・精度ともに元々学習に使っていた"EfficientNetV2S", "DenseNet121", "MobileNetV3Large" の組み合わせが1番であったためこれから当面の間はMMLI.py と CNN+binning3.pyで錆画像の判別を行っていくこととする。
-グループA:"EfficientNetV2M", "InceptionResNetV2", "DenseNet121", "MobileNetV3Large" 高精度&バランス型 
-グループB:"EfficientNetB3", "ResNet50", "MobileNetV3Small", "NASNetMobile" 軽量&高速重視型
-グループC:"InceptionResNetV2", "ResNet101", "EfficientNetV2S", "NASNetLarge" 深層学習&多スケール戦略型
-グループD:"EfficientNetV2S", "EfficientNetV2M", "EfficientNetB7", "InceptionResNetV2" 比較的新しい型のCNNモデル

-CNN+binning3.pyについて(抜粋)

--1, 学習画像と連続スコアの読み込み(回帰スコアが1.00点未満または5.01点以上の場合は学習に再利用・結果に保存しない)
 def load_images_and_scores(folder):                                                                       #指定フォルダから画像とスコアを読み込む関数を定義
     images, scores = [], []                                                                               #画像データとスコアを格納するリストを初期化
     for fname in sorted(os.listdir(folder)):                                                              #フォルダ内のファイル名を並び替えて1つずつ処理
         if fname.endswith(".png") or fname.endswith(".jpg"):                                              #画像ファイル(png/jpg)のみ処理対象
 def load_images_and_scores(folder):                                                                                   #指定フォルダから画像とスコアを読み込む関数を定義
     images, scores = [], []                                                                                           #画像データとスコアを格納するリストを初期化
     for fname in sorted(os.listdir(folder)):                                                                          #フォルダ内のファイル名を並び替えて1つずつ処理
         if fname.endswith(".png") or fname.endswith(".jpg"):                                                          #画像ファイル(png/jpg)のみ処理対象
             try: #エラー処理のためのtryブロック
                 score = float(fname[0])                                                                   #ファイル名の先頭文字からスコア(ラベル)を取得(例:「3_xxx.png」→3.0)
                 score += np.random.uniform(-0.2, 0.2)                                                     #スコアにランダムなノイズを任意で設定しラベルをソフト化
                 if score < 1.0 or score > 5.0:                                                            #1.00点未満または5.01点以上の場合は学習に再利用・結果に保存しない
                 score = float(fname[0])                                                                               #ファイル名の先頭文字からスコア(ラベル)を取得(例:「3_xxx.png」→3.0)
                 score += np.random.uniform(-0.2, 0.2)                                                                 #スコアにランダムなノイズを任意で設定しラベルをソフト化
                 if score < 1.0 or score > 5.0:                                                                        #1.00点未満または5.01点以上の場合は学習に再利用・結果に保存しない
                    print(f"⚠️ スコア範囲外: {fname} → {score:.2f} → スキップ")
                    continue
                 path = os.path.join(folder, fname)                                                        #画像ファイルのフルパスを作成
                 img = Image.open(path).convert("RGB").resize(IMAGE_SIZE)                                  #画像を開いてRGBに変換し、指定サイズにリサイズ
                 images.append(np.array(img) / 255.0)                                                      #画像をNumPy配列に変換し、0〜1に正規化してリストに追加
                 scores.append(score)                                                                      #スコアをリストに追加
             except:                                                                                       #例外が発生した場合の処理
                 path = os.path.join(folder, fname)                                                                    #画像ファイルのフルパスを作成
                 img = Image.open(path).convert("RGB").resize(IMAGE_SIZE)                                              #画像を開いてRGBに変換し、指定サイズにリサイズ
                 images.append(np.array(img) / 255.0)                                                                  #画像をNumPy配列に変換し、0〜1に正規化してリストに追加
                 scores.append(score)                                                                                  #スコアをリストに追加
             except:                                                                                                   #例外が発生した場合の処理
                 print(f"スキップ: {fname}") 
     return np.array(images), np.array(scores)                                                             #画像とスコアのリストをNumPy配列に変換して返す 
     return np.array(images), np.array(scores)                                                                         #画像とスコアのリストをNumPy配列に変換して返す 

--2, CNN構築
  def create_model(version):                                                                               #指定したバージョン番号(インデックス)に対応するモデルを構築する関数の定義
          input_img = Input(shape=(*IMAGE_SIZE, 3))                                                        #入力画像の形状(IMAGE_SIZE, 3チャンネル)でKerasのInput層を作成
  def create_model(version):                                                                                           #指定したバージョン番号(インデックス)に対応するモデルを構築する関数の定義
          input_img = Input(shape=(*IMAGE_SIZE, 3))                                                                    #入力画像の形状(IMAGE_SIZE, 3チャンネル)でKerasのInput層を作成
 
  if version == 0:
         base = EfficientNetV2S(include_top=False, weights="imagenet", input_tensor=input_img)             #モデル名がEfficientNetV2Sの場合の分岐
         base = EfficientNetV2S(include_top=False, weights="imagenet", input_tensor=input_img)                         #モデル名がEfficientNetV2Sの場合の分岐
     elif version == 1:
         base = DenseNet121(include_top=False, weights="imagenet", input_tensor=input_img)
     elif version == 2:
         base = MobileNetV3Large(include_top=False, weights="imagenet", input_tensor=input_img)
  
     base.trainable = False                                                                                #ベースモデルの重みを凍結し転移学習で特徴抽出器として使用
     x = base.output                                                                                       #ベースモデルの出力をxに代入
     x = layers.GlobalAveragePooling2D()(x)                                                                #グローバル平均プーリング層で特徴マップを1次元ベクトルに変換
     x = layers.Dense(2048, activation='relu')(x)                                                          #全結合層(2048ユニット、ReLU活性化)を追加
     x = layers.BatchNormalization()(x)                                                                    #バッチ正規化層を追加し学習を安定化
     x = layers.Dropout(0.5)(x)                                                                            #ドロップアウト(50%)で過学習を防止
     base.trainable = False                                                                                            #ベースモデルの重みを凍結し転移学習で特徴抽出器として使用
     x = base.output                                                                                                   #ベースモデルの出力をxに代入
     x = layers.GlobalAveragePooling2D()(x)                                                                            #グローバル平均プーリング層で特徴マップを1次元ベクトルに変換
     x = layers.Dense(2048, activation='relu')(x)                                                                      #全結合層(2048ユニット、ReLU活性化)を追加
     x = layers.BatchNormalization()(x)                                                                                #バッチ正規化層を追加し学習を安定化
     x = layers.Dropout(0.5)(x)                                                                                        #ドロップアウト(50%)で過学習を防止
     .
     .
     .
     output = layers.Dense(1)(x)                                                                           #出力層(1ユニット、活性化なし=線形)を追加
     output = ClipLayer()(output)                                                                          #出力値を1.0〜5.0にクリップするカスタムレイヤー(ClipLayer)を適用
     model = Model(inputs=input_img, outputs=output)                                                       #入力と出力を指定してKerasのModelを構築
     model.compile(optimizer='adam', loss=custom_penalizing_loss, metrics=['mae'])                         #モデルをAdam最適化, カスタム損失関数, MAE評価指標でコンパイル
     return model                                                                                          #構築したモデルを返す 
     output = layers.Dense(1)(x)                                                                                       #出力層(1ユニット、活性化なし=線形)を追加
     output = ClipLayer()(output)                                                                                      #出力値を1.0〜5.0にクリップするカスタムレイヤー(ClipLayer)を適用
     model = Model(inputs=input_img, outputs=output)                                                                   #入力と出力を指定してKerasのModelを構築
     model.compile(optimizer='adam', loss=custom_penalizing_loss, metrics=['mae'])                                     #モデルをAdam最適化, カスタム損失関数, MAE評価指標でコンパイル
     return model                                                                                                      #構築したモデルを返す 

-3, 回帰スコアとモデル学習の設定
--3, 回帰スコアとモデル学習の設定
 # === binning: 回帰スコア → 評点1〜5 === 
 →回帰モデルの連続値出力を1〜5の整数評価に変換する関数を定義
 def binning(score): #binning関数の定義
     if score < 2.3: return 1
     elif score < 3.1: return 2
     elif score < 3.4: return 3
     elif score < 3.7: return 4
     else: return 5 
 
 # === モデル学習 === 
 →データを読み込み、訓練・検証セットに分割し、全ての選択モデルについて構築・学習・保存を行う
 x, y = load_images_and_scores(TRAIN_FOLDER)                                                                #学習用画像とスコアを読み込み
 x_train, x_val, y_train, y_val = train_test_split(x, y, test_size=0.2, random_state=42)                    #データセットを訓練用と検証用(test_size)に8:2で分割
     model = create_model(i)                                                                                #モデルを構築
 x, y = load_images_and_scores(TRAIN_FOLDER)                                                                           #学習用画像とスコアを読み込み
 x_train, x_val, y_train, y_val = train_test_split(x, y, test_size=0.2, random_state=42)                               #データセットを訓練用と検証用(test_size)に8:2で分割
     model = create_model(i)                                                                                           #モデルを構築
     .
     .
     .
     model.save(MODEL_PATHS[i])                                                                             #学習済みモデルを保存
     model.save(MODEL_PATHS[i])                                                                                        #学習済みモデルを保存
     print(f"✅ モデル{i+1}保存完了: {MODEL_PATHS[i]}"

-4, 回帰スコアから評点の予測
--4, 回帰スコアから評点の予測
 # === 評点予測・保存 ===
 →アンサンブル学習済みモデルでテスト画像を予測し、平均スコアを整数評点に変換、評点ごとに画像を保存。予測過程を出力
 models_ensemble = [                                                                                        #アンサンブル用に複数の学習済みモデルをリストとして読み込み
     tf.keras.models.load_model(p, compile=False)                                                           #各モデルファイル(パスp)を、カスタムレイヤーClipLayerを認識できるようにして読み込み
     for p in MODEL_PATHS                                                                                   #上記の読み込みを、全てのモデルファイルに対して実行
 models_ensemble = [                                                                                                   #アンサンブル用に複数の学習済みモデルをリストとして読み込み
     tf.keras.models.load_model(p, compile=False)                                                                      #各モデルファイル(パスp)を、カスタムレイヤーClipLayerを認識できるようにして読み込み
     for p in MODEL_PATHS                                                                                              #上記の読み込みを、全てのモデルファイルに対して実行
 ]
 test_fnames = sorted([f for f in os.listdir(TEST_FOLDER) if f.endswith('.png') or f.endswith('.jpg')])      #テスト用フォルダ内の画像ファイル名(png/jpg)を取得して並び替え
 os.makedirs(OUTPUT_BASE, exist_ok=True)                                                                     #出力用のベースフォルダを作成(既に存在してもエラーにならない)
 for i in range(1, 6):                                                                                       #評点1〜5の各スコア用サブフォルダを作成するためのループ
     os.makedirs(os.path.join(OUTPUT_BASE, f"score{i}"), exist_ok=True)                                      #各スコアごとの出力サブフォルダを作成
 test_fnames = sorted([f for f in os.listdir(TEST_FOLDER) if f.endswith('.png') or f.endswith('.jpg')])                #テスト用フォルダ内の画像ファイル名(png/jpg)を取得して並び替え
 os.makedirs(OUTPUT_BASE, exist_ok=True)                                                                               #出力用のベースフォルダを作成(既に存在してもエラーにならない)
 for i in range(1, 6):                                                                                                 #評点1〜5の各スコア用サブフォルダを作成するためのループ
     os.makedirs(os.path.join(OUTPUT_BASE, f"score{i}"), exist_ok=True)                                                #各スコアごとの出力サブフォルダを作成
 -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 for fname in test_fnames:                                                                                   #テスト画像ごとにループ
     path = os.path.join(TEST_FOLDER, fname)                                                                 #画像ファイルのフルパスを作成
     img = Image.open(path).convert("RGB").resize(IMAGE_SIZE)                                                #画像を開き、RGB化・リサイズ
     x_input = np.array(img) / 255.0                                                                         #画像をNumPy配列に変換し正規化
     x_input = x_input.reshape(1, *IMAGE_SIZE, 3)                                                            #モデル入力用に配列の形状を調整(バッチ次元追加)
     preds = [model.predict(x_input, verbose=0)[0][0] for model in models_ensemble]                          #各モデルで画像を予測しスコアをリスト化
     avg_score = np.mean(preds)                                                                              #各モデルの予測スコアの平均値を計算します(アンサンブル平均)
     final_score = binning(avg_score)                                                                        #平均スコアを1〜5の整数評点に変換
     save_path = os.path.join(OUTPUT_BASE, f"score{final_score}", fname)                                     #評点ごとのサブフォルダに保存するためのパスを作成
     img.save(save_path)                                                                                     #画像を該当サブフォルダに保存
     print(f"📂 {fname} → 回帰スコア: {avg_score:.2f} → 評点: {final_score}")                              #画像名・回帰スコア・最終評点を表示
 for fname in test_fnames:                                                                                             #テスト画像ごとにループ
     path = os.path.join(TEST_FOLDER, fname)                                                                           #画像ファイルのフルパスを作成
     img = Image.open(path).convert("RGB").resize(IMAGE_SIZE)                                                          #画像を開き、RGB化・リサイズ
     x_input = np.array(img) / 255.0                                                                                   #画像をNumPy配列に変換し正規化
     x_input = x_input.reshape(1, *IMAGE_SIZE, 3)                                                                      #モデル入力用に配列の形状を調整(バッチ次元追加)
     preds = [model.predict(x_input, verbose=0)[0][0] for model in models_ensemble]                                    #各モデルで画像を予測しスコアをリスト化
     avg_score = np.mean(preds)                                                                                        #各モデルの予測スコアの平均値を計算します(アンサンブル平均)
     final_score = binning(avg_score)                                                                                  #平均スコアを1〜5の整数評点に変換
     save_path = os.path.join(OUTPUT_BASE, f"score{final_score}", fname)                                               #評点ごとのサブフォルダに保存するためのパスを作成
     img.save(save_path)                                                                                               #画像を該当サブフォルダに保存
     print(f"📂 {fname} → 回帰スコア: {avg_score:.2f} → 評点: {final_score}")                                        #画像名・回帰スコア・最終評点を表示
 
 # === 検証評価 === 
 →検証データでアンサンブル予測を行い、平均スコアを整数評点に変換して正解と比較できる形に整形する
 val_preds = [model.predict(x_val, verbose=0).flatten() for model in models_ensemble]                        #検証データに対して各モデルで予測し、スコア配列をリスト化
 y_val_pred = np.mean(val_preds, axis=0)                                                                     #各サンプルについて全モデルのスコア平均を計算
 y_val_bin = np.array([binning(s) for s in y_val_pred])                                                      #平均スコアを1〜5の整数評点に変換
 y_true_bin = np.array([binning(s) for s in y_val])                                                          #正解スコアも同様に整数評点に変換
 val_preds = [model.predict(x_val, verbose=0).flatten() for model in models_ensemble]                                  #検証データに対して各モデルで予測し、スコア配列をリスト化
 y_val_pred = np.mean(val_preds, axis=0)                                                                               #各サンプルについて全モデルのスコア平均を計算
 y_val_bin = np.array([binning(s) for s in y_val_pred])                                                                #平均スコアを1〜5の整数評点に変換
 y_true_bin = np.array([binning(s) for s in y_val])                                                                    #正解スコアも同様に整数評点に変換

**6/23 [#j417c623]

-錆の画像から評点を判断するのに用いるスクリプト
--MMLI (=More Machine Learning Images).py … 既存の画像を反転・回転等で学習させる画像枚数を増やすスクリプトのこと。
--CNN+binning

, 特徴 / スクリプト名 , CNN+binning.py , CNN+binning2.py , CNN+binning3.py , CNN+binning4.py 
, モデルの種類 , オリジナルCNN3種 , 強化CNN(層数増加) , EfficientNetV2S / DenseNet121 / MobileNetV3 , 同左 
, アンサンブル学習 , ○ , ○ , ○ , ○ 
, 出力形式 , 回帰+binning , 回帰+binning , 回帰+binning , 回帰+Sigmoid正規化+binning 
, Soft Labeling(評点ぼかし) , ○ , ○ , ○ , ○ 
, 損失関数 , MSE+重みペナルティ , 強化ペナルティ損失関数 , 同左 , 同左 
, 特徴量の利用 , × , × , × , ○(画像+数値特徴:面積、粒径、Sobel量) 
, 特徴量融合方法 , ー , ー , ー , CNN出力ベクトル+数値特徴 → Dense結合 
, 出力スケーリング , × , × , × , ○(シグモイド関数+0〜5.0スケーリング) 
, カスタムbinning関数 , ○ , ○ , ○ , ○ 
, UMAP可視化 , ○ , ○ , ○ , ○ 
, 判別補正(3⇔4の補正など) , × , × , × , ○(特徴量条件付き補正が可能な構造) 
, 使用層の深さ・複雑さ , 普通 , やや深め , 深層+転移学習モデル , 同左 
**手書き数字の画像をCNNで機械学習するのに必要な画像とPythonファイル [#bfidf3ca]
-/home/kouzou/Morii25/hikitugi 内にある画像とPythonファイルについて

***5/21 [#j417c521]
-- 1, Mnist-Hanbetsu-Full_auto4.py (Ver4.0) … Ver3.0ではモデルの学習回数を1回としていたが、より高い精度を出すために学習回数を3回としその中から最も信頼できるモデルを画像ごとに取り出して機械が自動的に判別できるようにした。

-- 2, Mnist-Hanbetsu-Full_auto5.py (Ver5.0) … Ver4.0からCNNの学習方法を毎回変えるようにした(アンサンブル学習)。アンサンブル学習の導入により構造の異なる学習モデルを使うことで特徴の学習傾向に多様性を持たせることができ、全体の分類精度を高めやすくなる。今までは畳込みとプーリングの層を3層にして計3回学習させる方法を取っていたが、今回から3回とも畳込みとプーリング層の変化や関数の有無を交えながら画像の判別をさせるようにした。

--1回目の学習は畳込みとプーリング層が1層の最もシンプルな基本形とし、パラメータも少なめで学習が早いというメリットがある一方で過学習しやすいという側面がある。
--2回目は1回目よりも畳込み層を深くしたことに加えて正則化 (BatchNormalization) も組み込んだ。これにより複雑な特徴を抽出しやすく過学習を抑制できる。
--3回目はより学習させる範囲を大きくし正則化を強化させた学習モデルとした。→ 大きめのフィルターで広範囲の特徴を抽出。

-各モデルの構造比較(表)
,項目 ,モデル1 ,モデル2 ,モデル3
,畳み込み層 ,1層 ,2層 ,2層
,プーリング ,1回 ,1回 ,1回
,正規化	,× ,〇 ,〇
,Dropout ,× ,〇(1回),〇(2回)
,Dense層,64ユニット ,128ユニット ,64ユニット
,出力層	,softmax(10) ,softmax(10) ,softmax(10)
,学習の安定性 ,弱い(過学習しやすい) ,普通(汎化性能〇) ,強い(深く・安定)


ただVer5.0は様々な学習要素を詰め込んでしまったのが原因なのか判別精度がかえって落ちてしまったため、今後手書き数字の画像判別を行なう際にはVer4.0のスクリプトで実行することを勧めておく。


***5/14 [#j417c512]
-新たに作成したPythonファイルについて説明していく
--1, Gazou-Kakou.py … 判別させたい画像に点や直線, 円や多角形等の図形を加えて画像処理させるためのものであり、わざと数字を見せづらくすることで正確に読み取ることができるのか確かめるためのもの。点の数や多角形の頂点を増減したい場合は一括処理関数の "処理を適用:ランダムで描画" の部分を書き換える必要がある。ちなみにこのスクリプトで画像加工すると以下のようになる

&ref(http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250508/0_0.png,150x); ー画像加工→
&ref(http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250508/modified_0_0.png,150x);

&ref(http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250508/5_0.png,150x); ー画像加工→
&ref(http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250508/modified_5_0.png,150x);

&ref(http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250508/7_2.png,150x); ー画像加工→
&ref(http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250508/modified_7_2.png,150x);

---1-1, Gazou-Kakou-Sen_only.py … 上記のGazou-Kakou.pyから "線だけ" を加えた画像処理を行うスクリプトのこと。
---1-2, Gazou-Kakou-Ten_only.py … 上記のGazou-Kakou.pyから "点だけ" を加えた画像処理を行うスクリプトのこと。
---1-3, Gazou-Kakou-Zukei_only.py … 上記のGazou-Kakou.pyから "図形だけ" を加えた画像処理を行うスクリプトのこと。
---※1-1~3 はGazou-Kakou.py内において "処理を適用:ランダムで描画" の部分からでも "#"の有無で自身の好きなようにカスタムできる。

--2, Suuji-Gazou-Seisei.py … 0~9までの数字を自動で生成するスクリプト。一応手書き風文字フォント(KGPrimaryPenmanship.ttf)を使用しているが、似通った文字が複数枚生成されてしまうため使用はあまりおすすめしない。もし自身で画像をペイントツール等を使用して作成するのが面倒だと感じる場合は後述する "Mnist-tyuusyutsu.py" の使用を勧める。

--3, Mnist-tyuusyutsu.py … Mnist上にある画像データを抽出して保存するスクリプトで、保存する枚数は任意で決められる。("画像1クラスあたりの保存枚数"で変更可能)

--4, Hanbetsu-Full_auto.py … 判別画像の処理からそれらの判別及び数字ごとの正答率をテキストファイルに保存するまでの流れを一括で行えるようにしたスクリプトで、Mnist.pyを実行した後にこれを使用することになる。判別画像の名前は ○_1.png または  ○_1.jpg とつけておく必要がある。丸には画像の数字を入力する必要があり、後ろの数字には何枚目なのかを記すこと。例) 9_8.png … "9"と書かれた画像の"8"番目

--5, Mnist-Hanbetsu-Full_auto.py … 上記の Hanbetsu-Full_auto.py にMnistの機械学習を付け加えたスクリプトで基本的に指定されたフォルダ(デフォでは "digits_dataset" になっている)を作成しあとはこのスクリプトを実行するだけで正答率をテキストファイルに保存するまでを自動的に行ってくれる。またMnistを用いた機械学習を行うごとに結果がh5ファイルとして保存されると思うが、ファイルを消さずに上書きという形で学習させるとかえって正答率が下ってしまう過学習という状況が発生しかねないので常に新しいh5ファイルが作成されるようにした。(それまでのファイルは削除されてしまうので注意)

--6, Mnist-Hanbetsu-Full_auto2.py … 5の Mnist-Hanbetsu-Full_auto.py ではデータ(Mnist)を画像処理することなく(下図左側3枚)機械学習させていたが、こちらではMnistのデータを下図右側3枚(イメージ 実際に学習する画像とは異なる)のように画像処理を行ってから機械学習させた。こうすることで識別率を上げることができる。

&ref(http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250513/1_0.png,150x);
&ref(http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250513/4_0.png,150x);
&ref(http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250513/9_0.png,150x);
&ref(http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250513/noised_1_0.png,150x);
&ref(http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250513/noised_4_0.png,150x);
&ref(http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250513/noised_9_0.png,150x);


***5/7 [#j417c507]
--1~9 のjpg画像 … CNNで手書き数字を機械学習させたものに数字を判別させるためのもの。ただし判別精度は良くない。
--mnist.py … mnistという6万枚の手書き数字データ(学習用が5万枚, 判別用が1万枚)を学習してそれがどのくらいの精度で正解できたかをMATE端末上で表示し、その結果を h5 ファイルとして保存するものである。
--mnist-hosei.py … mnist.pyとの違いは画像が傾いていたり文字が歪んでいたりしている状態で機械学習させる事だけで、その他は mnist.py と同じ。
--Hukusuu-hanbetsu.py … mnist.py または mnist-hosei.py を実行した後に用いるファイルで、複数枚の画像を一度に判別するプログラムコードが書かれている。あらかじめ保存しておいた h5 ファイルの名前や複数枚の画像を保存したファイル名が一致しているか確認しておく必要がある。
--Suuji-kakuritsu.py … mnist.py または mnist-hosei.py を実行した後に用いるファイルで、ある1枚に書かれた数字を機械が何と判別したか またその判別結果にはどのくらいの精度があるかをMATE端末上で表示されるものである。あらかじめ保存しておいた h5 ファイルの名前や判別したい画像のファイル名がプログラムコードと一致しているか確認しておく必要がある。
--kani.py … mnist.py または mnist-hosei.py を実行した後に用いるファイルで、判別した画像に何の数字(0 ~ 9)が描かれているかに加えてどのくらいの信頼度があるかをグラフ化した画像が表示されるものである。あらかじめ保存しておいた h5 ファイルの名前や判別したい画像のファイル名がプログラムコードと一致しているか確認しておく必要がある。
--suuji-hanbetsu.py … mnist.py または mnist-hosei.py を実行した後に用いるファイルで、ある1枚に書かれた数字を機械が何と判別したかを確認する。あらかじめ保存しておいた h5 ファイルの名前や判別したい画像のファイル名がプログラムコードと一致しているか確認しておく必要がある。


**錆の写真からSVMで機械学習するまでの流れ [#g1ddf3ca]
 この一連の流れは同じファイル内に保存するのが望ましい
-(1) RGBrironti.py について (コマンド)
--1, MATE端末を開き py ファイルのある hikitugi に移動する (cd hikitugi)
--2, py ファイルを呼び出す (python RGByomitori.py) 
--3, フォルダーのパス入力が求められるので錆の写真があるフォルダーを入力する → Enterキー  (一例: /home/kouzou/sato24/gr/data/1_ppm)
--4, 保存するファイル名を入力する → Enterキー (一例: /home/kouzou/sato24/gr/data/1_ppm/RGBkekka.csv ) この場合錆の写真があるフォルダーに "クリックした座標" , "RGB値"の結果がcsv形式で保存される。
--5, その後ウィンドウのどこかしらに錆の画像が表示されるので、カラースケールの "シアン" , "イエロー" , "マゼンタ" の部分を順番にクリックする。そうするとMATE端末上に [ 画像: ファイル名(.ppm) | クリック位置: (x座標, y座標), RGB値: (R(0~255), G(0~255), B(0~255),) ] 
と表示される。
--6, ファイル内にある写真すべての "シアン" , "イエロー" , "マゼンタ" の部分を順番にクリックする。すべての写真で "シアン" , "イエロー" , "マゼンタ" の部分をクリックすると下のようになり、これと同じような感じでcsvファイルにも保存されている。

&ref(http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250428-1.png,600x);

---補足:保存するファイル名を以前作成したファイル名と同じにすると新たに上書きされるのではなく、既存のデータに加えられる形で保存される。


-(2) matrix.py について (コマンド)
--1, MATE端末を開き py ファイルのある hikitugi に移動する (cd hikitugi) ←必要であれば
--2, py ファイルを呼び出す (python matrix.py) → Enterキー
--3, 結果を書き込むファイルを入力してください と表示されるので入力する。ここでは保存する場所に加えて結果ファイルの名前も”名前 + .txt ”と入力する必要がある。(例: kekka.txt) → Enterキー
--4, シアン・イエロー・マゼンタの各RGB値を入力してください と表示されるので入力する。(0~255 の間) → 入力する値はどれか1枚の写真における"シアン" , "イエロー" , "マゼンタ" のRGB値


-(3) henkan.py について (コマンド)
--1, MATE端末を開き py ファイルのある hikitugi に移動する (cd hikitugi) ←必要であれば
--2, py ファイルを呼び出す (python henkan.py)
--3, 変換行列ファイルのパスを入力してください と表示されるので(2)で作成したtxtファイルを入力する(一例: kekka.txt ) → Enterキー

--4, 補正したいPPM画像のパスを入力してください と表示されるのでppm画像のパス入力する。(例: rating○_○.ppm) → Enterキー
---基本的に/home/kouzou/sato24/gr/data内にある ○_ppm や hg_○_ppm と書かれたファイルから選択するはず (例: /home/kouzou/sato24/gr/data/1_ppm/rating1_1.ppm)

--5, 補正後の画像を保存するパスを入力してください と表示されるので変換後のppm画像をどのパスに保存したいか入力する (例: henkan-after.ppm と入力すると henkan-after というppmファイルが保存される) → Enterキー

-(4) グレースケール化とedge.py について(コマンド)
--1, $ convert rating○_○.ppm -colorspace Gray gray.pgm → gimp と打って Enterキー
--2, py ファイルを呼び出す (python edge.py)
--3, 入力ディレクトリパスの入力が求められる。なお edge.py はpgmファイルのみ対応しているのでpgmファイルで保存されていいる写真のあるフォルダー名を入力する → Enterキー (一例: edge)
--4, 出力ディレクトリパスの入力が求められる。ここでは3で入力したファイルをエッジ処理したものをどこに保存するかを設定する。ここでは一例として(edge_150)と入力する。
--- 3のedgeはエッジ処理したものを入れておくファイル名であり、もしファイル名を入れずにEnterキーを押してしまうとこの場合hikitugiのフォルダー内に保存されてしまうので注意すること。
--5, エッジ処理の閾値1, 2を入力してくださいと表示される
---エッジ処理の閾値1は "Cannyエッジ検出の「低い方のしきい値」" のことである。画像の中で「ここはエッジ」と判断するための数値で、50〜300くらい(50刻み)に設定しておくとよい。
---エッジ処理の閾値2は "Cannyエッジ検出の「高い方のしきい値」" であり、100〜400くらい に設定しておくとよい。
--6, 閾値1, 2 を入力して Enterキー を押してしばらくするとhikitugi内にedge_150というフォルダーが作成される。そのフォルダーを開いて錆の写真が左下 (edge) から右下 (edge_150) のような感じに変換されていれば成功。

http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250424-2.png → http://www.str.ce.akita-u.ac.jp/~gotouhan/j2024/morii/20250424-3.png


-(5) svm.py について (コマンド)
--1, py ファイルを呼び出す前に svm.py ファイル(編集画面)を開く
--2, ファイルを開いたら13行目に書いてある data_dir = 〜 の部分を確認する。data_dir = ( "〜" ) の部分を " edge " に変更してclass_namesも定義する必要があり、そうしないとエラーがでる。今回はclass_namesを作成・定義してこなかったので佐藤さんが作成した 150_300_edge を機械学習= svm させる。
---①  150_300_edgeファイルをhikitugiファイル内にコピーする。
---② 編集画面の13行目: data_dir = "150_300_edge" と編集する。
---③ 編集画面の15行目: class_names = ["mk1_pgm", "mk2_pgm", "mk3_pgm", "mk4_pgm"] になっているのを確認する。
--3, 編集が完了したら python svm.py と入力 → Enterキー


**GIMPでの画像の切り取り方(200×200ピクセルの場合) [#xccc5194]
--1, GIMPで画像を開き上のツールバーから 画像 → ガイド → 新規ガイド と進む
--2, 新規ガイドを選択すると方向と位置を決めることができ、初めは方向を"水平"として位置を"200"に設定する。そうすると画像に青の破線が表示されたと思う。再びツールバーから 画像 → ガイド → 新規ガイド と進み、方向を"水平"位置を"400"に設定する。今度は前に引かれた青の破線よりも200ピクセル分右側に破線が引かれた。これを "600" , "800" , ...と繰り返していく
--3, 水平方向に200ピクセル間隔で線を引けたら次に垂直方向に200ピクセル間隔で線を引いていく。ツールーバーから 画像 → ガイド → 新規ガイド と進み、方向を"垂直" 位置を"200"とする。水平の時と同様に位置を200ずつ変えながら線を引いていくと碁盤状に線が引けたのではないかと思う。
--4, そうしたらツールバーから 画像 → ガイドを使用して切り分け と選択すると200×200ピクセルで分割した画像が出来上がる。

トップ   編集 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS