環境整備(テンプレート同期・docs 番号修正) (2026-06-06): プログラミングテンプレートを初回同期(エージェント/コマンド/GUIDE_05 等を取り込み)し、docs カテゴリ番号を命名規則(GUIDE_03)に整合(PLAN→03 / SPEC→04 / TECH→05)。リモートをセルフホスト Git から GitHub の Private リポジトリへ移行。
CameraBase のリファクタリング(責務分離 Phase 1〜4) (2026-06-06): 肥大化していた CameraBase の責務を分離。Cameras/・UI/(Phase1)、色補正→ColorCorrection/ColorCorrector(Phase2)、チャート検出→ChartDetection/ChartDetector(Phase3)、ファイル I/O・サウンド→Utils/IoUtil(Phase4)。
CameraBase にカメラ制御・チャート検出・色補正・ファイル I/O・サウンドが集中していた。CameraBase に残した。具体的には UpdateRate/GetRatio(ゲイン補正)、SetSaveFolder/WriteInfo/SetInfo(_saveFolder/_ShotInfo 経由)。後者 2 つは純粋ロジックのみ IoUtil へ移し、CameraBase 側は薄いラッパーとした。_基準データ_refactor前/、特に TCC_RGB.csv)を取得して保管。実機の再校正は物理入力が変わり数値が一致しないため、回帰は「同一入力での計算一致」+「コードの文字単位一致」で担保した。 CameraBase リファクタリング Phase 5(IScam/Lucam の重複処理を集約) (2026-06-07): Phase 1〜4 後も派生クラスに残っていたプレビュー/校正フローと撮影ループの重複を、CameraBase のテンプレートメソッドに集約。カメラ固有のゲイン反映・フレーム取得・撮影前後処理のみ抽象メソッドで派生クラスに残した。
IScam の撮影前後処理(Sink 切替・最初のフレーム捨て)は Lucam と実行順序が異なるため共通骨格に取り込まず派生側に残した(順序維持を優先)。CalcTcc の後に移したことで元の「ログ→CalcTcc→記録」順がずれた → テストで検出し、CalcTcc 前に呼ぶ専用フックへ分離して厳密な順序一致を回復。 PLAN_02 優先度1: _shots のスレッドセーフ化(連続撮影クラッシュ修正) (2026-06-07): 連続撮影で4枚以上取得するとたまにクラッシュする不具合を修正。根本原因は _shots(List<Mat>)を撮影スレッドと保存スレッドで無保護に共有していたこと(容量拡張時のリサイズ競合・TOCTOU)。
ConcurrentQueue 単体ではなく BlockingCollection<Mat> を採用し生産者-消費者パイプライン化。GetConsumingEnumerable/CompleteAdding で Thread.Sleep ポーリング待機を排除。保存連番は独立カウンタで従来順序を維持。try/finally で包み、例外時も CompleteAdding() を必ず呼んで消費者(保存スレッド)の永久ブロックを防止(例外はそのまま伝播。ユーザー向けエラー表示・撮影中断は優先度3 で別途)。テスト方針(GUIDE_08)整備 (2026-06-07): 立ち上げフローの規約整備フェーズが未着手だったため、品質管理の土台としてテスト方針を策定。ハードウェア結合層(カメラ/UI/スレッド)と純粋ロジック層を分け、後者を NUnit で自動テスト、前者をビルド+手動+実機回帰で担保する方針。
/implement のテストフェーズが毎回「テスト不可」で終わっていたが、実態は純粋ロジック層(ColorCorrector 等)にテストプロジェクトを立てていなかっただけ、という認識のズレを是正。TIASshot.Tests, NUnit / x64 / .NET Framework 4.8)の立ち上げと ColorCorrector・Config・IoUtil 等の初期テスト作成(次ステップ)。 エラーハンドリング方針(GUIDE_09)整備 (2026-06-07): 既存の実装パターン(ErrorMsg+bool 返却・MessageBox・Debug.WriteLine・ShowMessage)を土台に,エラーの分類(起動時致命/処理中の回復可能/プログラミングエラー)・処理方法・ログ方針を軽量に標準化。
Debug.WriteLine のみとし永続ログファイルは作らない(撮影現場での解析が必要になったら別途見直す)。空 catch 禁止・例外時のスレッド同期資源の finally 終端を明文化。 テストプロジェクト立ち上げ(TIASshot.Tests, NUnit) (2026-06-07): GUIDE_08 に従い,ピュアロジック層を自動テストする基盤を構築。ColorCorrector(次元拡張・変換行列・色変換)・Config(パース)・IoUtil(CSV 往復)に初期テストを追加。
OpenCvSharp4.runtime.win のネイティブコピー規則をそのまま機能させ,dotnet test ではなく vstest.console.exe /Platform:x64 で実行)。NUnit 3.14 を採用。[InternalsVisibleTo("TIASshot.Tests")] 追加,ColorCorrector の純粋メソッドを private→internal・チャネル配列を受け取る internal コンストラクタ追加,Config.Load(string path) オーバーロード追加。IoUtil の CSV テストが通る=ネイティブ動作の試金石)。.gitignore を汎用 bin/・obj/ に変更し,テストプロジェクトの成果物も除外。GetRatio(ゲイン補正式)は CameraBase(ハードウェア結合層)にインラインのため未テスト。抽出すればテスト候補。ENV_02 のメインソース一覧がリファクタ前構成のままドリフトしており,別途修正が必要。 docs ドリフト修正(ENV_02・TECH_01) (2026-06-07): リファクタリング(Phase 1〜5)後も旧構成のまま残っていたドキュメントを実構成に整合。ENV_02 のソース一覧をサブフォルダ構成に、TECH_01 のファイルパス・クラス一覧(ChartDetector/ColorCorrector/IoUtil 追加)・CameraBase メンバ(移動した ConvertImage/_convRGB2SRGB 削除)を修正。
ゲイン補正式(GetRatio)の純粋メソッド抽出+テスト (2026-06-07): CameraBase にインラインだったゲイン更新比率の計算式を,ハードウェア非依存の純粋クラス GainCalc.CalcRatio に抽出し,CameraBase.GetRatio は委譲に変更。TIASshot.Tests でテスト対象化(GUIDE_08 の「ピュアロジック層を分離して自動テスト」方針の実践)。
float 比較・ゼロ除算挙動・UpdateRate の流れをすべて保持し,派生クラスの呼び出し箇所は無変更。実機で校正(ホワイトバランス自動調整)の収束を確認。updateRate 減衰・下降補正(target<value)・value==target→1.0・value==255 の係数 1.0 特別扱い・updateRate=0 の更新停止・ゼロ除算(Infinity/NaN)の現状固定。 PLAN_02 優先度2: ConvertImage の中間 Mat 未 Dispose(OOM クラッシュ)修正 (2026-06-07): 連続撮影で ColorCorrector.ConvertImage 内の中間 Mat(flatten/extended/converted/convertedImage)が解放されず数十 GB 規模で蓄積し OOM クラッシュする不具合を,入れ子 using で確実に Dispose して修正。
convImg8 は using の外で ConvertTo のコピー後に返却し use-after-dispose を作らない。テスト容易化のため private→internal(挙動不変)。ConvertImage の src in-place 書き換え)は未修正。現状挙動をテストで記録済み(修正時に検出可能)。 白板撮影モード(照明均一性評価用・DEBUG 限定) (2026-06-07): SmTIAS との装置間比較(照明均一性評価)用に、ImagingSource DFK 23UX249 を対象とした白板撮影機能を追加。#if DEBUG 限定で配布版には出さない。
Utils/ImageStats)に分離し自動テスト(GUIDE_08)。実機で 10 枚撮影・Color Enhancement OFF・飽和率0・p99=181(露出適正)を確認。WhiteBoard_*)に加えクロップなしのフルフレーム(WhiteBoard_full_*)も保存。飽和統計は ROI のみ(白板領域の露出チェックが目的)。実機で full=1200×1920・ROI=1136×1528 が設定どおりと確認。finally での状態復元は今後の検討事項)。JSON の固定状態文字列(gamma_setting 等)は device-state 由来の決め打ちで動的読取ではない。 白板撮影の出し分けを専用ビルド記号 WHITEBOARD に変更 (2026-06-18): 白板撮影モードを #if DEBUG から独立した #if WHITEBOARD に切り替え、Form1.Designer.cs の条件コンパイルを全廃(白板ボタンを専用 partial ファイルに分離)。あわせて白板ボタンの長年のレイアウト衝突(データ保存フォルダ欄との重なり)を修正。撮影ロジックは不変。
#if が入っていると WinForms デザイナで破損するリスクがあったため全廃が主目的。WHITEBOARD を定義、Release は未定義)。 PLAN_02 メモリ修正の効果検証ツール(NUnit ベンチ+実アプリ統合のメモリ観測ウィンドウ) (2026-06-23): 優先度2(ConvertImage 中間 Mat 解放)の効果を定量・デモ両面で検証できるようにした。定量は NUnit [Explicit] ベンチ(修正前リーク再現 vs 修正後を同条件反復し PrivateMemory/WS の peak・増分を比較)。デモは TIASshot 本体に統合したメモリ観測ウィンドウ(MEMMONITOR 記号・起動時自動オープン・Timer サンプリングのライブ折れ線+CSV)で実使用時のメモリをライブ可視化。
MEMMONITOR、Release 除外)。さらに対比録画用に LEAKY_REPRO 記号で ConvertImage を修正前(中間 Mat 未解放)に戻せるようにした(既定未定義=修正後)。GC.GetTotalMemory では捕捉不可 → Process.PrivateMemorySize64/WorkingSet64 を使用。OpenCvSharp が GC にメモリ圧を通知するためリーク版でも GC+ファイナライザで周期回収が起き、グラフはのこぎり波になる(見るべきは振れ幅でなくピーク包絡線のトレンド:修正後=天井一定、リーク=上昇)。_shots/_chartMasks の Clear 時未解放)は未修正のため LEAKY_REPRO の対象外(対比は優先度2のみ)。グラフのトレンド可視化(包絡線・移動平均等)は要望次第で追加余地。 連続撮影フロー再現のメモリ計測ベンチ+計測結果レポート (2026-06-23): 既存の単体ループベンチ(ConvertImage 隔離)では本番の連続撮影フローを再現できていなかったため、カメラ取得部だけを合成フレームに差し替えて本番フローを構造再現するベンチ(ContinuousShootMemoryBenchmark)を追加。生産者-消費者スレッディング・1 フレーム複数チャンネル変換・フレームバッファを含む。修正前/後の計測結果を docs/06_TEST/TEST_01_メモリ修正効果計測.md にまとめた(カメラ実機不要・ヘッドレスで Claude 側が実行可能)。
CameraBase.RunShotLoop/SaveThread/SaveImages を直接ヘッドレス実行するには Form1・Config・TCC・校正で埋まる _convRGB2SRGB 依存が重すぎる → 本番コード無改造のまま「フローの構造再現」を選択(本番メソッドそのものの呼び出しではない旨を明記)。リーク再現と計測ユーティリティは MemBenchSupport に共有化し既存ベンチと統一。 PLAN_03 プレビューメモリリーク修正+派生クラッシュ・副モニタ描画飢餓の解決 (2026-07-11): PLAN_03(撮影経路とは別系統の「プレビュー表示中の長時間クラッシュ」)の原因1〜3(ShowImage のフルコピー Bitmap リーク・表示バッファの取りこぼし未 Dispose・PreviewMonitor.UpdateImage の上書き前未 Dispose)を修正。実機検証の過程でさらに 2 件(Lucam のクロススレッド GDI クラッシュ・副モニタの描画飢餓)が発覚し、あわせて解決した。実機のメモリ観測(MEMMONITOR)で反復検証。
_bmps[] をコールバックスレッドで Dispose するため、それを直接 picDisplay.Image に載せると UI の OnPaint と衝突し「オブジェクトは現在他の場所で使用されています」で落ちる(v1.6 からの潜在バグ)。→ 入力 bmp は「読むだけ」に統一し、表示は UI 所有コピー、入力の Dispose 責任は呼び出し側(IScam は自分の ToBitmap を破棄)に置く。BeginInvoke 案は Lucam の「ShowImage 直後に _bmps を Dispose」する同期前提を壊すため不採用。DetectChart が止まりコールバックが高速化 → コールバックスレッドからの毎フレーム Invalidate() 洪水で Form1 が常時 WM_PAINT 保留になり、同一 UI スレッドを共有する副モニタが飢餓(sub_paint_fps≈2)。sub_paint_ms(実描画時間)が崩壊中も低いまま=描画は軽い、img_w/h 一定=画像肥大でない、gdi_objects が上限(1万)に対し桁違いに小さい=ハンドル枯渇でない、という三点の否定でスケジューリング(メッセージ枯渇)に原因を絞り込めた。 プレビューのフレームコピーを LockBits で高速化 (2026-07-11): プレビュー表示経路で毎フレーム生成する Bitmap コピー(new Bitmap(bmp))が 1 回 ~25ms かかり、コールバックスレッドの律速で実効 ~10fps に頭打ちだった問題を、生画素の直接コピーに置換して解消。実機計測で コピー 25ms→2.5ms(約10倍)、callback_fps 16→30、両プレビュー描画 10→20fps を確認。
new Bitmap(Image) は内部で 32bppARGB への変換を伴う GDI+ DrawImage 経路を通るため遅い。プレビューは 24bppRgb(Mat.ToBitmap() 由来)で、同一フォーマットの生画素をそのままコピーすれば足りる。LockBits で src/dst の生画素ポインタを取得し RtlMoveMemory(kernel32)で行単位ネイティブコピーする FastClone(/unsafe 不要)。生成物は入力と独立した画素バッファ=所有権・スレッド安全性(Lucam クロススレッド Dispose と非衝突)は従来の new Bitmap(bmp) と同一で不変。src は ReadOnly ロックのみで非破壊。インデックスカラー(8bpp 以下・パレット保持要)は安全網として従来の GDI+ フルコピーにフォールバック(この経路は色は等価だが PixelFormat が 32bppArgb に変換される点に注意)。FastClone のみ(独立コピー・src 非破壊・ストライドパディング・Indexed フォールバック・null)。プレビューのタイマー駆動描画・_dispBufLock を介したクロススレッド Dispose の所有権・WM_PAINT/WM_TIMER のスケジューリングは UI スレッド/GDI/実カメラ・副ディスプレイ結合層でユニットテスト不能のため、実機 MEMMONITOR 計測(コピー時間・各段 FPS・GDI/handle・描画時間の CSV)で反復検証した。