diff --git a/.claude/rules/testing.md b/.claude/rules/testing.md index 5128914..3d02521 100644 --- a/.claude/rules/testing.md +++ b/.claude/rules/testing.md @@ -56,7 +56,7 @@ | ビルドテスト | ソリューション全体 | 自動(MSBuild) | 全コミット前 | | 回帰テスト | 色補正・チャート検出の出力(合成チャート,および実機で録画したチャート・白板のフレーム) | 自動(基準データ比較) | リファクタ・修正の前後 | | セルフテスト | 依存ロード・偽カメラでのプレビュー経路・合成チャートでの校正〜保存 | 自動(`--selftest`.`/verify`・`/implement` Phase 1b) | 依存更新・層②〜④の変更後,手動テストの前段 | -| 実機テスト | 層④のうち数値で判定できる SDK の実呼び出し(接続・プレビュー・露光/ゲイン・光源・閉じる・再接続) | 自動(`--hwtest`.Claude が実機を操作する.**ユーザーの合図があるときだけ**) | 層③・④の変更後,手動テストの前段 | +| 実機テスト | 層④のうち数値で判定できる SDK の実呼び出し(接続・プレビュー・露光/ゲイン・光源・閉じる・再接続.`--with-chart` では実チャートでの校正・撮影と保存・保存中/校正中に閉じる) | 自動(`--hwtest`.Claude が実機を操作する.**ユーザーの合図があるときだけ**) | 層③・④の変更後,手動テストの前段 | | 手動テスト | SDK の実呼び出し・実画像の見た目(層④) | 手動(実機) | 機能追加・修正の完了時 | ※ 実機録画データ(舌診チャート・白板のフレーム)による回帰は PLAN_05 のフェーズ 4 で整備する.**舌の画像は個人情報のためテストデータに含めない**. @@ -96,7 +96,7 @@ | `LightSource` のシリアル通信 | 光源(実機)に依存する.ポートを開けなかったときの扱い等の判断は層③として切り出す | | 画面描画の見た目(`Form1`・`PreviewMonitor` の表示内容) | 目視でしか判断できない.表示用 Bitmap の所有権・更新の流れはセルフテスト(`preview`)で担保する | -層④のうち次の項目は,実機テスト([PLAN_06](../../docs/03_PLAN/PLAN_06_実機自動テスト計画.md).`python scripts/verify/run_hwtest.py --camera `.`HWTEST` フラグ)で Claude が実機を操作して自動で確認できる.**ユーザーが会話の中で合図したときだけ**実行し,合図が無ければ「検証不能(合図なし)」とする(手順・しきい値は `.claude/verify-profile.md` の「実機テスト」節). +層④のうち次の項目は,実機テスト([PLAN_06](../../docs/03_PLAN/PLAN_06_実機自動テスト計画.md).`python scripts/verify/run_hwtest.py --camera [--with-chart]`.`HWTEST` フラグ)で Claude が実機を操作して自動で確認できる.**ユーザーが会話の中で合図したときだけ**実行し,合図が無ければ「検証不能(合図なし)」とする(手順・しきい値は `.claude/verify-profile.md` の「実機テスト」節). | 項目 | 確認できること | | --- | --- | @@ -106,8 +106,12 @@ | `light` | 光源の点灯・消灯が明るさに効き,ポートを閉じた後に開き直せる | | `close-preview` | プレビュー中に閉じる処理を呼んでもすぐ戻り,後始末の順序が正しい | | `reconnect` | 切断した後に再接続でき,フレームが届く | +| `calibrate`(`--with-chart`) | 実物の舌診チャートで自動校正が完了し,校正後のフレームを変換した色票が参照値に近い(8bit・チャネルごとの差) | +| `shot`(`--with-chart`) | 単発・連続撮影で撮影画像・sRGB 変換画像・Info.csv が保存され,撮影時刻の間隔が設定どおり | +| `close-saving`(`--with-chart`) | 保存中に閉じようとすると取り消され,保存の完了後は閉じられる(後始末の順序) | +| `close-calibrating`(`--with-chart`) | 再接続して校正中に閉じる処理を呼んでもすぐ戻る | -※ 2026-10-08 時点で実機テストを通したのは ImagingSource だけ(Lumenera の実機テストは行わない方針.PLAN_06「対象機種」).校正・撮影・保存中や校正中に閉じる等のチャートが要る項目(PLAN_06 フェーズ 2)は未実装のため,引き続き手動テストで確認する. +※ 2026-10-08 時点で実機テストを通したのは ImagingSource だけ(Lumenera の実機テストは行わない方針.PLAN_06「対象機種」).チャートが要る項目(`--with-chart`.PLAN_06 フェーズ 2)も同日に実物のチャートで合格した.`--with-chart` はチャート不要の検査を行わないため,両方を続けて実行する.変換画像の見た目(17 次元の変換の点状のノイズ等.PLAN_06「17 次元の変換のノイズ」)は数値で判定しきれないため,引き続き手動で確認する. ※ 層④に手を入れた場合は**設計レビュー+実機回帰**で挙動を確認する.その前段として,実機なしで通せる範囲はセルフテスト(`python scripts/verify/run_selftest.py`.`.claude/verify-profile.md`)で,上表の実機テストの項目はユーザーの合図のもと実機テストで確認できる.`/implement` の Tester フェーズでは,対象が層④だけの場合に限り,テストを書かずに設計レビューで判断してよい.層②・③に当たる部分が含まれるなら,その部分のテストは書く. diff --git a/.claude/verify-profile.md b/.claude/verify-profile.md index ee64e49..b5ddbe5 100644 --- a/.claude/verify-profile.md +++ b/.claude/verify-profile.md @@ -62,17 +62,22 @@ | 用途 | コマンド | | --- | --- | | Lumenera を検査する(通常は行わない.ユーザーの明示指示があるときだけ) | `python scripts/verify/run_hwtest.py --camera lucam` | -| ImagingSource を検査する | `python scripts/verify/run_hwtest.py --camera iscam` | +| ImagingSource を検査する(チャート不要の検査) | `python scripts/verify/run_hwtest.py --camera iscam` | +| ImagingSource を検査する(チャートが必要な検査.上の行に続けて実行する) | `python scripts/verify/run_hwtest.py --camera iscam --with-chart` | -- `--with-chart`(チャートが必要な検査.PLAN_06 フェーズ 2)は未実装.指定すると機材に触れずに終了コード 2 になるため使わない +- `--with-chart`(チャートが必要な検査.PLAN_06 フェーズ 2)を指定すると,チャート不要の検査(`preview`〜`reconnect`)の代わりに `calibrate`・`shot`・`close-saving`・`close-calibrating` を行う(`connect`・`cleanup` は両方で行う).校正は止めない.**チャート不要の検査は行わないため,`--camera iscam` と `--camera iscam --with-chart` をカラーチャートをはめたまま続けて実行する**(付け外しは不要) +- `--keep`(`TIASshot.exe` の `--hwtest-keep`)を付けると,合格時も作業フォルダ(`%TEMP%\TIASshot-hwtest\work-*`)を残し,`--with-chart` では校正後のフレームとその変換画像を証拠の画像(`evidence\calibrated-frame-raw.png`・`evidence\calibrated-frame-srgbNN.png`.`NN` は変換の次元)として保存する.画像を人間に見せたいときや,色の誤差を調べるときに使う(判定は変わらない) +- 所要時間の目安(ビルドを除いた検査の部分): チャート不要の検査は約 30〜40 秒,`--with-chart` は約 50〜55 秒(校正 約 9〜10 秒・撮影 約 16 秒・保存中に閉じる 約 20〜24 秒・校正中に閉じる 約 3.5〜4 秒).実機テスト内部の全体の上限はチャート不要 600 秒・`--with-chart` 1200 秒,ランナーの打ち切りはそれぞれ 720 秒・1320 秒 - `--no-clean`(Debug 出力を消さない)は開発時の短縮用であり,判定には使わない - ランナーは Debug|x64 をビルドしてから `TIASshot.exe --hwtest --camera <機種> --hwtest-out <結果ファイル>` を実行ファイルのフォルダで実行する.NUnit テスト・セルフテストは実行しない - 出力先: `.verify/hwtest/run-<日時>/`(`summary.json`・`build.log`・`hwtest-result.txt`(UTF-8 BOM 付き)) -- ランナーの終了コード: `0`=全項目合格,`1`=不合格あり(ビルド失敗・検査の不合格・タイムアウト),`2`=前提条件を満たさない(→「検証不能」.ツール未導入・TIASshot 起動中・指定機種が見つからない・引数不正・`--with-chart`) -- 実機テスト単体の終了コード(`summary.json` の `hwtest_exit_code`): `0`=全項目合格,`1`=不合格あり,`2`=実機テスト自体の異常(引数不正・指定機種が見つからない・未実装の指定),`3`=タイムアウト(各項目の上限または全体 10 分.ハングの疑い),`null`=ランナーが 720 秒で打ち切った +- ランナーの終了コード: `0`=全項目合格,`1`=不合格あり(ビルド失敗・検査の不合格・タイムアウト),`2`=前提条件を満たさない(→「検証不能」.ツール未導入・TIASshot 起動中・指定機種が見つからない・引数不正) +- 実機テスト単体の終了コード(`summary.json` の `hwtest_exit_code`): `0`=全項目合格,`1`=不合格あり,`2`=実機テスト自体の異常(引数不正・指定機種が見つからない),`3`=タイムアウト(各項目の上限または全体(チャート不要 10 分・`--with-chart` 20 分).ハングの疑い),`null`=ランナーが打ち切った(チャート不要 720 秒・`--with-chart` 1320 秒) ### 検査項目 +#### チャート不要(`--with-chart` なし) + | ID | 確認内容 | 測定値と判定(しきい値は ImagingSource の実測(PLAN_06 フェーズ 1)から決めた.結果ファイルの表記は「暫定」のまま) | | --- | --- | --- | | `connect` | 指定した機種だけに接続でき,機種名・シリアル番号が取れる | 列挙した台数,`Connect()` の成否と所要時間,機種名・シリアル番号 | @@ -83,11 +88,23 @@ | `reconnect` | 切断した後に再接続できる | 2 回目の `Connect()` の成否・シリアル番号の一致・再接続後のフレームの到着(5 フレーム以上) | | `cleanup` | 後始末と書き込み禁止の確認 | 露光・ゲインを戻す → カメラ切断 → 光源のポートを閉じる(消灯はしない),の成否.実行ファイルのフォルダの `*.xml`(`config.xml`・デバイス状態ファイル)の内容が変わっていないこと,本番の保存先の今日のフォルダが変わっていないこと | +#### チャートが必要(`--with-chart`) + +`connect`・`cleanup` は上表と同じ(`cleanup` ではホワイトバランスを戻さない.校正でカメラ側の値だけが変わり,次の接続でデバイス状態ファイルの値に戻る).しきい値は ImagingSource の実測(PLAN_06 フェーズ 2)から決めた. + +| ID | 確認内容 | 測定値と判定 | +| --- | --- | --- | +| `calibrate` | 実物の舌診チャートで自動校正が完了し,校正後のフレームを変換した色票が参照値に近い | 校正の待ち時間(最初のフレーム → チャート検出 → 校正完了.上限 60 秒),校正中の表示の順,校正完了後に撮影ボタンが有効になること,校正データが一時フォルダに保存されること.校正後のフレームを校正の変換行列で変換し,24 色票の平均と参照値(`tcc_srgb`)の差を **8bit(保存画像と同じ切り詰め後)・チャネルごとの差の絶対値**で判定する: 平均 5 以下,白色票を除いた最大 10 以下,白色票の最大 40 以下(**暫定**.下記「既知のノイズ」).白色票は参照値の BGR の和が最大の色票(13 番).ΔE76・白飛びの割合・当てはめの誤差(`TCC_sRGB17.csv`)は参考 | +| `shot` | 単発・連続撮影で撮影画像・sRGB 変換画像・Info.csv が保存され,撮影時刻の間隔が設定どおり | 単発 1 枚・連続 3 枚(間隔 1000 ms)を撮影し,撮影直後は保存中で撮影ボタンが無効,保存の完了(上限 90 秒)後に再有効化されること,保存されたファイル(撮影画像・変換画像・Info.csv.大きさ 0 でない)と撮影ログの行数・備考,撮影時刻の間隔と設定値の差(100 ms 以下),エラー通知が無いこと | +| `close-saving` | 保存中に閉じようとすると取り消され,保存の完了後は閉じられる | 連続 5 枚(間隔 0 ms.保存が先に終わったら 10 枚で再試行)の保存中に閉じる処理を呼び,取り消されること・表示「保存中です.保存完了後に閉じてください」・後始末が走っていないこと.保存の完了後に閉じる処理の所要時間(上限 1000 ms)・後始末の順序(closing → timer → camera → light)・閉じた後 1 秒間に届いたフレーム数(2 以下) | +| `close-calibrating` | 再接続して校正中に閉じる処理を呼んでもすぐ戻る | 再接続(シリアル番号の一致)→ 校正中になる(上限 60 秒)→ 500 ms 後に閉じる処理を呼び,所要時間(上限 1000 ms)・後始末の順序・閉じた後に届いたフレーム数(2 以下)・例外の有無 | + ### 判定の読み方 -- `hwtest-result.txt` はセルフテストと同じ書式(`[PASS] : ...` / `[FAIL] : ...` の見出し行,` - ` 情報・` WARN:` 参考・` FAIL:` 失敗理由の詳細行,最終行 `RESULT: PASS (7/7)` または `RESULT: FAIL (...)`).冒頭に暫定しきい値の一覧(`thresholds (暫定)`)と校正の扱い(`校正: 停止(チャート不要の検査…)`)が出る +- `hwtest-result.txt` はセルフテストと同じ書式(`[PASS] : ...` / `[FAIL] : ...` の見出し行,` - ` 情報・` WARN:` 参考・` FAIL:` 失敗理由の詳細行,最終行 `RESULT: PASS (7/7)`(`--with-chart` は `RESULT: PASS (6/6)`)または `RESULT: FAIL (...)`).冒頭に行う検査の一覧(`checks:`),暫定しきい値の一覧(`thresholds (暫定)`),全体の上限(`overall timeout:`),校正の扱い(`校正: 停止(チャート不要の検査…)` または `校正: 有効(チャートが必要な検査…)`)が出る - **測定値(フレームレート・平均輝度・所要時間)は PASS / FAIL にかかわらず詳細行に出る**.暫定しきい値で FAIL した場合は,測定値を報告に必ず書く(しきい値の決め直しに使う) - タイムアウト時は,止まった項目の見出しの下に途中までの測定値と `FAIL: タイムアウト: ...(実行中のステップ: ...)` が出る.どの SDK 呼び出しで止まったかはステップ名で特定する +- タイムアウト時は,その下に UI スレッド・保存スレッドのマネージドスタック(` - UI スレッド(ManagedThreadId ...)のマネージドスタック ...:` に続く ` at ...` の行)と,自プロセスのダンプのパス・大きさ(` - ミニダンプ: \hang-<日時>.dmp(全メモリ,... MB ...)`.書けなければ `WARN:`)も出る.ダンプは作業フォルダに残るので,報告にパスを書き,`.dmp` を Visual Studio(「マネージドのみでデバッグ」→ 並列スタック)か WinDbg(`.loadby sos clr` → `~*e !clrstack`)で開いて止まった場所を調べる - 指定機種が見つからない場合は `RESULT: FAIL (camera not found: <機種>)`(終了コード 2).機材の接続を人間に依頼する ### 前提条件 @@ -104,16 +121,19 @@ - 平均輝度・フレームレートは照明・被写体・カメラの個体差で変わる.判定は変化の向きと量で行い,絶対値は判定しない - 実測(ImagingSource DFK 33UX178・カラーチャートをはめた状態): フレームレート 13〜31 fps(実行ごとのばらつきが大きい),光源の点灯と消灯の差 149〜196,閉じる処理 75〜221 ms.これより大きく外れたら,しきい値より先に照明・チャート・機材の状態を疑う +- `--with-chart` の実測(同上.2026-10-08〜09 の 4 回): 校正の待ち時間 5.0〜7.9 秒(チャート検出まで 1.6〜3.0 秒+校正 3.4〜4.9 秒),色の誤差の平均 1.46〜1.57・白色票を除いた最大 3.47〜3.73・白色票 24.33〜27.35(ΔE76 の平均 1.17〜1.26),撮影間隔のずれ 4〜63 ms,保存は 1 枚あたり約 3.3〜11 秒,保存の完了後に閉じる 33〜76 ms,校正中に閉じる 53〜98 ms.**重いアプリ(Fusion360・Docker・WSL・ブラウザ等)が動いていると,校正・保存が 1.5〜3 倍遅くなり,撮影間隔のずれも大きくなる**(2026-10-09 の実測).保存の待ちの上限は 180 秒.これより大きく外れたら,しきい値より先にチャートのはまり方・照明・機材の状態を疑う +- **白色票の誤差が大きいのは 17 次元(3 次)の変換の性質**(上流 v1.6 でも同じ.PLAN_06「17 次元の変換のノイズ」): 白色票の入力のばらつきが約 10 倍に増幅され,8bit に切り詰めると点状のノイズ・白飛びになる(白色票の 255 の画素 約 73%).平均の色は合っている.白色票のしきい値 40 は対策が決まるまでの暫定であり,白色票だけが 40 を超えた場合は不具合と決めつけず,測定値(白色票の画素の統計・白飛びの割合)を添えて報告する - 飽和は「254 以上の画素の割合が 1% を超える」で判定する(平均輝度では判定しない).上げた向きの結果が飽和した場合,または真っ暗(平均輝度 5 以下)の場合,その向きの確認は省かれる(詳細行に「確認しない」と出る).両方とも省かれると FAIL になる.基準探しで中間の明るさにできなかった場合も FAIL になる - 露光・ゲインが設定範囲の端にあると,その向きの設定が変わらず確認が省かれる(詳細行に「反映されませんでした」と出る) - `exposure-gain` の `WARN: 元に戻した後の平均輝度が最初と離れています` は参考(判定は設定値の読み戻しで行う) - 実際のフォームが表示される(副ディスプレイがあればプレビューモニタも開く).メモリ観測ウィンドウ(`MEMMONITOR`)は開かない +- **実行中はユーザーに画面(TIASshot のウィンドウ)を操作しないよう案内する**.実行中にウィンドウを閉じると閉じる処理が検査の待機の中で割り込み,検査が戻らずタイムアウトしうる(2026-10-09 に撮影中に閉じられて shot がタイムアウトした).合図を受けたら,実行前に「画面に触らないでください」と伝える ### 後始末 - 実機テストは終了時(失敗時も)に「変えた露光・ゲインを元に戻す → カメラ切断 → 光源のポートを閉じる」を行い,`cleanup` 項目に結果が出る.光源は消灯しない(アプリの終了時と同じく点いたまま残るのが仕様.上流 v1.7 と同じ).`light` 項目は点灯・消灯・再点灯を検査し,最後は点灯した状態で終わる - タイムアウト・未処理例外の場合は光源のポートだけを緊急に閉じる(消灯はしない.カメラには触れない.露光・ゲインは次の接続で設定ファイルの値に戻る).`WARN: 緊急の後始末: 光源のポートのクローズが 5 秒以内に終わりません` が出たら,ポートが開いたままの可能性を人間に報告する(光源が点いたままなのは仕様であり報告不要.`light` 項目の途中(消灯中)で止まった場合は消灯したまま残りうる) -- 書き込み先は `%TEMP%\TIASshot-hwtest\work-<日時>-\`(一時設定ファイル `config.hwtest.xml`.チャート不要の検査では校正を止めるため校正データは書かれない)と `.verify/hwtest/run-<日時>/` だけ.合格時と前提を満たさずに終わった場合(終了コード 2)は `work-*` を自動削除し(`--hwtest-keep` 指定時は残す),不合格(1)・タイムアウト(3)時は残して結果ファイルの末尾に `work dir kept: <パス>` と出る.残った `work-*` の有無とパスを報告の「後始末」に書く +- 書き込み先は `%TEMP%\TIASshot-hwtest\work-<日時>-\`(一時設定ファイル `config.hwtest.xml`.チャート不要の検査では校正を止めるため校正データは書かれない.`--with-chart` では校正データ・撮影データ(`data\<日付>\`)と,`--keep` 指定時は証拠の画像(`evidence\`)が書かれる)と `.verify/hwtest/run-<日時>/` だけ.合格時と前提を満たさずに終わった場合(終了コード 2)は `work-*` を自動削除し(`--keep`(`--hwtest-keep`)指定時は残す),不合格(1)・タイムアウト(3)時は残して結果ファイルの末尾に `work dir kept: <パス>` と出る.残った `work-*` の有無とパスを報告の「後始末」に書く - 同梱の `config.xml`・デバイス状態ファイル(`{DeviceName}.xml`)・本番の保存先には書き込まない(`cleanup` で確認する) ## 前提条件と確認方法 (Preconditions) @@ -153,7 +173,7 @@ ## 禁止操作 (Prohibited Operations) - `--selftest` を付けない `TIASshot.exe` の起動(UI が開き,実機カメラ・光源(シリアルポート)へ接続を試みる) - - 例外: ユーザーの合図があるときの `python scripts/verify/run_hwtest.py --camera `(上記「実機テスト」節).`TIASshot.exe --hwtest` の直接実行・合図なしの実行・`Release` の exe での実行はしない + - 例外: ユーザーの合図があるときの `python scripts/verify/run_hwtest.py --camera [--with-chart] [--keep]`(上記「実機テスト」節).`TIASshot.exe --hwtest` の直接実行・合図なしの実行・`Release` の exe での実行はしない - `config.xml`(リポジトリ内・bin 内とも)や本番の保存先フォルダ(`C:\TIAS_Data` 等)の編集・削除 - 自分が起動していないプロセスの停止(人間が起動した TIASshot・Visual Studio のデバッグ実行を止めない) - `packages.bak-*` 以外のリポジトリ内ディレクトリの手動削除・改名(`packages` の退避と復元はランナーの `--full` だけが行う) diff --git a/CLAUDE.md b/CLAUDE.md index 58bfe19..1cdfa71 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ ## 開発進捗 -最新: 実機自動テスト(PLAN_06 フェーズ 1)を実装し,ImagingSource の実機で 7 項目が合格した(Lumenera の実機テストは行わない方針) +最新: 実機テストにチャートが必要な検査(校正・撮影・保存中/校正中に閉じる)を追加し ImagingSource で合格.17 次元の変換のノイズ(白色票の点状のノイズ・白飛び)は上流 v1.6 から同じと確認(対策は要判断) ※ 本欄は**最新ステップ 1 行のみ上書き更新**.詳細な進捗履歴(動機・設計判断・失敗パターン)は [docs/PROGRESS.md](docs/PROGRESS.md) に追記する.運用ルールは `.claude/rules/progress-log.md` を参照(該当ファイル編集時に自動ロードされる). ## 必須ルール(コード実装時) diff --git "a/docs/02_ENV/ENV_04_\351\226\213\347\231\272\343\202\263\343\203\236\343\203\263\343\203\211.md" "b/docs/02_ENV/ENV_04_\351\226\213\347\231\272\343\202\263\343\203\236\343\203\263\343\203\211.md" index 2075837..bff6b75 100644 --- "a/docs/02_ENV/ENV_04_\351\226\213\347\231\272\343\202\263\343\203\236\343\203\263\343\203\211.md" +++ "b/docs/02_ENV/ENV_04_\351\226\213\347\231\272\343\202\263\343\203\236\343\203\263\343\203\211.md" @@ -151,7 +151,7 @@ ## 実機テスト (Hardware Test) -実機のカメラと光源を操作して,接続・プレビュー・露光/ゲイン・光源・閉じる処理・再接続を検査する(`Debug|x64` のみ.[ENV_06](ENV_06_ビルド構成とビルドフラグ.md) の `HWTEST`.計画は [PLAN_06](../03_PLAN/PLAN_06_実機自動テスト計画.md)).実際の `Form1` が表示される. +実機のカメラと光源を操作して,接続・プレビュー・露光/ゲイン・光源・閉じる処理・再接続と,`--with-chart` では実物の舌診チャートでの校正・撮影と保存・保存中/校正中に閉じる処理を検査する(`Debug|x64` のみ.[ENV_06](ENV_06_ビルド構成とビルドフラグ.md) の `HWTEST`.計画は [PLAN_06](../03_PLAN/PLAN_06_実機自動テスト計画.md)).実際の `Form1` が表示される. **ユーザーの合図があるときだけ実行する**(撮影の本番中に機材を操作しないため.Claude は合図なしに実行しない). @@ -161,10 +161,15 @@ - 検査する機種のカメラと光源が開発 PC に接続されている - カメラの前の穴にカラーチャート(または白板)がはめてある(チャート不要の検査の間は自動校正を止める) - TIASshot が起動していない(起動中ならランナーは実行せずに終了コード 2 を返す) +- **実行中は TIASshot のウィンドウを操作しない**(閉じると検査が戻らずタイムアウトしうる).重いアプリが動いていると校正・保存が遅くなる(保存の待ちの上限は 180 秒) ```powershell # ビルド(Debug|x64)→ 実機テスト(結果は .verify/hwtest/run-<日時>/).対象は ImagingSource だけ python scripts/verify/run_hwtest.py --camera iscam +# 続けてチャートが必要な検査(カラーチャートをはめたまま.チャート不要の検査は行わないため上の行と両方実行する) +python scripts/verify/run_hwtest.py --camera iscam --with-chart +# 合格時も作業フォルダを残し,--with-chart では証拠の画像(evidence\*.png)も保存する +python scripts/verify/run_hwtest.py --camera iscam --with-chart --keep # Lumenera(通常は行わない.PLAN_06「対象機種」) python scripts/verify/run_hwtest.py --camera lucam # 開発中の素早い再確認(Debug 出力を消さない.判定には使わない) @@ -176,10 +181,11 @@ Get-Content "$env:TEMP\tias-hwtest.txt" # 各項目の PASS/FAIL と測定値(UTF-8 BOM 付き) ``` -- 書式: `python scripts/verify/run_hwtest.py --camera [--with-chart] [--no-clean]`.`--with-chart`(チャートが必要な検査.PLAN_06 フェーズ 2)は未実装で,指定すると機材に触れずに終了コード 2 になる. -- 単体の書式: `TIASshot.exe --hwtest --camera [--hwtest-out <結果ファイル>] [--with-chart] [--hwtest-keep]`.`--hwtest-keep` を付けると合格時も作業フォルダ(`%TEMP%\TIASshot-hwtest\work-*`)を残す(不合格・タイムアウト時は常に残る). +- 書式: `python scripts/verify/run_hwtest.py --camera [--with-chart] [--keep] [--no-clean]`.`--with-chart`(チャートが必要な検査.PLAN_06 フェーズ 2)は `calibrate`・`shot`・`close-saving`・`close-calibrating` を行い(校正は止めない),チャート不要の検査(`preview`〜`reconnect`)は行わない(`connect`・`cleanup` は両方で行う).`--keep` は単体の `--hwtest-keep` を付けて実行する. +- 単体の書式: `TIASshot.exe --hwtest --camera [--hwtest-out <結果ファイル>] [--with-chart] [--hwtest-keep]`.`--hwtest-keep` を付けると合格時も作業フォルダ(`%TEMP%\TIASshot-hwtest\work-*`)を残し(不合格・タイムアウト時は常に残る),`--with-chart` では校正後のフレームとその変換画像(`evidence\calibrated-frame-raw.png`・`evidence\calibrated-frame-srgbNN.png`)も保存する.`--with-chart` の撮影データ・校正データは作業フォルダの `data\` に保存される(本番の保存先には書かない). +- 所要時間(ビルドを除いた検査の部分): チャート不要の検査 約 30〜40 秒,`--with-chart` 約 50〜55 秒. - 出力先: `.verify/hwtest/run-<日時>/`(`build.log`・`hwtest-result.txt`・`summary.json`). -- ランナーの終了コード: `0`=全項目合格,`1`=不合格あり(ビルド失敗・検査の不合格・タイムアウト),`2`=前提条件を満たさない(ツール未導入・TIASshot 起動中・指定機種が見つからない・引数不正・`--with-chart`). -- 実機テスト単体の終了コード(`summary.json` の `hwtest_exit_code`): `0`=全項目合格,`1`=不合格あり,`2`=実機テスト自体の異常(引数不正・指定機種が見つからない・未実装の指定),`3`=タイムアウト(各項目の上限または全体 10 分.ランナーでは `1` になる),`null`=ランナーが 720 秒で打ち切った. +- ランナーの終了コード: `0`=全項目合格,`1`=不合格あり(ビルド失敗・検査の不合格・タイムアウト),`2`=前提条件を満たさない(ツール未導入・TIASshot 起動中・指定機種が見つからない・引数不正). +- 実機テスト単体の終了コード(`summary.json` の `hwtest_exit_code`): `0`=全項目合格,`1`=不合格あり,`2`=実機テスト自体の異常(引数不正・指定機種が見つからない),`3`=タイムアウト(各項目の上限または全体(チャート不要 600 秒・`--with-chart` 1200 秒).ランナーでは `1` になる),`null`=ランナーが打ち切った(チャート不要 720 秒・`--with-chart` 1320 秒). - NUnit テスト・セルフテストは実行しない(それぞれ `run_tests.py`・`run_selftest.py`). - 検査項目・しきい値・判定の読み方は `.claude/verify-profile.md` の「実機テスト」節と [TEST_01](../06_TEST/TEST_01_テスト仕様.md) を参照する. diff --git "a/docs/03_PLAN/PLAN_06_\345\256\237\346\251\237\350\207\252\345\213\225\343\203\206\343\202\271\343\203\210\350\250\210\347\224\273.md" "b/docs/03_PLAN/PLAN_06_\345\256\237\346\251\237\350\207\252\345\213\225\343\203\206\343\202\271\343\203\210\350\250\210\347\224\273.md" index 78c37da..37209ae 100644 --- "a/docs/03_PLAN/PLAN_06_\345\256\237\346\251\237\350\207\252\345\213\225\343\203\206\343\202\271\343\203\210\350\250\210\347\224\273.md" +++ "b/docs/03_PLAN/PLAN_06_\345\256\237\346\251\237\350\207\252\345\213\225\343\203\206\343\202\271\343\203\210\350\250\210\347\224\273.md" @@ -19,7 +19,9 @@ 既存のセルフテスト(`TIASshot.exe --selftest`.偽カメラ・ヘッドレス)と同じ考え方で,実機版の検査モードを追加する. -- **起動**: `TIASshot.exe --hwtest --camera [--with-chart] --hwtest-out <結果ファイル>`.ランナー `scripts/verify/run_hwtest.py` がビルドから実行・判定までを行う(`run_selftest.py` と同じ形) +- **起動**: `TIASshot.exe --hwtest --camera [--with-chart] [--hwtest-keep] --hwtest-out <結果ファイル>`.ランナー `scripts/verify/run_hwtest.py` がビルドから実行・判定までを行う(`run_selftest.py` と同じ形) +- **`--with-chart`**: チャートが必要な検査(connect → calibrate → shot → close-saving → close-calibrating → cleanup)を行う.校正は止めない.チャート不要の検査は行わないため,`--camera iscam` と `--camera iscam --with-chart` をカラーチャートをはめたまま続けて実行する.全体の上限はチャート不要 600 秒・`--with-chart` 1200 秒,ランナーの打ち切りはそれぞれ 720 秒・1320 秒 +- **`--keep`(ランナー)= `--hwtest-keep`**: 合格時も作業フォルダ(`%TEMP%\TIASshot-hwtest\work-*`)を残す(不合格・タイムアウト時は常に残る).`--with-chart` では校正後のフレームとその変換画像を証拠の画像(`evidence\calibrated-frame-raw.png`・`evidence\calibrated-frame-srgbNN.png`.`NN` は変換の次元)として保存する.撮影データ・校正データは作業フォルダの `data\` に保存され,合格時は作業フォルダごと削除される - **ビルドフラグ**: `HWTEST`(Debug 系の構成のみ).診断・評価機能を Release に含めない方針(CLAUDE.md・[ENV_06](../02_ENV/ENV_06_ビルド構成とビルドフラグ.md))に従う - **フォーム**: ImagingSource は SDK の画面部品(`ICImagingControl`)を使うため,ヘッドレスではなく**実際の `Form1` を表示して**動かす.人間がその場にいる前提なので表示してよい - **カメラの選択**: 両機種を同時につないでも,`--camera` で指定した機種だけを使う(通常起動の `Form1_Load` は Lumenera を優先して探すため,そのままでは ImagingSource を検査できない) @@ -55,20 +57,20 @@ ### チャートが必要(`--with-chart`.人間がチャートをカメラの前に置いてから実行する) -※ チャート不要の検査と同じくカラーチャートをはめたまま続けて実行できる(付け外しは不要).こちらは自動校正を走らせて結果を確かめる. +※ チャート不要の検査と同じくカラーチャートをはめたまま続けて実行できる(付け外しは不要).こちらは自動校正を走らせて結果を確かめる.`--with-chart` ではチャート不要の検査(`preview`〜`reconnect`)は行わない(`connect`・`cleanup` は共通.`cleanup` ではホワイトバランスを戻さない.校正で変わるのはカメラ側の値だけで,次の接続でデバイス状態ファイルの値に戻る). | ID | 確認内容 | 判定の仕方 | | --- | --- | --- | -| `calibrate` | 実物の舌診チャートで自動校正が完了する | 校正完了までの時間(上限つき)と,変換後の色票と参照値の色差 | -| `shot` | 単発・連続撮影で保存される | 保存されたファイル・Info.csv の中身,撮影時刻の間隔(設定値との差) | -| `close-saving` | 保存中に閉じようとすると取り消され,保存後は閉じられる | 取り消しの成否と表示文,保存完了後の後始末の順序 | -| `close-calibrating` | 校正中に閉じてもすぐ戻る | 後始末の所要時間と例外の有無 | +| `calibrate` | 実物の舌診チャートで自動校正が完了し,校正後のフレームを変換した色票が参照値に近い | 校正の待ち時間(最初のフレーム → チャート検出 → 校正完了.上限 60 秒),校正完了後に撮影ボタンが有効になること,校正データが一時フォルダに保存されること.校正後のフレームを校正の変換行列で変換し,24 色票の平均と参照値(`tcc_srgb`)の差を**保存画像と同じ 8bit(切り詰め後)・チャネルごとの差の絶対値**で判定する(平均,白色票を除いた最大,白色票の最大).白色票は参照値の BGR の和が最大の色票(13 番).ΔE76・白飛びの割合・当てはめの誤差は参考 | +| `shot` | 単発・連続撮影で保存される | 単発 1 枚・連続 3 枚(間隔 1000 ms).撮影直後は保存中で撮影ボタンが無効,保存完了(上限つき)後に再有効化されること,保存されたファイル(撮影画像・変換画像・Info.csv)と撮影ログの行数・備考,撮影時刻の間隔(設定値との差),エラー通知の有無 | +| `close-saving` | 保存中に閉じようとすると取り消され,保存後は閉じられる | 連続 5 枚(間隔 0 ms.保存が先に終わったら 10 枚で再試行)の保存中に閉じる処理を呼び,取り消しの成否と表示文・後始末が走っていないこと.保存完了後に閉じる処理の所要時間・後始末の順序(closing → timer → camera → light)・閉じた後に届いたフレーム数 | +| `close-calibrating` | 校正中に閉じてもすぐ戻る | 再接続して校正中になってから 500 ms 後に閉じる処理を呼び,所要時間・後始末の順序・例外の有無・閉じた後に届いたフレーム数 | -※ 判定のしきい値(色差の上限,撮影間隔の許容誤差等)は,最初の実行で実測値を見てから決める.チャート不要の検査のしきい値はフェーズ 1 で決めた(下記「確定したしきい値と実測値」). +※ 判定のしきい値はチャート不要の検査はフェーズ 1,チャートが必要な検査はフェーズ 2 の実測から決めた(下記「確定したしきい値と実測値」). ### 確定したしきい値と実測値 (Thresholds and Measurements) -フェーズ 1 の実測(ImagingSource DFK 33UX178.シリアル 35620307・10620446.カラーチャートをはめた状態)から決めた.しきい値の本体は `HwTest/HwTestJudge.cs`. +フェーズ 1 の実測(ImagingSource DFK 33UX178.シリアル 35620307・10620446.カラーチャートをはめた状態)と,フェーズ 2 の実測(同機種.シリアル 10620446.2026-10-08 の 2 回)から決めた.しきい値の本体は `HwTest/HwTestJudge.cs`. | 項目 | しきい値 | 実測値 | | --- | --- | --- | @@ -81,11 +83,29 @@ | `close-preview` の閉じる処理 | 1000 ms 以内,閉じた後に届くフレーム 2 以下 | 75〜221 ms,0 フレーム | | `reconnect` | 再接続後に 5 フレーム以上 | 964 ms で 5 フレーム(2026-10-08 13:38 の実行) | | 露光・ゲインの復元 | 元の値との相対誤差 1% 以内 | 一致 | +| `calibrate` の校正の待ち時間 | 60 秒以内 | 5.0〜5.6 秒(チャート検出まで 1.6〜1.8 秒+校正 3.4〜3.8 秒) | +| `calibrate` の色の誤差(8bit・チャネルごとの \|測定−参照\|.17 次元)の平均 | 5 以下 | 1.57 | +| `calibrate` の色の誤差の白色票を除いた最大 | 10 以下 | 3.47〜3.5(10 番) | +| `calibrate` の色の誤差の白色票(13 番)の最大 | 40 以下(**暫定**.下記「17 次元の変換のノイズ」) | 24.65〜27.35 | +| `calibrate` の ΔE76 | 参考(判定しない) | 平均 1.20〜1.26,最大 10.11〜12.04(白色票) | +| `shot` の撮影間隔のずれ | 設定値との差 100 ms 以下 | 4〜22 ms | +| `shot`・`close-saving` の保存の待ち時間 | 180 秒以内(2026-10-09 に 90 秒から延ばした) | 1 枚あたり約 3.3 秒(5 枚で 16〜20 秒).重いアプリが動いていると約 11 秒(5 枚で 55 秒) | +| `close-saving` の閉じる処理 | 保存中は取り消される.保存の完了後は 1000 ms 以内,閉じた後に届くフレーム 2 以下 | 取り消しを確認,33〜72 ms,0 フレーム | +| `close-calibrating` の閉じる処理 | 校正中になるまで 60 秒以内,閉じる処理 1000 ms 以内,閉じた後に届くフレーム 2 以下 | 53〜98 ms,0 フレーム | + +### 17 次元の変換のノイズ (Noise of the 17-Term Conversion) + +フェーズ 2 の実機テストで,白色票の色の誤差だけが大きい(24.65〜27.35.他の色票は 3.5 以下)ことが分かった.**製品の性質であり,対策は要判断**. + +- 事実: 白色票の入力(約 226.標準偏差 3〜5.飽和なし)が 17 次元(3 次)の変換で約 10 倍に増幅され(変換後の標準偏差 約 50,8bit に切り詰める前の値 -249〜621),8bit の範囲を外れて点状のノイズ・白飛びになる(白色票の 255 の画素 約 73%).チャート外の白い台紙・枠でも点状のノイズが出る.平均の色は合っている(切り詰め前の値で平均すると参照値との差は 2 以内).白など色票の範囲の端の明るい色で,高次の多項式の外挿がノイズを増幅するためと考えられる +- **回帰ではない(上流 v1.6 でも同じ)**: 2026-10-09 に v1.6 と現行で同じチャートを撮影し,同じ入力を両方のコードに通すと,マスク・色票の値・変換行列・変換後の画像(PNG/JPEG)がビット単位で一致した(色変換はリファクタリングで変わっていない).白色票の変換後の標準偏差も v1.6 51/39/23・現行 50/36/24(B/G/R)で同程度 +- 要判断: 対策(使う次元を下げる,入力・出力に制限をかける,色票の範囲外を別扱いにする等)は色の再現性に関わるため,研究室・上流と相談して決める.それまで白色票のしきい値 40 は暫定とし,色の誤差は白色票とそれ以外に分けて判定する +- 付随して確かめたこと: CSV に保存する変換行列(小数 7 桁)は 17 次元の 3 次の係数では有効数字が約 3 桁しかなく,CSV から画像を再現すると 8bit で最大 2〜4 ずれる ## 進め方 (Workflow) 1. 人間が機材をつなぎ,カラーチャート(または白板)を穴にはめて,「実機テストして」等と合図する -2. Claude(verifier)が `python scripts/verify/run_hwtest.py --camera <機種> [--with-chart]` を実行し,結果ファイルと終了コードで判定する +2. Claude(verifier)が `python scripts/verify/run_hwtest.py --camera <機種>` と `python scripts/verify/run_hwtest.py --camera <機種> --with-chart` を続けて実行し,結果ファイルと終了コードで判定する 3. 対象は ImagingSource(`--camera iscam`)だけ.Lumenera は行わない(上記「対象機種」) 4. 人間に残る確認は,画面の見た目の最終確認など,数値で置き換えられないものだけにする @@ -116,6 +136,8 @@ - `calibrate`・`shot`・`close-saving`・`close-calibrating` を実装する - 完了条件: ImagingSource で実物のチャートを使って全項目が合格する +- **状態: ImagingSource で完了(2026-10-08.DFK 33UX178(シリアル 10620446)で 2 回とも 6/6 合格)** +- 実機テストで見つかったこと: 17 次元の変換で白色票・白い台紙に点状のノイズ・白飛びが出る(上流 v1.6 から同じ.上記「17 次元の変換のノイズ」.対策は要判断) ### フェーズ 3: 手動テストの縮小 diff --git "a/docs/06_TEST/TEST_01_\343\203\206\343\202\271\343\203\210\344\273\225\346\247\230.md" "b/docs/06_TEST/TEST_01_\343\203\206\343\202\271\343\203\210\344\273\225\346\247\230.md" index 13c834c..fca7357 100644 --- "a/docs/06_TEST/TEST_01_\343\203\206\343\202\271\343\203\210\344\273\225\346\247\230.md" +++ "b/docs/06_TEST/TEST_01_\343\203\206\343\202\271\343\203\210\344\273\225\346\247\230.md" @@ -10,7 +10,7 @@ - 結合ロジックテスト: 偽カメラとヘッドレス Form1 で,撮影・保存の流れと失敗時の通知を NUnit で自動確認する(`[Category("Integration")]`.方針は `.claude/rules/testing.md`,移行計画は [PLAN_05](../03_PLAN/PLAN_05_テスト網羅性向上計画.md)) - 回帰テスト: リファクタリング前後の出力が一致することを確認する - セルフテスト: 実機なしで依存ロード・プレビュー経路・校正〜保存を自動確認する(手動テストの前段) -- 実機テスト: Claude が実機のカメラと光源を操作して,接続・プレビュー・露光/ゲイン・光源・閉じる処理・再接続を自動確認する(ユーザーの合図があるときだけ.手動テストの前段) +- 実機テスト: Claude が実機のカメラと光源を操作して,接続・プレビュー・露光/ゲイン・光源・閉じる処理・再接続と,実物の舌診チャートでの校正・撮影と保存・保存中/校正中に閉じる処理を自動確認する(ユーザーの合図があるときだけ.手動テストの前段) - 手動テスト: 実機を使って動作を目視確認する ## セルフテスト (Self Test) @@ -26,8 +26,11 @@ Claude が実機のカメラと光源を操作して,層④のうち数値で判定できる項目を自動で確認する([PLAN_06](../03_PLAN/PLAN_06_実機自動テスト計画.md).`Debug|x64` のみ.手順は [ENV_04](../02_ENV/ENV_04_開発コマンド.md) の「実機テスト」,判定としきい値の詳細は `.claude/verify-profile.md` の「実機テスト」節).**ユーザーの合図があるときだけ実行する**(撮影の本番中に機材を操作しないため). - `python scripts/verify/run_hwtest.py --camera `(対象は ImagingSource の `--camera iscam` だけ.Lumenera の実機テストは行わない.PLAN_06「対象機種」) +- 続けて `python scripts/verify/run_hwtest.py --camera iscam --with-chart`(チャートが必要な検査.カラーチャートをはめたまま実行する.`--with-chart` ではチャート不要の検査を行わないため,両方を実行する) - **実行の前提**: カメラ・光源のドライバが入っている([ENV_02](../02_ENV/ENV_02_環境構築手順.md)),検査する機種のカメラと光源が接続されている,カメラの前の穴にカラーチャート(または白板)がはめてある,TIASshot が起動していない -- **合格条件**: 終了コード 0(下表の 7 項目が PASS.結果は `.verify/hwtest/run-<日時>/hwtest-result.txt`) +- **合格条件**: 両方の実行で終了コード 0(チャート不要は下表の 7 項目,`--with-chart` は `connect`・`calibrate`・`shot`・`close-saving`・`close-calibrating`・`cleanup` の 6 項目が PASS.結果は `.verify/hwtest/run-<日時>/hwtest-result.txt`) + +チャート不要(`--with-chart` なし): | 項目 | 確認内容 | 合格条件 | | --- | --- | --- | @@ -39,8 +42,18 @@ | `reconnect` | 切断した後に再接続できる | 2 回目の `Connect()` が成功し,5 フレーム以上届く | | `cleanup` | 後始末と書き込み禁止 | 露光・ゲインを戻す → カメラ切断 → 光源のポートを閉じる(消灯しない)が成功し,設定・デバイス状態ファイル・本番の保存先が変わっていない | +チャートが必要(`--with-chart`.`connect`・`cleanup` は上表と同じ): + +| 項目 | 確認内容 | 合格条件 | +| --- | --- | --- | +| `calibrate` | 実物の舌診チャートで自動校正が完了し,校正後のフレームを変換した色票が参照値に近い | 60 秒以内に校正が完了し,撮影ボタンが有効になる.校正後のフレームを変換した 24 色票と参照値(`tcc_srgb`)の差(8bit・チャネルごとの差の絶対値)が平均 5 以下,白色票(13 番)を除いた最大 10 以下,白色票の最大 40 以下(暫定.PLAN_06「17 次元の変換のノイズ」) | +| `shot` | 単発・連続撮影で保存される | 単発 1 枚・連続 3 枚(間隔 1000 ms)で撮影画像・sRGB 変換画像・Info.csv がそろい,撮影ログの行数が撮影枚数と一致する.保存が 90 秒以内に終わって撮影ボタンが再有効化され,撮影時刻の間隔と設定値の差が 100 ms 以下,エラー通知がない | +| `close-saving` | 保存中に閉じようとすると取り消され,保存後は閉じられる | 保存中の閉じる処理が取り消され(表示「保存中です.保存完了後に閉じてください」・後始末が走らない),保存の完了後の閉じる処理が 1000 ms 以内・後始末の順序が closing → timer → camera → light・閉じた後に届くフレームが 2 以下 | +| `close-calibrating` | 校正中に閉じてもすぐ戻る | 再接続して校正中になり(60 秒以内),閉じる処理が 1000 ms 以内に戻り,例外がなく,閉じた後に届くフレームが 2 以下 | + - 2026-10-08 に ImagingSource(DFK 33UX178 の 2 個体)で 7/7 合格した.Lumenera の実機テストは行わない(解像度が相対的に低く今後あまり使わない見込みのため) -- チャートが要る項目(校正・撮影・保存中や校正中に閉じる.PLAN_06 フェーズ 2)は未実装のため,下記の手動テストで確認する +- 2026-10-08 に ImagingSource(DFK 33UX178.シリアル 10620446)で `--with-chart` を 2 回実行し,いずれも 6/6 合格した +- 変換画像の見た目(白色票や白い台紙の点状のノイズ・白飛び等)は数値で判定しきれないため,下記の手動テストで確認する ## 結合ロジックテスト (Integration Logic Tests) @@ -136,12 +149,14 @@ - ※ フレームが流れることは実機テスト(`preview`)でも確認できる.見た目は手動で確認する - 舌診チャートを映すとキャリブレーションが自動開始される - キャリブレーション完了後に撮影ボタンが有効になる + - ※ 校正の完了と撮影ボタンの有効化は実機テスト(`calibrate`)でも確認できる - 1枚撮影が正常に完了し,ファイルが保存される - 連続撮影が正常に完了し,ファイルが保存される + - ※ 保存されるファイルと撮影間隔は実機テスト(`shot`)でも確認できる.変換画像の見た目は手動で確認する - 光源の ON/OFF が切り替わる - ※ 実機テスト(`light`)でも確認できる - アプリを閉じてもエラーが出ない(閉じた後も光源は点いたまま残るのが仕様) - - ※ プレビュー中に閉じる場合は実機テスト(`close-preview`)でも確認できる + - ※ プレビュー中・保存中・校正中に閉じる場合は実機テスト(`close-preview`・`close-saving`・`close-calibrating`)でも確認できる **合格条件** diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index aca732a..2fdd014 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -199,3 +199,9 @@ - 後段: Lumenera は機材が未接続で未実施(つながり次第実行する).フェーズ 2(チャートが要る検査).本番の Info.csv の露光記録が整数の段を「1/10 して ms」として書いており誤った値になっている疑い(未確認.報告台帳に記録). - [x] **Lumenera を実機テストの対象外に** (2026-10-08): Lumenera は解像度が相対的に低く今後あまり使わない見込みのため,実機テスト(PLAN_06)の対象を ImagingSource だけにした.`--camera lucam` の実装は残すが検査の対象にしない. + +- [x] **実機テストにチャートが必要な検査(PLAN_06 フェーズ 2)を追加し,ImagingSource の実機で合格** (2026-10-08〜09): `--with-chart` で校正(`calibrate`)・撮影と保存(`shot`)・保存中に閉じる(`close-saving`)・校正中に閉じる(`close-calibrating`)を検査できるようにした.DFK 33UX178(シリアル 10620446)で 2 回とも 6/6 合格し,しきい値を実測から決めた(校正の待ち時間 60 秒・色の誤差の平均 5 / 白色票を除いた最大 10 / 白色票 40(暫定)・撮影間隔のずれ 100 ms 等.PLAN_06).ランナーに `--keep`(合格時も作業フォルダを残し,校正後のフレームとその変換画像を証拠として保存)を足した. + - 設計判断: ① `--with-chart` ではチャート不要の検査を行わない(校正を止めない検査と止める検査を 1 回に混ぜると,校正でホワイトバランスが変わった後に露光・ゲインを評価することになるため).カラーチャートをはめたまま `--camera iscam` と続けて実行する.② 色の誤差は保存画像と同じ 8bit(切り詰め後)・チャネルごとの差の絶対値で判定し,ΔE76 は参考にした(実際に保存される画像の色で判定するため).③ 白色票(参照値の BGR の和が最大の色票)を分けて判定した.白色票だけが 17 次元の変換のノイズで大きく外れ,同じしきい値では他の色票の確認が甘くなるため. + - 発見: 17 次元(3 次)の変換が白色票の入力のばらつき(標準偏差 3〜5)を約 10 倍に増幅し(切り詰め前 -249〜621),8bit で点状のノイズ・白飛びになる.チャート外の白い台紙・枠でも出る.平均の色は合っている.回帰かを確かめるため,2026-10-09 に上流 v1.6 と現行で同じチャートを撮影し,それぞれの入力(TCC.png・撮影画像)を両方のコードに通して比べた.マスク・色票の値・変換行列・変換後の画像(PNG/JPEG)がビット単位で一致し,白色票の変換後の標準偏差も同程度(v1.6 51/39/23・現行 50/36/24)だったため,リファクタリングによる回帰ではなく上流からの性質と判断した.付随して,CSV に保存する変換行列(小数 7 桁)では 3 次の係数の有効数字が約 3 桁しかなく,CSV から画像を再現すると 8bit で最大 2〜4 ずれることを確かめた(報告台帳の「SaveMatToCsv の精度」の裏付け).同梱 `DFK33UX178.xml` は v1.6 版とホワイトバランス等の設定値・シリアル(v1.6: 27710698,現行: 41520093)が異なる. + - 失敗パターン: ① v1.6 を別フォルダから起動すると,作業フォルダが exe の場所でないため `config.xml` を読めずに落ちた(報告台帳の「config.xml をカレントディレクトリ基準で読む」を実際に踏んだ).exe のフォルダで起動する.② v1.6 は同梱のデバイス状態ファイルのシリアルの個体を開こうとするため,手元の別個体には接続できなかった.比較用に接続処理だけを差し替えた(色変換のコードには手を入れていない). + - 後段: 17 次元の変換のノイズの対策(使う次元を下げる・入力/出力に制限をかける等)は色の再現性に関わるため研究室・上流と相談して決める(それまで白色票のしきい値 40 は暫定.報告台帳に記録).PLAN_06 フェーズ 3(手動テストの縮小).