========================================================================
カメラ制御仕様 (Camera Control Specification)
========================================================================
1. 起動時のカメラ接続フロー (Startup Connection Flow)
------------------------------------------------------------------------
Form1 ロード時に以下の順で接続を試みる.
1. Lucam.Connect() を実行する
・成功: Lucam をアクティブカメラとして使用する
・失敗: 次へ
2. ImagingSource デバイス一覧を走査する
・接続されているデバイス名を順に IScam.Connect() で試行する
・最初に成功したカメラをアクティブカメラとして使用する
3. どのカメラも接続できない場合
・エラーダイアログを表示してアプリを終了する
2. IScam(ImagingSource カメラ)の制御 (IScam Control)
------------------------------------------------------------------------
2-1. 接続
・`[デバイス名].xml` からカメラ設定をロードする.
・`config.xml` の `<カメラ名>/ROI` から ROI 設定を読み込む.
・`FrameQueueSink` をシンクに設定してライブ開始する.
2-2. プレビュー(フレーム取得コールバック)
・`FrameQueueSink` の `Retrieve` コールバックでフレームを受け取る.
・受け取った画像を転置(`.T()`)し,ROI を切り出して表示する.
・キャリブレーション中は白色票の測定・ゲイン更新も行う(後述).
2-3. ROI クリップ
・ImagingSource カメラは横向きに画像を出力するため,転置して縦向きに変換する.
・転置後の画像座標系で ROI(X,Y,W,H)を切り出す.
2-4. 撮影
・シンクを `FrameQueueSink` → `FrameSnapSink` に切り替える.
・`SnapSingle()` で1フレームずつ取得して `_shots` に蓄積する.
・撮影完了後,シンクを `FrameQueueSink` に戻す.
・最初の1フレームは捨てる(カメラの安定待ち).
3. Lucam(Lumenera カメラ)の制御 (Lucam Control)
------------------------------------------------------------------------
3-1. 接続
・`LucamNumCameras()` で接続台数を確認する(0台または2台以上はエラー).
・カメラ ID から機種を特定する(`0x49f` → Lw110).
・`LucamRgbPreviewCallback` コールバックを登録する.
・`config.xml` の `<Lucam>` からカメラパラメータを設定して,プレビューを開始する.
3-2. プレビュー(フレーム取得コールバック)
・`LucamRgbPreviewCallback` でフレームを受け取る.
・受け取った画像を転置(`.T()`)して表示する(ROI クリップなし).
・キャリブレーション中は白色票の測定・ゲイン更新も行う(後述).
3-3. 撮影
・`LucamEnableFastFrames()` でスナップ撮影モードに切り替える.
・`LucamTakeFastFrame()` でRAW画像を取得し,`LucamConvertFrameToRgb24()` でRGB変換する.
・撮影完了後,`LucamDisableFastFrames()` で通常モードに戻す.
4. ホワイトバランス自動調整 (White Balance Calibration)
------------------------------------------------------------------------
チャート検出後(`_calibrating` が `Calib/Frames` にセットされた後),
各フレームで以下の処理を行う.
1. 白色票(`_chartMasks[12]`,24色票の13番)の平均 RGB 値を測定する
2. `Calib/UpdateInterval` フレームごとにゲインを更新する
・更新比率: `ratio = (target / current - 1) * UpdateRate + 1`
・IScam: `VCDRangeProperty.Value` を直接更新する
・Lucam: `_snap.Gain*` を更新し `SetCameraParam()` で反映する
3. `_calibrating` をデクリメントし,0 になったら `CalcTcc()` を呼び出す
5. データ保存フォルダの生成 (Save Folder)
------------------------------------------------------------------------
`SetSaveFolder(note)` が保存先フォルダを以下の書式で生成する.
[SaveFolder]/[yyyy-MM-dd]/[HH_mm_ss]-[note]/
・`SaveFolder` は `config.xml` の `<File/SaveFolder>` で指定する.
・`note` は「データ名」(撮影時)または「校正」(キャリブ時).
・フォルダが存在しない場合は自動作成する.