Files
yoshikazuandClaude Opus 4.8 e4eca6b303 Initial commit: ノーコード画像検査アプリ (MVP + 追加機能一式)
検査レシピ=処理/検査ステップの縦リスト(配線なし)。yfoxlib(yfoximg/yfoxbase)使用。

- ビジュアル・パイプライン(カード+適用後サムネイル+緑/赤 合否)
- テンプレート/対話式ウィザードでレシピ生成(CTaskDialog)
- パラメータのスライダー・ライブ調整
- レシピ保存/読込(*.itr) + 最近使ったファイル(MRU)
- 検査範囲(ROI)を複数マウス指定(ドラッグ追加/右クリック削除)
- カードのドラッグ並べ替え
- 判定結果画像の保存 + 検査ログCSV(項目拡張)
- 処理6種+検査3種(明るさ/白画素率/塊の数)
- /selftest(実行+レシピ往復+結果画像+複数ROI塊カウント検証)、/demo

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-23 09:26:10 +09:00

9.5 KiB

CLAUDE.md

This file provides guidance to Claude Code when working with code in this repository.

概要

ImgTestSystem は yfoxlib(yfoximg / yfoxbase)を使う ノーコード画像検査アプリ(純MFC)。 パラダイムは隣の C:\debug\ImgChkSystem(ブロックをワイヤで繋ぐノードエディタ)とは 意図的に別物:

検査レシピ = 上から下へ順に実行する「ステップ」の縦リスト(配線なし)。 料理のレシピ / 検査チェックリストのメタファ。ステップは2種:

  • 処理(画像を加工): グレー化 / メディアン / 二値化(帯) / 大津 / ガンマ / コントラスト
  • 検査(測って範囲判定→PASS/FAIL): 平均輝度 / 白画素率

UI: 左=ステップ縦リスト(追加/削除/↑↓)・右上=選択ステップのパラメータ入力・右下=作業画像プレビュー・ 上部=[画像を開く]/[実行]と総合判定バナー。ノーコード=ドロップダウンと数値入力のみ、コードもワイヤも書かない。

ビルド

VS2022 (v143 / MFC Dynamic / Release|x64 / /utf-8 / stdcpp17)。

$msb="C:\Program Files\Microsoft Visual Studio\2022\Professional\MSBuild\Current\Bin\amd64\MSBuild.exe"
& $msb ImgTestSystem.sln /p:Configuration=Release /p:Platform=x64
  • リンク: yfoximg.lib;yfoxbase.lib;gdiplus.lib(libdir C:\debug\yfoxlib\x64\$(Configuration))。
  • include: C:\debug\yfoxlib\yfoximg;...\yfoxbase;...\yfoxbase\include。
  • PostBuild で yfoximg.dll/yfoxbase.dll を出力先へコピー。出力=bin\x64\<Config>\。

アーキテクチャ

UI非依存の core/ と MFC UI層(ルート)に分離。

core/(ウィンドウ非依存)

  • Recipe.h — StepKind(処理/検査)、StepParam(数値パラメータ)、Step、Recipe(ステップの並び)。
  • StepCatalog.h — 種別→表示名 StepName / 検査判定 IsInspect / 既定パラメータ生成 MakeStep / パレット AllStepKinds。 新ステップ追加は StepKind に足し、この2関数(StepName/MakeStep)と InspectEngine の RunStep に1ケース足すだけ。
  • InspectEngine.h/.cpp — 唯一 yfoximg に依存する層。LoadImage→Run(recipe, upTo) で作業画像を原画像から作り直し、 各ステップを CImgProcessing(RGB2BW/Threshold/Threshold_Otsu/Avg/Gamma/Contrast/Median)で適用。 upTo>=0 でその番号までプレビュー実行、-1 で全実行し総合 PASS/FAIL を返す。DrawWork でプレビュー描画。

UI層(ルート)

  • App.h/.cpp — CImgTestApp:CWinApp。GDI+ 起動、/selftest 分岐、CMainFrame 生成。
  • MainFrame.h/.cpp — CMainFrame:CFrameWnd。子コントロールは リソース不使用で OnCreate で動的生成(.rc なし=RC の cp932 罠を回避)。 リスト選択→パラメータ欄ロード+PreviewUpTo、[追加/削除/↑↓]でレシピ編集、[実行]で全実行+バナー更新。
  • SelfTest.cpp — /selftest(ヘッドレス)。合成画像→レシピ実行→selftest_result.txt(UTF-8)。

yfoximg 作法(重要)

  • アンブレラ yfoximg.h(OpenGL 引き込み)は使わず ImgProcessing.h を直接 include。
  • yfoximg は NOMINMAX を定義しない(裸の min/max マクロ前提)。GDI+ も min/max マクロを要求するため、 ImgProcessing.h を含む TU(InspectEngine.cpp/SelfTest.cpp)では std::min/std::max を使わない(手書きクランプ)。
  • 8bit グレー画像は SetGrayPalette() してから Draw/Save。処理系は R1(入力不変)・R2(出力は新規 CDiBitmap)。
  • 画像は 8/24/32bit を受理。Ensure8 が 32→24(手動)→RGB2BW で 8bit へ正規化してから濃淡系処理を行う。

検証

  • ImgTestSystem.exe /selftest → 合成画像(一様輝度128)で グレー化→平均輝度→白画素率 を実行し PASS を確認、 selftest_result.txt を出力(終了コード 0=PASS)。

わかりやすさ強化(3方式を統合)

  • ビジュアル・パイプライン(PipelineView.*, CPipelineView:CWnd): 各ステップをカード化し、 「そのステップ適用後のサムネイル」を縦に並べる=画像が上から下へ変化する様子が見える。 検査カードは大きな緑✓/赤✗バッジ+測定値。左ストライプ 青=処理/橙=検査。ダブルバッファ描画・ホイール/スクロール対応。 罠: CDiBitmap::Draw(サムネ)は DC の BkMode を OPAQUE/暗色へ戻すので、直後の文字描画前に SetBkMode(TRANSPARENT) を必ず再設定する(でないと暗地に明字で反転)。
  • テンプレート(core/Templates.h + wizard::ChooseTemplate): 目的(キズ/欠け/明るさ/文字)を選ぶと完成レシピが入る。
  • 対話式ウィザード(Wizard.* + CTaskDialog): Q&A でレシピ生成。.rc 不要のため CTaskDialog(要 Common-Controls v6 マニフェスト=stdafx.h の pragma)。
  • 右パネル: 選択ステップのパラメータを CSliderCtrl でライブ調整(OnHScroll→即再実行→サムネ更新)。整数域は実値、 ガンマ等の実数域は 0..1000 マッピング。合否バナーは OnCtlColor で緑/赤/灰に色分け。
  • 検査種別に 塊(キズ/穴)の数(InspectBlobCount)を追加(LabelingInit/Labeling/m_nLabelCount)。

検証(追加)

  • ImgTestSystem.exe /demo → デモ画像(明るい地に暗い欠陥3点)+ キズ検査テンプレを読み込み実行(画面確認用)。 スクリーンショットは PrintWindow(PW_RENDERFULLCONTENT=2) で捕捉可(Windows PowerShell 5.1 + System.Drawing)。

レシピ保存/ROI/並べ替え/検査ログ(追加実装)

  • レシピ保存/読込(core/RecipeStore.*): 人が読める UTF-8 テキスト *.itr(STEP <id> / PARAM <key> <val> / ROI ...)。 StepKindId/StepKindFromId(StepCatalog.h)で enum を安定文字列 ID として永続化。読込は MakeStep 既定へキー一致で上書き(前方互換)。メニュー ファイル。
  • 検査範囲 ROI(Recipe::roiEnabled/roi): 大プレビュー上をドラッグして矩形指定(CMainFrame::OnLButtonDown/MouseMove/Up)。 描画メソッド DrawShot/DrawSource は実際に描いた矩形(アスペクト維持=AspectFit)を返し、client↔画像座標の相互変換に使う。 検査は ROI 内で計測: 明るさ=RectAvg(roi) / 白画素率=Threshold(...,roi)÷ROI面積 / 塊数=Labeling(...,roi)。処理ステップは寸法不変なので全ステップ ROI 同座標系。ROI は大プレビュー+カードサムネに黄枠表示。メニュー 検査範囲。
  • カードのドラッグ並べ替え(CPipelineView): 押下→しきい値超で m_dragging、青い挿入インジケータ、離すと WM_PV_MOVESTEP(from,slot)→CMainFrame::OnPipeMoveStep が並べ替え+再実行。
  • 判定結果画像の保存 / 検査ログ: InspectEngine::SaveResultImage=最終画像を24bit化し ROI枠+PASS/FAIL バナー+検査要約(縁取り文字)を焼き込み保存(拡張子で png/bmp/jpg)。 検査ログ=記録フォルダ(SHBrowseForFolder)へ result_<ts>.png 保存+inspect_log.csv(UTF-8 BOM, 日時/総合/画像/詳細)追記、フォルダを開く。メニュー 検査ログ。
  • ⚠ 罠: Windows ヘッダの #define small char(rpcndr.h)のため、ローカル変数名に small を使うと C2628。fSmall 等にする。

複数ROI / MRU / CSV拡張(追加実装)

  • 複数ROI(Recipe::rois = vector<CRect>。空=画像全体): 大プレビューをドラッグで範囲追加、右クリックでその範囲を削除、 メニュー 検査範囲=「最後を取り消す」「すべてリセット」。検査は全ROIを合算(明るさ=面積重み付き平均 / 白画素率=合算/合計面積 / 塊数=全ROIマスクを結合→union bbox でラベリング)。 大プレビュー+カード+結果画像に黄枠+番号を描画。.itr は ROI l t r b を範囲ごとに1行(旧 ROI enabled l t r b 5値も読める)。
    • ⚠ 重要バグ修正: yfoximg CImgProcessing::Threshold を同一バッファへ sub-rect で複数回呼ぶとマスクが壊れる(2個ROIで塊数0になった)。 MakeBinary は Threshold をやめ、画素を直接走査してROI内だけ白く塗る方式に変更(8bit前提=Ensure8済)。/selftest に複数ROI塊カウント検証(全体3/大ROI2/小2個ROI2)を常設。
  • 最近使ったレシピ(MRU): 最大5件を HKCU\Software\YFox\ImgTestSystem\Recent\File1..5 に保存(SetRegistryKey(L"YFox"))。 ファイルメニューの「最近使ったレシピ」サブメニュー(m_hRecentMenu を保持し UpdateRecentMenu で再構築、ON_COMMAND_RANGE)。開く/保存時に AddRecent。存在しない項目はクリック時に一覧から除去提案。
  • 検査ログCSV 拡張: 列= 日時,総合判定,元画像,レシピ,ステップ数,検査数,合格数,不合格数,検査範囲数,結果画像,詳細(UTF-8 BOM)。記録フォルダも HKCU\...\Log\Folder に永続化。

現状

処理6種+検査3種、ビジュアル・パイプライン、テンプレート、ウィザード、スライダー調整、 レシピ保存/読込(+MRU)、複数ROI 指定、カードのドラッグ並べ替え、判定結果画像保存/検査ログ(CSV拡張)、/selftest・/demo。 /selftest は 実行 + レシピ往復一致 + 結果画像保存 + 複数ROI塊カウント を検証(RESULT: PASS)。