目的 = Fullseye Studio(
studio.py)を MVTec HDevelop に忠実な画像処理 IDE にする。 原則 = 「IDE の画面はシンプルかつ多機能」「情報密度が高い」(ユーザー 2026-08-15、[[feedback_ide_design_simple_multifunctional]])。 本ドキュメントは複数セッション横断の実装スペック。各セッションはここを読んで続きを実装する。
content/ide/index.htmlcontent/ide/debugging/index.htmlcontent/halcon_script/index.htmlcontent/reference/index.htmldev_display/dev_set_color/dev_set_draw/dev_set_colored/dev_set_lut が現在の active window に作用。dev_display)。control をダブルクリック→ Variable Inspection。ステップ実行に連動して変数状態が更新。| Operator Window: オペレータ選択コンボ(オートコンプリート) + カテゴリツリー + 検索。1 パラメータ = 1 行で **名前 / 型 / 方向(iconic | control × in | out) / デフォルト / 候補値ドロップダウン / min-max / inline doc。引数入力までできる。コードへ挿入と単発実行(single-shot)の両方が可能で、結果を Graphics Window で確認**できる。 |
read_image→Image、threshold→Region、connection→ConnectedRegions、edges_sub_pix→XLD。dev_display。region は image 上に色 overlay(dev_set_draw の margin/fill、複数色 dev_set_colored)。if / elseif / else / endif・for / endfor・while / endwhile・repeat / until・break / continue / return / stop / exit・代入 :=。< > <= >= = #、論理 and / or / xor / not。タプル [1,2,3]。operator (Params) は 公式 Script Reference で確定してから実装。線形 a/b パイプライン(op,a,b の列)→ 変数 + 制御文 + 型付き引数の HDevelop 型へ段階進化。
op_arg_roles/op_impl_source/op_signature_detail で knob a/b の役割 + 実装式を高密度表示(「引数が判断できない」を解消)。op (params)・:=・コメント・if/else/for/while)。実行モデル(step/breakpoint/実行カーソル)と Variable/Graphics 連動。QT_QPA_PLATFORM=offscreen)でテストする(build_window ハンドル経由)。QMenu(title, parent))で shiboken 回収を防ぐ(v18.7 で判明)。open_window/dev_open_window の WindowHandle)。dev_* 系オペレータ(dev_display/dev_set_color/dev_set_draw/dev_clear_window 等)はカレント窓へ描画。dev_set_window(Handle) でカレント切替。→ Studio 実装: 各 graphics 窓に handle 番号 + カレント窓ポインタ + 変数ダブルクリック=カレント窓へ描画 + カレント切替 UI(窓クリック or ハンドル指定)。★自律 UI 操作ハーネスを実装(tools/studio_ui_harness.py)。offscreen subprocess で Studio を起動し、実マウスイベント(QMouseEvent 直送=drag は buttons=LeftButton 保持)を全 QPushButton / 全 QAction / 全 dock ドラッグ / 変数リスト / 右クリックコンテキストメニューへ注入(P0–P9 の 183 ステップ)。設計:
faulthandler。硬い C++ segfault は親が exit code + step-log の最後の phase_start + native traceback で帰属。QDialog.exec)は CONFIRM/ERROR stub + QFileDialog monkeypatch + watchdog QTimer(activeModalWidget と activePopupWidget=QMenu.exec も閉じる)。sys.excepthook で queued signal 内の非同期例外をフェーズ付きで記録。graphics_primary の生存 + in-MDI を記録。★ハーネスが実イベント注入でしか出ない 3 クラッシュを自動検出→修正(全て studio.py、regression テスト付き tests/test_studio.py):
show_3d_surface(旧 737 行)の Q3DSurface() は OpenGL コンテキスト不在(offscreen / Remote Desktop / ソフトウェア GL)で native segfault、try/except は import 失敗しか捕捉せず。→ _opengl_available()(QOffscreenSurface+QOpenGLContext プローブ、offscreen は即 False)でゲート、open_3d は None 時に「3-D surface needs OpenGL」を flash。GL があれば動く / 無ければ無害に degrade / 決してクラッシュしない。b_save(Save result)は image_panel(=プライマリ Graphics 窓)内にあり、窓破棄で削除されるが queued currentRowChanged→update_actions が setEnabled で RuntimeError: Internal C++ object already deleted。→ _enable(cond, *widgets) ヘルパで削除済みを skip(状態同期は生存分を継続)。image_panel ごと view/b_save が破棄。→ プライマリ サブ窓に close 拒否 event filter(_ResidentCloseGuard)+ detach_graphics はプライマリ(objectName == "graphics_primary")の detach を拒否。常駐カレント窓モデルの第一歩。検証 = ハーネス再走で 183 steps 全 OK・slot 例外 0・crash 0、プライマリ窓は全 10 フェーズで alive+in-MDI 維持(修正前は P2 の MDI「Close」で in-MDI=False→P9 で削除→クラッシュ)。studio テスト 69→72(detach テストを常駐仕様へ更新 + resident/update_actions/3D の 3 回帰追加)。dock ドラッグ(GroupedDragging 疑い)は全 25 パターンで crash せず(自動プロキシは通過。実 windowing-system の native drag とは差があるため実機確認は別途)。
用途 = 「画像処理アルゴリズムを対話的に組み・パラメータを詰め・holdout 検証する」設計作業(HDevelop 経験者が同等の操作感を期待)。Codex に studio.py + 本 doc を読ませ、操作フローに限定して 12 件の code-backed 批判を取得(各件を私が一次コード検証。規律=鵜呑み禁止 [[feedback_external_ai_verify]])。採用した論点(★=次の実装対象):
new_graphics_window 1550– は窓を追加するだけ、_render は常に固定 view へ)= 本 doc の北極星「カレント窓モデル」と一致。操作対象と結果表示先が乖離。→ P4-current: カレント窓ポインタ + ハンドル番号 + dev_set_window 相当の切替 UI + _render/display_variable/run_op_once をカレント窓へ。上記修正 3(常駐化)がその土台。display_variable(True)→常に新窓)。HDevelop は active 窓へ表示。→ ダブルクリック=カレント窓へ、Shift/ボタンで新窓。run_op_once 1861–、入力 model.image 固定)。中間結果や選択変数を入力にできない。→ カレント窓表示 + 入力=選択ステージ/変数の結果を選べるように。_var_icon は 2D/3D ndarray のみ)。step_to は refresh_variables を呼ばない、全ステージ先行計算で未実行の後段も存在して見える)。confirm_discard は Pipeline のみ、code_edit の変更未追跡、sync_program が上書き)。remove が select 指定なしで refresh)。load_image は単一画像のみ、load_frame_b は 2 フレーム perception 用)= 用途の最終工程が未完結。要ユーザー判断(スコープ大)。次の実装順(deliberated): (P4-current)カレント窓モデル ← 常駐化済で土台あり・最大クラスタ(Codex #1–5)を一括で筋通し → (P2b’)op 別引数 UI → (step 連動)→(Program dirty 追跡)。Undo / holdout 経路はスコープ大ゆえユーザー確認後。
_fs_handle、never-reused の連番 _gfx_handle_seq)を各 graphics 窓に付与。primary=1、new/reattach で連番。win._current_gfx(既定=常駐プライマリ)+ mdi.subWindowActivated→追従(窓クリックでカレント切替=dev_set_window)+ ステータスバー右に「current: Graphics N」常設表示。display_variable(target) を "current"/"new"/"main" の 3-way に(旧 bool 互換維持)。v_disp=新窓 / v_here「Display → current」/ 右クリックも current/new に。_current_view()(カレント窓の ImageView、閉窓時はプライマリへ自己修復)/ _current_handle()。回帰 test_current_graphics_window_model。ハーネス実測=変数操作の窓増殖が 8→5 に減少。残(Codex #1)= パイプライン結果 _render 自体を current 窓へ出す案は結果表示の意味変更が大きく、現状はプライマリ固定のまま(要検討)。次=P2b’ op 別引数 UI。_ARG_ROLES(既存 curated 表)+ _knob_label ヘルパ。公開 win._op_arg_labels。回帰 test_operator_arg_labels_reflect_selected_op。ユーザー指針=「画像を一番大きく / 次にスクリプトコード / op選択・変数窓は縦小さめ・ほとんどドッキングせず必要時のみ表示」。
setCorner で下部 Program を画像下のみに限定。layout_version 2→3(既存 save を無効化し新既定を反映)。回帰 test_default_layout_is_image_dominant。「Balanced (default)」プリセットは従来通り全表示(reset は全 show)。run_holdout(stages, image_paths, gt_paths=None)(Qt-free、api.run_pipeline で検証画像フォルダを batch 実行→per-image ran/failed+timing、GT フォルダがあれば holdout_metric=IoU(binary)/PSNR(intensity) の per-image+mean、honest=GT 無ければ metric 出さず)+ Studio「Validate on holdout…」(Ctrl+H, Run メニュー)=フォルダ選択→結果テーブル+集計+honest note。imgevolve 北極星(holdout gate)を UI に接続。残(Codex #1)= パイプライン結果 _render 自体を current 窓へ出す案のみ未実装(意味変更大・要検討)。回帰 test_undo_redo_pipeline_edits / test_program_editor_tracks_unapplied_edits / test_step_through_marks_variable_frontier / test_remove_keeps_a_neighbour_selected / test_holdout_*。studio テスト 69→82、full suite 4300→(次計測)、ハーネス 192 steps・fail0・slot0。