// 画像計測アプリケーション // Created by Tatsuya Shirai // National Institute of Technology, Suzuka college // Mechanical Department // // Ver. 1.0 : 2022.06.07 // Readme: // ファイルを一つずつ選択する単一画像モードと,フォルダー単位で選択するフォルダーモードがあります. // 各画像の計測点の数が決まっているのであれば,「定数」の Max_measure の数を指定して下さい. // もし決まっていないのであれば,おおよそ予想される最大値を指定して下さい. // Max_measure で指定した数の計測が完了したら,自動的に次の画像ファイルを選択するダイアログボックスが表示されます. // 単一画像モード,フォルダーモード共に,現在の画像の計測を終了したい場合は(右クリック)して下さい.単一画像モードの場合は次のファイルを開くダイアログボックスが表示されます. // フォルダーモードの場合の途中でフォルダーモードを終了したい場合も「ESC」キーを押して下さい. // メニュー画面が表示された状態で「ESC」キーを押すとプログラムは終了します. // 出力されるデータの書式は,一行目にスケール,二行目以下は,”測定点の番号,X座標,Y座標,赤,緑,青”です.色はそのピクセルの色を各色に分解したものです. // 定数 final int Max_measure = 32; // ここで指定した数のポイントを計測し終えたら自動的に次の画像の選択用ダイアログボックスが表示される // フォルダーモードの場合はフォルダー内の次の画像が自動的に開かれる final int Target_size = 5; // ターゲットマーカーのサイズ final int Target_color[][] = {{255, 80, 80}, {255, 255, 255}, {0, 0, 0}}; // ターゲットの色 : 赤,白,黒 final float Initial_scale = 1.0; // 画像のスケール(倍率):拡大のみ final String Export_ext = ".txt"; // 出力するデータファイルの拡張子 currentImageClass ci; void setup() { ci = new currentImageClass(); size(400, 500); //サイズ変更を許可する surface.setResizable(true); } void draw() { if (ci.img != null) { // 画像が正常にロードされている場合 int cnt = 0; image(ci.img, 0, 0); for (cnt = 0; cnt < ci._counter; cnt++) ci.target.plot(ci.measured[cnt].px, ci.measured[cnt].py); } else { //ヘルプ:画像が選択されていない場合 int x = 16; int y = 32; int dx = 150; int dy = 40; noStroke(); fill(72, 72, 72); surface.setSize(400, 500); rect(0, 0, 399, 499); textSize(24); fill(Target_color[ci.target.t_color][0], Target_color[ci.target.t_color][1], Target_color[ci.target.t_color][2]); text("(Left click)", x, y); text(": measure", x + dx, y); y += dy; text("Shift+(left)", x, y); text(": back", x + dx, y); y += dy; text("(Right clisk)", x, y); text(": end / select file", x + dx, y); y += dy; text("[ESC]", x, y); text(": end / exit", x + dx, y); y += dy; text("[p]", x, y); text(": change plot", x + dx, y); y += dy; text("[c]", x, y); text(": change color", x + dx, y); y += dy; text("[+]", x, y); text(": scale up", x + dx, y); y += dy; text("[-]", x, y); text(": scale down", x + dx, y); y += dy; text("[0]", x, y); text(": reset scale", x + dx, y); y += dy; text("[s]", x, y); text(": show settings", x + dx, y); y += dy; text("[d]", x, y); text(": show datas", x + dx, y); y += dy; text("[f]", x, y); text(": select folder", x + dx, y); y += dy; } } void mousePressed() { if (mouseButton == RIGHT) { // 右クリック時 ci.flush_data(); // データを出力 if (ci.folder_mode) { // フォルダーモードの場合の if (ci.next_image() == null) ci.quit_folder_mode (); // もう画像がフォルダー内に無いならば終了 } else { // 単体画像モードの場合はファイル選択ダイアログボックスを表示 open_fileselector(); } } else if (mouseButton == LEFT) { // 左クリック時 if (ci.img != null) { if (keyPressed && keyCode == SHIFT) ci.back(); // 計測のキャンセル(バック) else ci.measure(mouseX, mouseY); // 計測 } } } void keyPressed() { switch (keyCode) { case ESC : if (ci.img == null) terminate(); else { // 画像計測中 ci.flush_data(); // データを出力 if (ci.folder_mode) ci.quit_folder_mode(); // フォルダーモードならば終了 key = 0; // keyをクリアしないとProcessingが終了してしまう } // 画像計測時以外は,このままProcessingが終了する break; case 'p' : case 'P' : ci.target.change_shape(); break; case 'c' : case 'C' : ci.target.change_color(); break; case 's' : case 'S' : show_settings(); break; case 107 : case 59 : case '+' : ci.rescale( 0.5); break; case 109 : case '-' : ci.rescale(-0.5); break; case 96 : case '0' : ci.rescale( 0.0); break; case 'd' : case 'D' : show_datas(); break; case 'f' : case 'F' : selectFolder("Select a folder to process:", "folderSelected"); break; } } //// ファイル・フォルダー選択ダイアログボックス関係の関数 // ファイル選択ダイアログボックスの呼び出し void open_fileselector() { selectInput("Select a file to process:", "fileSelected"); } // ファイル選択後の処理 void fileSelected(File selection) { ci.flush_data(); if (selection == null) ci.img = null; else ci.load(selection.getAbsolutePath()); } // フォルダーモード void folderSelected(File selection) { File[] files; if (selection == null) return; // キャンセル時 files = selection.listFiles(); ci.flush_data(); // 計測済みデータの書き出し println("User select folder = " + selection.getAbsolutePath()); ci.open_folder(selection.listFiles()); } //// それ以外のユーザー関数 // 終了時の処理 void terminate() { if (ci.img != null) ci.export_data(); // 計測済みならば出力 println("Exit program."); exit(); } // 設定を表示 void show_settings() { println("[Settings]"); println("Max_measure = " + Max_measure); println("Target_size = " + Target_size); println("Target_color = " + Target_color[0] + ", " + Target_color[1] + ", " + Target_color[2]); println("Scale = " + ci.scale); } // 計測済みのデータを表示 void show_datas() { if (ci.img == null) return; if (ci._counter <= 0) println("no datas"); int n; println("[Datas]"); for (n = 0; n < ci._counter; n++) println(n + " : " + ci.measured[n].px + " , " + ci.measured[n].py); }