diff --git a/.claude/rules/testing.md b/.claude/rules/testing.md index 7a500cf..2fbc968 100644 --- a/.claude/rules/testing.md +++ b/.claude/rules/testing.md @@ -18,7 +18,7 @@ | ① ピュアロジック層 | ハードウェア・UI・スレッドに依存しない計算/変換ロジック | **NUnit で必ず自動テスト** | | ② 結合ロジック層 | `CameraBase` の校正・撮影・保存の流れ,`Form1` の UI 連携メソッド | **NUnit+偽カメラ+ヘッドレス `Form1` で自動テスト**(後述「結合ロジック層のテスト」) | | ③ SDK アダプタ層 | `IScam`・`Lucam`・`LightSource` | 判断ロジックを純粋関数に切り出して層①で検証する.SDK を呼ぶ部分そのものは層④(後述「SDK アダプタの書き方」) | -| ④ 実機層 | SDK の実呼び出し・実画像の見た目 | 手動テスト(TEST_01).ここに残す項目は最小限にする | +| ④ 実機層 | SDK の実呼び出し・実画像の見た目 | 実機テスト(`--hwtest`.ユーザーの合図があるときだけ)と手動テスト(TEST_01).ここに残す項目は最小限にする | 「テストできない」と「テストしていない」を混同しない.実機が本当に要るのは SDK の実呼び出しと見た目だけであり,それ以外(状態遷移・スレッド連携・失敗時の通知等)は層②・③の手段でテストできる.「UI だから」「スレッドだから」を理由にテストを省かない. @@ -56,6 +56,7 @@ | ビルドテスト | ソリューション全体 | 自動(MSBuild) | 全コミット前 | | 回帰テスト | 色補正・チャート検出の出力(合成チャート,および実機で録画したチャート・白板のフレーム) | 自動(基準データ比較) | リファクタ・修正の前後 | | セルフテスト | 依存ロード・偽カメラでのプレビュー経路・合成チャートでの校正〜保存 | 自動(`--selftest`.`/verify`・`/implement` Phase 1b) | 依存更新・層②〜④の変更後,手動テストの前段 | +| 実機テスト | 層④のうち数値で判定できる SDK の実呼び出し(接続・プレビュー・露光/ゲイン・光源・閉じる・再接続) | 自動(`--hwtest`.Claude が実機を操作する.**ユーザーの合図があるときだけ**) | 層③・④の変更後,手動テストの前段 | | 手動テスト | SDK の実呼び出し・実画像の見た目(層④) | 手動(実機) | 機能追加・修正の完了時 | ※ 実機録画データ(舌診チャート・白板のフレーム)による回帰は PLAN_05 のフェーズ 4 で整備する.**舌の画像は個人情報のためテストデータに含めない**. @@ -95,7 +96,20 @@ | `LightSource` のシリアル通信 | 光源(実機)に依存する.ポートを開けなかったときの扱い等の判断は層③として切り出す | | 画面描画の見た目(`Form1`・`PreviewMonitor` の表示内容) | 目視でしか判断できない.表示用 Bitmap の所有権・更新の流れはセルフテスト(`preview`)で担保する | -※ 層④に手を入れた場合は**設計レビュー+実機回帰**で挙動を確認する.その前段として,実機なしで通せる範囲はセルフテスト(`python scripts/verify/run_selftest.py`.`.claude/verify-profile.md`)で確認できる.`/implement` の Tester フェーズでは,対象が層④だけの場合に限り,テストを書かずに設計レビューで判断してよい.層②・③に当たる部分が含まれるなら,その部分のテストは書く. +層④のうち次の項目は,実機テスト([PLAN_06](../../docs/03_PLAN/PLAN_06_実機自動テスト計画.md).`python scripts/verify/run_hwtest.py --camera `.`HWTEST` フラグ)で Claude が実機を操作して自動で確認できる.**ユーザーが会話の中で合図したときだけ**実行し,合図が無ければ「検証不能(合図なし)」とする(手順・しきい値は `.claude/verify-profile.md` の「実機テスト」節). + +| 項目 | 確認できること | +| --- | --- | +| `connect` | 指定した機種に接続でき,機種名・シリアル番号が取れる | +| `preview` | プレビューが流れる(フレームレートの下限・本モニタへの表示) | +| `exposure-gain` | 露光・ゲインの設定がフレームの明るさに期待どおりの向きで効き,元の値に戻せる | +| `light` | 光源の点灯・消灯が明るさに効き,ポートを閉じた後に開き直せる | +| `close-preview` | プレビュー中に閉じる処理を呼んでもすぐ戻り,後始末の順序が正しい | +| `reconnect` | 切断した後に再接続でき,フレームが届く | + +※ 2026-10-08 時点で実機テストを通したのは ImagingSource だけ(Lumenera は未実施).校正・撮影・保存中や校正中に閉じる等のチャートが要る項目(PLAN_06 フェーズ 2)は未実装のため,引き続き手動テストで確認する. + +※ 層④に手を入れた場合は**設計レビュー+実機回帰**で挙動を確認する.その前段として,実機なしで通せる範囲はセルフテスト(`python scripts/verify/run_selftest.py`.`.claude/verify-profile.md`)で,上表の実機テストの項目はユーザーの合図のもと実機テストで確認できる.`/implement` の Tester フェーズでは,対象が層④だけの場合に限り,テストを書かずに設計レビューで判断してよい.層②・③に当たる部分が含まれるなら,その部分のテストは書く. ## 結合ロジック層のテスト (Integration Logic Tests) diff --git a/.claude/verify-profile.md b/.claude/verify-profile.md index 2f4d3ba..a76e606 100644 --- a/.claude/verify-profile.md +++ b/.claude/verify-profile.md @@ -21,6 +21,7 @@ - ローカルの接続先: このマシンのみ(ビルド・実行ファイル・一時フォルダ).ネットワーク上のサービスは使わない(`--full` 時の `nuget restore` による nuget.org からのパッケージ取得のみ例外) - ローカル以外で許可する環境: なし - 接続を禁止する環境(拒否リスト): 実機カメラ(Lumenera / ImagingSource)・光源(シリアルポート)・本番の撮影データフォルダ(`config.xml` の `File/SaveFolder`,既定 `C:\TIAS_Data`).セルフテストはこれらに触れない設計であり,verifier も触れない +- 条件付きで許可する環境: 実機カメラ・光源・シリアルポートは,**ユーザーが会話の中で実機テストを明示的に合図したとき(オーケストレーターから「実機テストの合図: あり」と渡されたとき)に限り**,後述「実機テスト」節のランナー(`scripts/verify/run_hwtest.py`)経由でだけ接続してよい.本番の撮影データフォルダは実機テストでも触れない(保存先は一時フォルダに差し替わる) ## 実行コマンド (Run Command) @@ -44,6 +45,77 @@ - `FAIL:` 行には例外型・メッセージ・対象アセンブリ名(`[assembly: ...]`)・Fusion ログの要点(`[fusion: ...]`)・スタックの先頭が入る.依存の問題はここで特定できる - 判定は**終了コードと結果ファイル**で行う.`TIASshot.exe` の標準出力は OS のコードページ(cp932)で出るため,直接実行すると文字化けすることがある(ランナーは標準出力を使わない) +## 実機テスト(ユーザーの合図があるときだけ)(Hardware Test) + +[PLAN_06](../docs/03_PLAN/PLAN_06_実機自動テスト計画.md) の実機テスト(`TIASshot.exe --hwtest`,`HWTEST` ビルドフラグ).実際の `Form1` を表示し,指定した機種のカメラと光源を操作して検査する. + +### 実行してよい条件 + +- **ユーザーが会話の中で実機テストを明示的に合図したとき(オーケストレーターから「実機テストの合図: あり」と渡されたとき)だけ**実行する.撮影の本番中に機材を操作しないため +- 合図が無ければ実機テストは実行せず,該当する確認を「**検証不能(合図なし)**」と報告する(セルフテスト等,他の検証は通常どおり行う).合図を推測で補わない.「動作確認して」等の一般的な依頼は合図とみなさない +- 合図は 1 回の検証の依頼ごとに有効とする.以前の会話・別のタスクでの合図を流用しない + +### 実行コマンド + +リポジトリルートで実行する.2 機種とも検査する場合は機種ごとに実行する. + +| 用途 | コマンド | +| --- | --- | +| Lumenera を検査する | `python scripts/verify/run_hwtest.py --camera lucam` | +| ImagingSource を検査する | `python scripts/verify/run_hwtest.py --camera iscam` | + +- `--with-chart`(チャートが必要な検査.PLAN_06 フェーズ 2)は未実装.指定すると機材に触れずに終了コード 2 になるため使わない +- `--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 秒で打ち切った + +### 検査項目 + +| ID | 確認内容 | 測定値と判定(しきい値は ImagingSource の実測(PLAN_06 フェーズ 1)から決めた.結果ファイルの表記は「暫定」のまま) | +| --- | --- | --- | +| `connect` | 指定した機種だけに接続でき,機種名・シリアル番号が取れる | 列挙した台数,`Connect()` の成否と所要時間,機種名・シリアル番号 | +| `preview` | プレビューが流れる | 最初のフレームまでの時間,フレームレート(下限 10 fps),本モニタへの表示,平均輝度と飽和画素の割合 | +| `exposure-gain` | 露光・ゲインの設定がフレームに効く | 先に基準の明るさを探す(元の露光に最も近い 2^n 秒の段に合わせ,平均輝度 30〜220 かつ飽和画素の割合 1% 以下になるまで露光を 1 段(`ExposureLogStep`.時間で 2 倍・半分)ずつ動かす.最大 12 段).露光は基準から 1 段下げ・上げ(比が下げ 0.8 以下・上げ 1.25 以上),ゲインは範囲の幅の ±10%(差が 3 階調以上.片側の向きだけ期待どおりでも合格)で判定.ImagingSource は絶対値(`VCDAbsoluteValueProperty`.秒・dB)で操作する.元の値に戻ったことを読み戻しで確認(相対誤差 1% 以内) | +| `light` | 光源が点灯・消灯し,閉じた後に開き直せる | 照明ボタンでの点灯・消灯の平均輝度の差(100 階調以上),`LightSource.Close` → `Open` の成否,開き直した後の点灯の効き | +| `close-preview` | プレビュー中に閉じる処理を呼んでもすぐ戻る | 閉じる処理(`Form1_FormClosing`)の所要時間(上限 1000 ms)・例外の有無・後始末の順序(closing → timer → camera → light)・閉じた後 1 秒間に届いたフレーム数(2 以下) | +| `reconnect` | 切断した後に再接続できる | 2 回目の `Connect()` の成否・シリアル番号の一致・再接続後のフレームの到着(5 フレーム以上) | +| `cleanup` | 後始末と書き込み禁止の確認 | 露光・ゲインを戻す → カメラ切断 → 光源のポートを閉じる(消灯はしない),の成否.実行ファイルのフォルダの `*.xml`(`config.xml`・デバイス状態ファイル)の内容が変わっていないこと,本番の保存先の今日のフォルダが変わっていないこと | + +### 判定の読み方 + +- `hwtest-result.txt` はセルフテストと同じ書式(`[PASS] : ...` / `[FAIL] : ...` の見出し行,` - ` 情報・` WARN:` 参考・` FAIL:` 失敗理由の詳細行,最終行 `RESULT: PASS (7/7)` または `RESULT: FAIL (...)`).冒頭に暫定しきい値の一覧(`thresholds (暫定)`)と校正の扱い(`校正: 停止(チャート不要の検査…)`)が出る +- **測定値(フレームレート・平均輝度・所要時間)は PASS / FAIL にかかわらず詳細行に出る**.暫定しきい値で FAIL した場合は,測定値を報告に必ず書く(しきい値の決め直しに使う) +- タイムアウト時は,止まった項目の見出しの下に途中までの測定値と `FAIL: タイムアウト: ...(実行中のステップ: ...)` が出る.どの SDK 呼び出しで止まったかはステップ名で特定する +- 指定機種が見つからない場合は `RESULT: FAIL (camera not found: <機種>)`(終了コード 2).機材の接続を人間に依頼する + +### 前提条件 + +| 前提条件 | 確認方法 | 満たされない場合 | +| --- | --- | --- | +| ユーザーの合図がある | オーケストレーターからの指示に「実機テストの合図: あり」がある | 実行せず「検証不能(合図なし)」と報告する | +| 撮影の本番中でない・TIASshot が起動していない | ランナーが `tasklist` で確認する(起動中なら終了コード 2) | 検証不能とし,人間に TIASshot の終了を依頼する(**自分でプロセスを止めない**) | +| 指定機種のカメラと光源が開発 PC に接続されている | `connect` の詳細行(列挙した台数)・`light` の詳細行(ポートの有無) | カメラが無ければ検証不能(終了コード 2).光源が無ければ `light` が FAIL になる.機材の接続を人間に依頼する | +| カメラの前の穴に**カラーチャート(または白板)がはめてある**(穴が空だと暗く,明るさの変化を評価しにくい).チャート不要の検査では校正は止まる(結果ファイル冒頭に `校正: 停止(チャート不要の検査…)`) | 人間に確認する.`preview`・`light` の詳細行 `校正は止まっています` | はめていなければ人間にはめてもらってから再実行する.`preview`・`light` が `FAIL: 校正を止めているはずなのに校正が…` なら校正の停止が効いていない不具合として報告する(露光・ゲイン・カメラ本体のホワイトバランスが乱れている可能性あり) | +| セルフテストの前提(Visual Studio / Build Tools・`packages/`・IC Imaging Control 3.5) | 上記「前提条件と確認方法」と同じ | 同上 | + +### 既知のノイズ + +- 平均輝度・フレームレートは照明・被写体・カメラの個体差で変わる.判定は変化の向きと量で行い,絶対値は判定しない +- 実測(ImagingSource DFK 33UX178・カラーチャートをはめた状態): フレームレート 13〜18 fps,光源の点灯と消灯の差 153〜196,閉じる処理 75〜221 ms.これより大きく外れたら,しきい値より先に照明・チャート・機材の状態を疑う +- 飽和は「254 以上の画素の割合が 1% を超える」で判定する(平均輝度では判定しない).上げた向きの結果が飽和した場合,または真っ暗(平均輝度 5 以下)の場合,その向きの確認は省かれる(詳細行に「確認しない」と出る).両方とも省かれると FAIL になる.基準探しで中間の明るさにできなかった場合も FAIL になる +- 露光・ゲインが設定範囲の端にあると,その向きの設定が変わらず確認が省かれる(詳細行に「反映されませんでした」と出る) +- `exposure-gain` の `WARN: 元に戻した後の平均輝度が最初と離れています` は参考(判定は設定値の読み戻しで行う) +- 実際のフォームが表示される(副ディスプレイがあればプレビューモニタも開く).メモリ観測ウィンドウ(`MEMMONITOR`)は開かない + +### 後始末 + +- 実機テストは終了時(失敗時も)に「変えた露光・ゲインを元に戻す → カメラ切断 → 光源のポートを閉じる」を行い,`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-*` の有無とパスを報告の「後始末」に書く +- 同梱の `config.xml`・デバイス状態ファイル(`{DeviceName}.xml`)・本番の保存先には書き込まない(`cleanup` で確認する) + ## 前提条件と確認方法 (Preconditions) | 前提条件 | 確認方法 | 満たされない場合 | @@ -81,6 +153,7 @@ ## 禁止操作 (Prohibited Operations) - `--selftest` を付けない `TIASshot.exe` の起動(UI が開き,実機カメラ・光源(シリアルポート)へ接続を試みる) + - 例外: ユーザーの合図があるときの `python scripts/verify/run_hwtest.py --camera `(上記「実機テスト」節).`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 bda2329..4ddecaa 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ ## 開発進捗 -最新: Claude が実機(カメラ・光源)を操作して層④を確認する実機自動テストの計画(PLAN_06)を策定した +最新: 実機自動テスト(PLAN_06 フェーズ 1)を実装し,ImagingSource の実機で 7 項目が合格した(Lumenera は未実施) ※ 本欄は**最新ステップ 1 行のみ上書き更新**.詳細な進捗履歴(動機・設計判断・失敗パターン)は [docs/PROGRESS.md](docs/PROGRESS.md) に追記する.運用ルールは `.claude/rules/progress-log.md` を参照(該当ファイル編集時に自動ロードされる). ## 必須ルール(コード実装時) diff --git "a/docs/02_ENV/ENV_01_\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.md" "b/docs/02_ENV/ENV_01_\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.md" index baedb6c..52fb3fa 100644 --- "a/docs/02_ENV/ENV_01_\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.md" +++ "b/docs/02_ENV/ENV_01_\346\212\200\350\241\223\343\202\271\343\202\277\343\203\203\343\202\257.md" @@ -52,5 +52,9 @@ **Lumenera SDK** - 用途: Lumenera 製カメラの制御(Lw110) -- DLL: `lumenera.api.dll`(リポジトリ内に同梱) -- 別途インストール不要(同梱 DLL を参照) +- DLL: `lumenera.api.dll`(.NET 側.リポジトリ内に同梱) +- ビルド・セルフテストは同梱 DLL だけでできる.実機を使うにはネイティブの `lucamapi.dll` を含む LuCam Software の導入が別途要る([ENV_02](ENV_02_環境構築手順.md) の「カメラ・光源のドライバ」) + +**カメラ・光源のドライバ(実機を使う場合に別途インストール)** + +- LuCam Software(Lumenera)・Cam33U Driver(ImagingSource の 33U/37U/38U.IC Imaging Control SDK とは別)・CP210x Universal Windows Driver(光源の USB-シリアル変換).入手先・バージョンは [ENV_02](ENV_02_環境構築手順.md) を参照 diff --git "a/docs/02_ENV/ENV_02_\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206.md" "b/docs/02_ENV/ENV_02_\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206.md" index a31ad7f..dec5bcc 100644 --- "a/docs/02_ENV/ENV_02_\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206.md" +++ "b/docs/02_ENV/ENV_02_\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206.md" @@ -29,6 +29,8 @@ 5. スクリプト完了後,IC Imaging Control SDK を手動でインストールする. - 詳細は「必要なソフトウェア — IC Imaging Control SDK」を参照する. +6. 実機(カメラ・光源)を開発 PC で使う場合は,カメラと光源のドライバを手動でインストールする. + - 詳細は「必要なソフトウェア — カメラ・光源のドライバ」を参照する. **自動化される内容** @@ -40,6 +42,7 @@ **自動化されない内容(手動対応が必要)** - IC Imaging Control SDK のインストール +- カメラ・光源のドライバのインストール(実機を使う場合) - 実行時設定ファイルの配置(config.xml,カメラ設定 XML,CSV) ### 手動セットアップ @@ -63,7 +66,26 @@ ### Lumenera SDK - Lumenera 製カメラ(Lw110)の使用に必要. -- `lumenera.api.dll` はリポジトリ内に同梱されている. +- リポジトリに同梱されている `lumenera.api.dll` は .NET 側のラッパーだけで,これだけでは実機を使えない.ネイティブの `lucamapi.dll` は下記「カメラ・光源のドライバ」の LuCam Software で導入する. +- ※ ビルドとセルフテスト(偽カメラ)は同梱 DLL だけでできる. + +### カメラ・光源のドライバ + +開発 PC で実機(カメラ・光源)を使う場合(実機テストを含む)に必要.いずれも導入には管理者権限(UAC)が要る.2026-10-08 に以下のバージョンで導入・動作確認した. + +| 対象 | ドライバ(確認したバージョン) | 入手先 | ログイン | +| --- | --- | --- | --- | +| Lumenera 製カメラ(Lw110) | LuCam Software and Software Development Kit (Windows) 6.9.0 | [Teledyne Vision Solutions](https://teledynevisionsolutions.com/products/lt-series-usb3/GetResourcesSupportDownloads) の Resources & Support → Downloads タブ | 要(アカウント) | +| ImagingSource 製カメラ(DFK33UX178 等 33U/37U/38U) | Device Driver for USB 33U, 37U, 38U Cameras(Cam33U Driver and Tools)6.0.0.2811 | [The Imaging Source](https://www.theimagingsource.com/en-us/support/download/icwdmuvccamtis33u/) | 不要 | +| 光源(USB-シリアル変換 Silicon Labs CP2102) | CP210x Universal Windows Driver 11.6.0.420(zip) | [Silicon Labs](https://silabs.com/developers/usb-to-uart-bridge-vcp-drivers) | 不要 | + +- **LuCam Software**: 導入するとネイティブの `lucamapi.dll` が `System32`/`SysWOW64` に入る.Lw110(USB 2.0)への対応はダウンロードページに明記されていない. +- **Cam33U Driver**: IC Imaging Control SDK(.NET ライブラリ)とは別に要る.無いとカメラが Windows 標準の汎用カメラとして認識され,「USB3 Vision Device」がエラーになって IC Imaging Control から使えない. +- **CP210x Driver**: スクリプト(`curl` 等)からのダウンロードは 403 で拒否されるため,ブラウザで落とす.zip を展開して導入する. +- 導入後の確認(デバイスマネージャー): + - ImagingSource: カメラがエラー表示(「USB3 Vision Device」の警告)なしで認識されている. + - 光源: 「ポート (COM と LPT)」に「Silicon Labs CP210x USB to UART Bridge (COMn)」が現れる.アプリは `config.xml` の `LightSource/Device`(`Silicon Labs CP210x`)でこの名前を探して接続する. + - Lumenera: `C:\Windows\System32\lucamapi.dll` があり,カメラがエラー表示なしで認識されている. ### Python と bash(Claude Code のフック用) diff --git "a/docs/02_ENV/ENV_03_\347\256\241\347\220\206\350\200\205\347\224\250\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206.md" "b/docs/02_ENV/ENV_03_\347\256\241\347\220\206\350\200\205\347\224\250\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206.md" index 6d5aeac..7af118b 100644 --- "a/docs/02_ENV/ENV_03_\347\256\241\347\220\206\350\200\205\347\224\250\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206.md" +++ "b/docs/02_ENV/ENV_03_\347\256\241\347\220\206\350\200\205\347\224\250\347\222\260\345\242\203\346\247\213\347\257\211\346\211\213\351\240\206.md" @@ -36,7 +36,8 @@ | SDK | 用途 | 入手・配置 | | --- | --- | --- | | IC Imaging Control SDK | ImagingSource 製カメラ(DFK33UX178 / DFK23UX249) | [The Imaging Source](https://www.theimagingsource.com/en-us/support/download/) から各自インストール(`setup.ps1` が未導入時にダウンロードページを開く) | -| Lumenera SDK | Lumenera 製カメラ(Lw110) | `lumenera.api.dll` をリポジトリに同梱済み.追加インストールは不要 | +| Lumenera SDK | Lumenera 製カメラ(Lw110) | .NET 側の `lumenera.api.dll` はリポジトリに同梱済み(ビルド・セルフテストはこれだけでできる).実機を使うにはネイティブの `lucamapi.dll` を含む LuCam Software(Teledyne Vision Solutions.ダウンロードにアカウントが要る)を各自インストールする | +| カメラ・光源のドライバ | 実機(カメラ・光源)を開発 PC で使う場合 | LuCam Software(Lumenera)・Cam33U Driver(ImagingSource)・CP210x Universal Windows Driver(光源)を各自インストールする(管理者権限が要る).入手先・バージョンは [ENV_02](ENV_02_環境構築手順.md) の「カメラ・光源のドライバ」 | ## 実行時参照ファイルの配布 (Runtime Reference Files) 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 c29a8e9..cc0e245 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" @@ -148,3 +148,37 @@ - ランナーがクリーンするのは Debug 出力(`TIASshot/` と `TIASshot.Tests/` の `bin/x64/Debug`・`obj/x64/Debug`)のみ.`bin/x64/Release` 等ほかの構成の出力は消さない.`--no-clean`・`--skip-tests` は開発時の短縮用で,検証の判定には使わない. - `--selftest-keep` を付けると,合格時も作業フォルダ(`%TEMP%\TIASshot-selftest\work-*`.校正データ・保存画像)を残す(不合格時は常に残る). - verifier(`/verify`)による自動検証の手順・判定の読み方は `.claude/verify-profile.md` を参照する. + +## 実機テスト (Hardware Test) + +実機のカメラと光源を操作して,接続・プレビュー・露光/ゲイン・光源・閉じる処理・再接続を検査する(`Debug|x64` のみ.[ENV_06](ENV_06_ビルド構成とビルドフラグ.md) の `HWTEST`.計画は [PLAN_06](../03_PLAN/PLAN_06_実機自動テスト計画.md)).実際の `Form1` が表示される. + +**ユーザーの合図があるときだけ実行する**(撮影の本番中に機材を操作しないため.Claude は合図なしに実行しない). + +前提: + +- カメラ・光源のドライバが入っている([ENV_02](ENV_02_環境構築手順.md) の「カメラ・光源のドライバ」) +- 検査する機種のカメラと光源が開発 PC に接続されている +- カメラの前の穴にカラーチャート(または白板)がはめてある(チャート不要の検査の間は自動校正を止める) +- TIASshot が起動していない(起動中ならランナーは実行せずに終了コード 2 を返す) + +```powershell +# ビルド(Debug|x64)→ 実機テスト(結果は .verify/hwtest/run-<日時>/).2 機種とも行う場合は機種ごとに実行する +python scripts/verify/run_hwtest.py --camera lucam +python scripts/verify/run_hwtest.py --camera iscam +# 開発中の素早い再確認(Debug 出力を消さない.判定には使わない) +python scripts/verify/run_hwtest.py --camera iscam --no-clean + +# 実機テスト単体(WinExe のため Start-Process -Wait で終了コードを受け取る.実行ファイルのフォルダで実行する) +$p = Start-Process "TIASshot\bin\x64\Debug\TIASshot.exe" -WorkingDirectory "TIASshot\bin\x64\Debug" -ArgumentList "--hwtest","--camera","iscam","--hwtest-out","$env:TEMP\tias-hwtest.txt" -Wait -PassThru +$p.ExitCode # 0=全項目合格,1=不合格あり,2=実機テスト自体の異常,3=タイムアウト +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-*`)を残す(不合格・タイムアウト時は常に残る). +- 出力先: `.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 秒で打ち切った. +- NUnit テスト・セルフテストは実行しない(それぞれ `run_tests.py`・`run_selftest.py`). +- 検査項目・しきい値・判定の読み方は `.claude/verify-profile.md` の「実機テスト」節と [TEST_01](../06_TEST/TEST_01_テスト仕様.md) を参照する. diff --git "a/docs/02_ENV/ENV_06_\343\203\223\343\203\253\343\203\211\346\247\213\346\210\220\343\201\250\343\203\223\343\203\253\343\203\211\343\203\225\343\203\251\343\202\260.md" "b/docs/02_ENV/ENV_06_\343\203\223\343\203\253\343\203\211\346\247\213\346\210\220\343\201\250\343\203\223\343\203\253\343\203\211\343\203\225\343\203\251\343\202\260.md" index 1460d5b..458bf66 100644 --- "a/docs/02_ENV/ENV_06_\343\203\223\343\203\253\343\203\211\346\247\213\346\210\220\343\201\250\343\203\223\343\203\253\343\203\211\343\203\225\343\203\251\343\202\260.md" +++ "b/docs/02_ENV/ENV_06_\343\203\223\343\203\253\343\203\211\346\247\213\346\210\220\343\201\250\343\203\223\343\203\253\343\203\211\343\203\225\343\203\251\343\202\260.md" @@ -5,7 +5,7 @@ ## 設計方針 (Policy) - **Release(配布版)=素の製品**.診断・評価・デモ用の機能はコードごと除外する. -- **Debug=開発・検証版**.診断/評価機能(`MEMMONITOR`・`WHITEBOARD`・`SELFTEST`)を自動で含める. +- **Debug=開発・検証版**.診断/評価機能(`MEMMONITOR`・`WHITEBOARD`・`SELFTEST`・`HWTEST`)を自動で含める. ## ソリューション構成 (Solution Configurations) @@ -13,7 +13,7 @@ | 構成 | 用途 | 定義されるシンボル | 出力先 | | --- | --- | --- | --- | -| `Debug\|x64` | 開発・検証 | `DEBUG` `TRACE` `WHITEBOARD` `MEMMONITOR` `SELFTEST` | `TIASshot/bin/x64/Debug/` | +| `Debug\|x64` | 開発・検証 | `DEBUG` `TRACE` `WHITEBOARD` `MEMMONITOR` `SELFTEST` `HWTEST` | `TIASshot/bin/x64/Debug/` | | `Release\|x64` | 配布 | `TRACE` | `TIASshot/bin/x64/Release/` | > ※ `TIASshot.csproj` には `Debug\|AnyCPU` / `Release\|AnyCPU` の PropertyGroup も残っているが,`.sln` は `x64` のみをビルド対象としており,通常はこれらを使わない. @@ -26,6 +26,7 @@ | `MEMMONITOR` | メモリ観測ウィンドウ+プレビュー計測 | `Debug\|x64`(自動) | ✗ | `UI/MemoryMonitorForm`,`UI/PreviewProfiler`,`UI/TimedPictureBox`,`UI/Form1.MemMonitor`(F9 トグル),`Form1.ShowImage` 等のプレビュー計測 | | `WHITEBOARD` | 白板撮影モード(照明均一性評価用) | `Debug\|x64`(自動) | ✗ | 白板撮影ボタン(`Form1` の専用 partial),`Cameras/IScam.ShotWhiteBoard` 等 | | `SELFTEST` | ヘッドレスのセルフテスト(`--selftest`) | `Debug\|x64`(自動)・`Debug\|AnyCPU`(csproj のみ.通常は未使用) | ✗ | `SelfTest/`(ランナー・偽カメラ・合成チャート),`UI/Form1.SelfTest`・`UI/PreviewMonitor.SelfTest`,`Program.Main` の分岐,`Form1.ShowError` のヘッドレス記録 | +| `HWTEST` | 実機テスト(`--hwtest`.実機のカメラ・光源を操作する) | `Debug\|x64`(自動)・`Debug\|AnyCPU`(csproj のみ.通常は未使用).**`SELFTEST` と同時に定義すること**(無いと `#error`) | ✗ | `HwTest/`(ランナー・判定・引数),`UI/Form1.HwTest`,`Cameras/IScam.HwTest`・`Cameras/Lucam.HwTest`(露光・ゲインの操作),`Program.Main` の分岐,`CameraBase` の校正停止フラグ,`Form1_Load` の自動接続の省略・`Form1.ShowImage` のフレーム記録・`Form1.ShowError` の記録,メモリ観測ウィンドウを開かない分岐 | | `DEBUG` | .NET 標準デバッグシンボル | `Debug\|x64` | ✗ | 標準(一部の開発時分岐) | | `TRACE` | .NET 標準トレースシンボル | 全構成 | ○ | `System.Diagnostics.Trace` | @@ -48,9 +49,17 @@ - 依存更新後などに,人間の実機確認の前段として verifier(`/verify`)が使う.実行手順は [ENV_04_開発コマンド](ENV_04_開発コマンド.md) と `.claude/verify-profile.md` を参照する. - 配布版には不要なため Release では未定義(Release の exe に `--selftest` を渡しても通常起動になる). +### HWTEST — 実機テスト + +- `TIASshot.exe --hwtest --camera ` で実際の `Form1` を表示し,指定した機種のカメラと光源を操作して,接続・プレビュー・露光/ゲイン・光源・閉じる処理・再接続を検査する([PLAN_06](../03_PLAN/PLAN_06_実機自動テスト計画.md)).終了コード(0=合格)と結果ファイルで返す.保存先は一時フォルダに差し替え,同梱の `config.xml`・デバイス状態ファイルは書き換えない. +- チャート不要の検査の間は,`CameraBase` の校正停止フラグでフレームコールバックの校正処理(チャート検出・ホワイトバランスの調整・変換行列の算出)を止める(カメラの前にチャートをはめたまま検査するため). +- `SELFTEST` の部品(`SelfTestConfig`・`SelfTestReport`・`SelfTestPump`・閉じる処理の段階の記録)を使うため,`SELFTEST` と同時に定義する必要がある(`HwTest/HwTestRunner.cs`・`UI/Form1.HwTest.cs` が `#error` で検出する). +- 機材を操作するため,**ユーザーの合図があるときだけ実行する**.実行手順は [ENV_04_開発コマンド](ENV_04_開発コマンド.md) と `.claude/verify-profile.md` を参照する. +- 配布版には不要なため Release では未定義(Release の exe に `--hwtest` を渡しても通常起動になる). + ## ビルド方法 (How to Build) -標準構成(Debug / Release)のビルド・テスト・実行コマンドは [ENV_04_開発コマンド](ENV_04_開発コマンド.md) を参照する.`Debug|x64` では `WHITEBOARD`・`MEMMONITOR`・`SELFTEST` が自動で有効になり(メモリ観測ウィンドウが開き,白板撮影ボタンが表示され,`--selftest` 引数が使える),`Release|x64` ではいずれの診断フラグも含まれない. +標準構成(Debug / Release)のビルド・テスト・実行コマンドは [ENV_04_開発コマンド](ENV_04_開発コマンド.md) を参照する.`Debug|x64` では `WHITEBOARD`・`MEMMONITOR`・`SELFTEST`・`HWTEST` が自動で有効になり(メモリ観測ウィンドウが開き,白板撮影ボタンが表示され,`--selftest`・`--hwtest` 引数が使える),`Release|x64` ではいずれの診断フラグも含まれない. ## 関連 (Related) diff --git "a/docs/03_PLAN/PLAN_05_\343\203\206\343\202\271\343\203\210\347\266\262\347\276\205\346\200\247\345\220\221\344\270\212\350\250\210\347\224\273.md" "b/docs/03_PLAN/PLAN_05_\343\203\206\343\202\271\343\203\210\347\266\262\347\276\205\346\200\247\345\220\221\344\270\212\350\250\210\347\224\273.md" index c97b203..7f14c81 100644 --- "a/docs/03_PLAN/PLAN_05_\343\203\206\343\202\271\343\203\210\347\266\262\347\276\205\346\200\247\345\220\221\344\270\212\350\250\210\347\224\273.md" +++ "b/docs/03_PLAN/PLAN_05_\343\203\206\343\202\271\343\203\210\347\266\262\347\276\205\346\200\247\345\220\221\344\270\212\350\250\210\347\224\273.md" @@ -111,7 +111,7 @@ | --- | --- | | 校正中の例外(`CalcTcc`・`ProcessCalibrationFrame`) | カメラのコールバックへ例外を伝えない.捕捉してログを残し,「校正に失敗しました」と通知し,チャート検出からやり直せる状態(未校正・マスク解放)に戻す.通知がチャート検出の進捗表示ですぐ上書きされないよう,次に校正が完了するまで検出中の表示を「校正に失敗しました(理由).チャートの検出からやり直しています」に差し替えて出し続ける(エラーダイアログはカメラのコールバックを止めるため使わない) | | 校正画像(TccImage・TccRoisImage)の保存失敗 | 変換行列はメモリ上で有効なので校正済みのままにし,「自動校正完了(校正画像の保存に失敗)」のように警告を表示する | -| アプリを閉じるとき(`Form1_FormClosing`) | 保存中なら閉じるのを取り消して「保存中」と知らせる(閉じる理由は区別しない.Windows のシャットダウン時も取り消し,待つか強制終了するかはユーザーに選ばせる).閉じ始めたらカメラのコールバックから UI への呼び出しを行わない(ハングの防止).光源を消してポートを閉じる | +| アプリを閉じるとき(`Form1_FormClosing`) | 保存中なら閉じるのを取り消して「保存中」と知らせる(閉じる理由は区別しない.Windows のシャットダウン時も取り消し,待つか強制終了するかはユーザーに選ばせる).閉じ始めたらカメラのコールバックから UI への呼び出しを行わない(ハングの防止).光源のポートを閉じる(**消灯はしない**.終了後も光源は点いたまま.上流 v1.7 と同じ動作で,2026-10-08 にユーザーが仕様として確定) | | 保存スレッドから UI への通知 | 進捗表示などは UI スレッドを待たない非同期の呼び出しにする(撮影中でも保存が進み,画像がキューに溜まり続けない) | | 保存キューの待ち時間(`DrainShots`) | 固定 30 秒をやめ,「30 秒」と「撮影間隔の 2 倍」の大きい方にする | @@ -119,7 +119,7 @@ - 上表の方針をすべて実装した.判断(閉じてよいか,待ち時間,通知文の組み立て)は `Form1.CanClose`・`CameraBase.GetDrainIdleTimeout`・`FormatCalibrationFailure`・`ShouldNotifyCalibrationFailure`・`FormatChartDetectionMessage`・`FormatCalibrationDone` として切り出し,層①でテストした - 層②の新規・書き換えテストは修正前のコードで 14 件が赤になることを確認した.層②は計 36 件で 1 回あたり約 21〜26 秒(目安 30 秒に近づいてきたので,次に層②を増やすときはテスト用設定の見直しを先に検討する) - 保存中の切断テストは,通知の非同期化で「保存スレッドが UI を待つ間は必ず生きている」前提が崩れたため,保存スレッドを意図的に止めておく形に書き直した - - 実機でしか確かめられない残り: 保存中・プレビュー中・校正中に閉じたときの挙動(SDK のストリーム停止との待ち合い),光源の消灯とポートの解放,撮影と保存が並行するようになった後の連写間隔の精度 + - 実機でしか確かめられない残り: 保存中・プレビュー中・校正中に閉じたときの挙動(SDK のストリーム停止との待ち合い),光源のポートの解放(終了後も点灯したままであること),撮影と保存が並行するようになった後の連写間隔の精度 - **3b(未着手)**: ROI とフレームサイズの照合,フレームバッファのサイズ検査,光源ポートを開けなかったときの扱い(`/auto-audit` 報告台帳の該当項目) ### フェーズ 4: 実機録画データによる回帰 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 73d2b00..75496d2 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" @@ -29,24 +29,33 @@ - 保存先は一時フォルダ(`%TEMP%` 配下)にする.本番の保存先(`C:\TIAS_Data` 等)には書き込まない - 同梱の `config.xml` は変更しない(一時フォルダに複製して保存先等を差し替える) - カメラのデバイス状態ファイル(`{DeviceName}.xml`)は読むだけで,上書きしない.露光・ゲイン等を検査で変えた場合は,終了時に元の値へ戻す -- 光源は検査の最後に必ず消灯してポートを閉じる(失敗した場合も) + - ImagingSource の露光・ゲインは絶対値(`VCDAbsoluteValueProperty`.露光は秒,ゲインは dB)で読み書きし,元の絶対値そのものへ戻して読み戻しで確かめる(整数の段(`VCDRangeProperty`)で扱うと元の値に戻せないため) +- チャート不要の検査の間は自動校正(チャート検出・ホワイトバランスの調整・変換行列の算出)を止める(`CameraBase` の校正停止フラグ.`HWTEST` ビルド限定).はめたチャートで校正が走ると露光・ゲイン・ホワイトバランスが検査中に変わるため +- 光源は検査の最後に必ずポートを閉じる(失敗した場合も).消灯はしない(アプリ終了時に光源を消さない仕様に合わせる.`light` 項目の最後に再点灯した状態で終わる) - 待機には必ずタイムアウトを付ける ## 検査項目 (Test Items) ### チャート不要(`--with-chart` なし) +※ 穴に何もはめないと中が暗く明るさの変化を評価しにくいため,**カラーチャート(または白板)をはめた状態で行う**.この検査の間は,チャートが写っても自動校正を走らせない(テストモードだけの処理.2026-10-08 にユーザーと合意). + | ID | 確認内容 | 判定の仕方 | | --- | --- | --- | | `connect` | 指定した機種に接続でき,機種名・シリアル番号が取れる | `Connect()` の成否 | | `preview` | プレビューが流れる | 一定時間に届いたフレーム数(フレームレートの下限) | -| `exposure-gain` | 露光・ゲインの設定がフレームに効く | 設定を上げ下げしたときのフレームの平均輝度の変化の向き | +| `exposure-gain` | 露光・ゲインの設定がフレームに効く | 基準の明るさを探してから,露光を 1 段(2^n 秒の段で半分・2 倍),ゲインを範囲の幅の ±10% 上げ下げしたときの平均輝度の変化の向きと量.飽和した向きは確認しない.終了時に元の値へ戻ったことを読み戻しで確かめる | | `light` | 光源が点灯・消灯し,閉じた後に開き直せる | 点灯時と消灯時のフレームの平均輝度の差,ポートの再オープンの成否 | -| `close-preview` | プレビュー中に閉じる処理を呼んでもすぐ戻る | 後始末の所要時間(上限つき)と例外の有無 | +| `close-preview` | プレビュー中に閉じる処理を呼んでもすぐ戻る | 後始末の所要時間(上限つき)と例外の有無,閉じた後に届いたフレーム数 | | `reconnect` | 切断した後に再接続できる | 2 回目の `Connect()` の成否とフレームの到着 | +| `cleanup` | 後始末と書き込み禁止 | 露光・ゲインを戻す → カメラ切断 → 光源のポートを閉じる(消灯しない)の成否,設定・デバイス状態ファイル・本番の保存先が変わっていないこと | + +露光・ゲインの基準探し: 元の露光に最も近い 2^n 秒の段に合わせ,平均輝度が中間(30〜220)かつ飽和画素(254 以上)の割合が 1% 以下になるまで露光を 1 段ずつ動かす(最大 12 段).実測で露光 1 段は 0.497 倍(黒レベル 15.2 を引いた値)≈ 0.5 倍,ゲイン 1 dB は 1.122 倍 ≈ 10^(1/20) と理論どおりに効いた. ### チャートが必要(`--with-chart`.人間がチャートをカメラの前に置いてから実行する) +※ チャート不要の検査と同じくカラーチャートをはめたまま続けて実行できる(付け外しは不要).こちらは自動校正を走らせて結果を確かめる. + | ID | 確認内容 | 判定の仕方 | | --- | --- | --- | | `calibrate` | 実物の舌診チャートで自動校正が完了する | 校正完了までの時間(上限つき)と,変換後の色票と参照値の色差 | @@ -54,11 +63,27 @@ | `close-saving` | 保存中に閉じようとすると取り消され,保存後は閉じられる | 取り消しの成否と表示文,保存完了後の後始末の順序 | | `close-calibrating` | 校正中に閉じてもすぐ戻る | 後始末の所要時間と例外の有無 | -※ 判定のしきい値(フレームレートの下限,色差の上限,撮影間隔の許容誤差等)は,最初の実行で実測値を見てから決める. +※ 判定のしきい値(色差の上限,撮影間隔の許容誤差等)は,最初の実行で実測値を見てから決める.チャート不要の検査のしきい値はフェーズ 1 で決めた(下記「確定したしきい値と実測値」). + +### 確定したしきい値と実測値 (Thresholds and Measurements) + +フェーズ 1 の実測(ImagingSource DFK 33UX178.シリアル 35620307・10620446.カラーチャートをはめた状態)から決めた.しきい値の本体は `HwTest/HwTestJudge.cs`. + +| 項目 | しきい値 | 実測値 | +| --- | --- | --- | +| `preview` のフレームレート | 10 fps 以上 | 13〜18 fps | +| `exposure-gain` の露光 | 1 段下げで比 0.8 以下,1 段上げで比 1.25 以上(向きごと.飽和した向きは確認しない) | 下げ 0.545(2026-10-08 13:38 の実行.上げは比 1.322 だが飽和画素 70% のため確認しない向き) | +| `exposure-gain` のゲイン | 平均輝度の差 3 以上(片側の向きだけ期待どおりでも合格) | 下げ −15.6(同上.上げは +47.1 だが飽和画素 68% のため確認しない向き) | +| 基準の明るさ | 平均輝度 30〜220,飽和画素(254 以上)の割合 1% 以下 | 元の露光に近い段(0.015625 秒)で 158.9 | +| 飽和の判定 | 254 以上の画素の割合が 1% を超える | — | +| `light` の点灯と消灯の差 | 平均輝度の差 100 以上 | 153〜196 | +| `close-preview` の閉じる処理 | 1000 ms 以内,閉じた後に届くフレーム 2 以下 | 75〜221 ms,0 フレーム | +| `reconnect` | 再接続後に 5 フレーム以上 | 964 ms で 5 フレーム(2026-10-08 13:38 の実行) | +| 露光・ゲインの復元 | 元の値との相対誤差 1% 以内 | 一致 | ## 進め方 (Workflow) -1. 人間が機材をつなぎ(チャートが要る検査ではチャートを置き),「実機テストして」等と合図する +1. 人間が機材をつなぎ,カラーチャート(または白板)を穴にはめて,「実機テストして」等と合図する 2. Claude(verifier)が `python scripts/verify/run_hwtest.py --camera <機種> [--with-chart]` を実行し,結果ファイルと終了コードで判定する 3. 2 機種とも行う場合は,機種ごとに実行する 4. 人間に残る確認は,画面の見た目の最終確認など,数値で置き換えられないものだけにする @@ -82,6 +107,9 @@ - チャート不要の検査(`connect`・`preview`・`exposure-gain`・`light`・`close-preview`・`reconnect`)を実装する - 検証プロファイルを更新する - 完了条件: 両機種で人間の合図のもと実行でき,しきい値を実測から決めて全項目が合格する +- **状態: ImagingSource で完了(2026-10-08.DFK 33UX178 の 2 個体で 7/7 合格).Lumenera は機材がつながり次第実行する** +- 実機テストで見つかった不具合: 同梱の `DFK33UX178.xml` は別個体(シリアル 41520093)のものを指しており,旧 `IScam.Connect` はファイルのデバイスを開いていたため,別個体では接続できず例外が外へ漏れていた.機種名でデバイスを開いてから設定だけを適用し,失敗は `ErrorMsg`+`false` で返すように直した(`Cameras/IScamDeviceSelector`.[TECH_02](../05_TECH/TECH_02_カメラ制御仕様.md)) +- 仕様変更: アプリ終了時に光源を消灯しない(ポートを閉じるだけ.上流 v1.7 と同じ.2026-10-08 にユーザーが確定).実機テストの後始末も同じく消灯しない ### フェーズ 2: チャートが必要な検査 @@ -103,6 +131,6 @@ | --- | --- | | 撮影の本番中に Claude が機材を操作してしまう | 実行はユーザーの合図があったときだけ.検証プロファイルで明記し,合図がなければ検証不能として報告する | | 検査でカメラの設定が変わったまま残る | デバイス状態ファイルは上書きしない.変えた露光・ゲインは終了時に元に戻す | -| 光源が点いたまま残る | 検査の最後(失敗時も)に消灯してポートを閉じる | +| 光源のポートが開いたまま残る | 検査の最後(失敗時も)にポートを閉じる.光源は点いたままでよい(アプリ終了時と同じ仕様) | | 実機の個体差・照明で判定が不安定になる | しきい値は実測から余裕を持って決める.輝度は絶対値ではなく変化の向きで判定する | | SDK がハングして検査が終わらない | 検査全体と各項目にタイムアウトを付け,ランナー側でもプロセスを打ち切る | diff --git "a/docs/04_SPEC/SPEC_01_\346\251\237\350\203\275\344\273\225\346\247\230.md" "b/docs/04_SPEC/SPEC_01_\346\251\237\350\203\275\344\273\225\346\247\230.md" index 5fe9e52..9b91ddc 100644 --- "a/docs/04_SPEC/SPEC_01_\346\251\237\350\203\275\344\273\225\346\247\230.md" +++ "b/docs/04_SPEC/SPEC_01_\346\251\237\350\203\275\344\273\225\346\247\230.md" @@ -104,3 +104,5 @@ - 対応デバイス: Silicon Labs CP210x(`config.xml` で変更可能). - キャリブレーション中は光源の切り替えが無効になる. - 光源デバイスが見つからない場合,光源ボタンが無効化される. +- 起動時にポートを開いて点灯する. +- アプリ終了時は消灯せず,ポートを閉じるだけにする(終了後も光源は点いたまま残る).上流 v1.7 と同じ動作で,2026-10-08 にユーザーが仕様として確定した. diff --git "a/docs/05_TECH/TECH_02_\343\202\253\343\203\241\343\203\251\345\210\266\345\276\241\344\273\225\346\247\230.md" "b/docs/05_TECH/TECH_02_\343\202\253\343\203\241\343\203\251\345\210\266\345\276\241\344\273\225\346\247\230.md" index adec6b7..94e7105 100644 --- "a/docs/05_TECH/TECH_02_\343\202\253\343\203\241\343\203\251\345\210\266\345\276\241\344\273\225\346\247\230.md" +++ "b/docs/05_TECH/TECH_02_\343\202\253\343\203\241\343\203\251\345\210\266\345\276\241\344\273\225\346\247\230.md" @@ -19,7 +19,10 @@ ### 接続 -- `[デバイス名].xml` からカメラ設定をロードする. +- 列挙したデバイスから,機種名(列挙名から空白を除いたもの.例: `DFK 33UX178` → `DFK33UX178`)が一致するものを選んで開く(`IScamDeviceSelector`). +- `[デバイス名].xml`(デバイス状態ファイル)は設定の適用だけに使う(`LoadDeviceStateFromFile(file, false)`).ファイルに書かれた個体(シリアル番号)は開かないため,同じ機種なら別の個体でも接続できる. + - ※ 以前は `LoadDeviceStateFromFile(file, true)` でファイルのデバイスを開いていたため,同梱の `DFK33UX178.xml`(シリアル 41520093 の個体)と別の個体では接続できず,例外が外へ漏れていた(2026-10-08 に実機テストで発見して修正). +- デバイスが見つからない・開けない・設定を適用できない場合は,例外を外へ出さず `ErrorMsg` に理由を設定して `false` を返す(起動時の接続フローが次のデバイスを試せる). - `config.xml` の `<カメラ名>/ROI` から ROI 設定を読み込む. - `FrameQueueSink` をシンクに設定してライブ開始する. 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 8062629..2084455 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,6 +10,7 @@ - 結合ロジックテスト: 偽カメラとヘッドレス Form1 で,撮影・保存の流れと失敗時の通知を NUnit で自動確認する(`[Category("Integration")]`.方針は `.claude/rules/testing.md`,移行計画は [PLAN_05](../03_PLAN/PLAN_05_テスト網羅性向上計画.md)) - 回帰テスト: リファクタリング前後の出力が一致することを確認する - セルフテスト: 実機なしで依存ロード・プレビュー経路・校正〜保存を自動確認する(手動テストの前段) +- 実機テスト: Claude が実機のカメラと光源を操作して,接続・プレビュー・露光/ゲイン・光源・閉じる処理・再接続を自動確認する(ユーザーの合図があるときだけ.手動テストの前段) - 手動テスト: 実機を使って動作を目視確認する ## セルフテスト (Self Test) @@ -18,7 +19,28 @@ - `python scripts/verify/run_selftest.py`(依存を変えた場合は `--full`) - **合格条件**: 終了コード 0(`deps`・`preview`・`calib-save` の 3 項目が PASS) -- 代替していない範囲(実カメラ SDK との結合・実プレビュー表示・実チャートの検出性能・画像の見た目・長時間のメモリ/GDI)は,引き続き下記の手動テストで確認する +- 代替していない範囲(実カメラ SDK との結合・実プレビュー表示・実チャートの検出性能・画像の見た目・長時間のメモリ/GDI)は,下記の実機テストと手動テストで確認する + +## 実機テスト (Hardware Test) + +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 `(2 機種とも行う場合は機種ごとに実行する) +- **実行の前提**: カメラ・光源のドライバが入っている([ENV_02](../02_ENV/ENV_02_環境構築手順.md)),検査する機種のカメラと光源が接続されている,カメラの前の穴にカラーチャート(または白板)がはめてある,TIASshot が起動していない +- **合格条件**: 終了コード 0(下表の 7 項目が PASS.結果は `.verify/hwtest/run-<日時>/hwtest-result.txt`) + +| 項目 | 確認内容 | 合格条件 | +| --- | --- | --- | +| `connect` | 指定した機種に接続でき,機種名・シリアル番号が取れる | `Connect()` が成功する | +| `preview` | プレビューが流れる | 10 fps 以上で,本モニタに表示用 Bitmap がある | +| `exposure-gain` | 露光・ゲインの設定がフレームに効く | 基準(平均輝度 30〜220・飽和画素 1% 以下)から露光 1 段下げで比 0.8 以下・上げで比 1.25 以上(飽和した向きは確認しない),ゲインは差 3 以上(片側でよい).元の値に戻る | +| `light` | 光源が点灯・消灯し,閉じた後に開き直せる | 点灯と消灯の平均輝度の差が 100 以上.ポートを開き直した後も点灯が効く | +| `close-preview` | プレビュー中に閉じる処理を呼んでもすぐ戻る | 1000 ms 以内に戻り,例外がなく,閉じた後に届くフレームが 2 以下 | +| `reconnect` | 切断した後に再接続できる | 2 回目の `Connect()` が成功し,5 フレーム以上届く | +| `cleanup` | 後始末と書き込み禁止 | 露光・ゲインを戻す → カメラ切断 → 光源のポートを閉じる(消灯しない)が成功し,設定・デバイス状態ファイル・本番の保存先が変わっていない | + +- 2026-10-08 に ImagingSource(DFK 33UX178 の 2 個体)で 7/7 合格した.Lumenera は未実施 +- チャートが要る項目(校正・撮影・保存中や校正中に閉じる.PLAN_06 フェーズ 2)は未実装のため,下記の手動テストで確認する ## 結合ロジックテスト (Integration Logic Tests) @@ -109,13 +131,17 @@ - アプリが正常に起動する - カメラが自動で接続される(Lucam または ImagingSource) + - ※ 指定した機種への接続そのものは実機テスト(`connect`)でも確認できる.自動で機種を選んで接続する流れは手動で確認する - プレビューが表示される + - ※ フレームが流れることは実機テスト(`preview`)でも確認できる.見た目は手動で確認する - 舌診チャートを映すとキャリブレーションが自動開始される - キャリブレーション完了後に撮影ボタンが有効になる - 1枚撮影が正常に完了し,ファイルが保存される - 連続撮影が正常に完了し,ファイルが保存される - 光源の ON/OFF が切り替わる -- アプリを閉じてもエラーが出ない + - ※ 実機テスト(`light`)でも確認できる +- アプリを閉じてもエラーが出ない(閉じた後も光源は点いたまま残るのが仕様) + - ※ プレビュー中に閉じる場合は実機テスト(`close-preview`)でも確認できる **合格条件** diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index 5ea2c2f..4c6da3d 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -190,3 +190,10 @@ - [x] **実機自動テストの計画(PLAN_06)を策定** (2026-10-06): 層④(SDK の実呼び出し・実画像)に残る手動確認を減らすため,`--hwtest` で Claude が開発 PC につないだ実機のカメラ・光源を操作して検査する計画を立てた.実行はユーザーの合図があったときだけとし,保存先は一時フォルダ,設定ファイルは書き換えない. - 設計判断: ImagingSource は SDK の画面部品を使うため,ヘッドレスではなく実際の `Form1` を表示して動かす.両機種を同時につないでも `--camera` で 1 台ずつ検査する(通常起動は Lumenera を優先するため). + +- [x] **実機自動テスト(PLAN_06 フェーズ 1)を実装し,ImagingSource の実機で 7 項目が合格** (2026-10-08): `TIASshot.exe --hwtest`(`HWTEST` フラグ,Debug のみ)とランナー `run_hwtest.py` を作り,Claude が開発 PC につないだカメラと光源を操作して接続・プレビュー・露光/ゲイン・光源・閉じる処理・再接続・後始末を検査できるようにした.DFK 33UX178 の 2 個体で 7/7 合格し,しきい値を実測から決めた(PLAN_06).開発 PC に実機用のドライバ 3 種(LuCam Software・Cam33U Driver・CP210x)を入れ,ENV_02 に入手先を記録した. + - 動機: 層④に残る手動確認のうち,数値で判定できる SDK の実呼び出しを人間の手から外すため(PLAN_05 の 4 層モデルの仕上げ). + - 設計判断: チャート不要の検査も穴にカラーチャート(または白板)をはめて行い,その間は自動校正を止める.穴が空だと暗くて明るさの変化を評価しにくく,一方でチャートが写ると校正が走って検査中に露光・ゲイン・ホワイトバランスが変わるため.露光・ゲインは整数の段ではなく絶対値(秒・dB)で扱い,2^n 秒の段で動かして元の絶対値へ戻す.実測で露光 1 段は約 0.5 倍,ゲイン 1 dB は約 1.122 倍と理論どおりに効いた. + - 仕様変更: アプリ終了時に光源を消灯しない(ポートを閉じるだけ.上流 v1.7 と同じ)とユーザーが確定した. + - 失敗パターン: ① 同梱の `DFK33UX178.xml` は別個体のシリアルを持ち,旧 `IScam.Connect` がファイルのデバイスを開いていたため,手元の個体では接続できず例外が外へ漏れた.機種名でデバイスを開いてから設定だけ適用する形に直した(本番の接続にも効く修正).② 露光を整数の段(`VCDRangeProperty`)で扱っていたため,2^n でない元の露光(1/60 秒等)に戻せていなかった.絶対値で扱う形に改めた.③ Release の exe を作り直さずに確認し,古い動作を見て判断を誤りかけた.確認は必ずランナー(Debug をビルドし直す)経由で行う. + - 後段: Lumenera は機材が未接続で未実施(つながり次第実行する).フェーズ 2(チャートが要る検査).本番の Info.csv の露光記録が整数の段を「1/10 して ms」として書いており誤った値になっている疑い(未確認.報告台帳に記録).