Newer
Older
SmTIAS-LightSim / scripts / select_white_board.py
"""実測 PNG で白色板の境界をマウスドラッグで選択する GUI スクリプト.

使い方:
    uv run python scripts/select_white_board.py \
        [--image reference_measurement/.../*.png] [--output configs/white_board_bbox.json]

操作:
    1. 表示された画像で白色板の **境界を囲むように** マウスでドラッグして矩形を引く
    2. Enter または Space で確定
    3. 結果が JSON に保存される

備考:
    実画像は 2448x3264 と大きいので 30% 縮小表示する.座標は実寸に変換して保存.
"""

from __future__ import annotations

import argparse
import json
from pathlib import Path

import cv2


def main() -> None:
    parser = argparse.ArgumentParser(description="Select white board boundary in real PNG")
    parser.add_argument(
        "--image",
        type=Path,
        default=Path("reference_measurement/MiniTIAS_20260408_144434/MiniTIAS_20260408_144434.png"),
        help="実測 PNG パス",
    )
    parser.add_argument(
        "--output",
        type=Path,
        default=Path("configs/white_board_bbox.json"),
        help="出力 JSON パス",
    )
    parser.add_argument("--scale", type=float, default=0.3, help="表示時の縮小率")
    args = parser.parse_args()

    if not args.image.exists():
        msg = f"画像が見つかりません: {args.image}"
        raise FileNotFoundError(msg)

    img = cv2.imread(str(args.image))
    if img is None:
        msg = f"画像を読み込めません: {args.image}"
        raise RuntimeError(msg)
    h, w = img.shape[:2]
    print(f"画像サイズ: {w} x {h}")

    small = cv2.resize(img, None, fx=args.scale, fy=args.scale)
    print("白色板の境界をマウスでドラッグして選択してください(Enter/Space で確定)")
    bbox_small = cv2.selectROI(
        "Select white board (drag, then Enter/Space)",
        small,
        fromCenter=False,
        showCrosshair=True,
    )
    cv2.destroyAllWindows()

    if bbox_small == (0, 0, 0, 0):
        print("選択がキャンセルされました")
        return

    # 実寸に戻す
    x = int(bbox_small[0] / args.scale)
    y = int(bbox_small[1] / args.scale)
    bw = int(bbox_small[2] / args.scale)
    bh = int(bbox_small[3] / args.scale)
    result = {
        "image": str(args.image),
        "x": x,
        "y": y,
        "width": bw,
        "height": bh,
    }

    args.output.parent.mkdir(parents=True, exist_ok=True)
    args.output.write_text(json.dumps(result, ensure_ascii=False, indent=2), encoding="utf-8")
    print(f"\n保存: {args.output}")
    print(f"白色板 bbox: x={x}, y={y}, width={bw}, height={bh}")
    print(f"画像中心からのオフセット: ({x + bw//2 - w//2}, {y + bh//2 - h//2})")


if __name__ == "__main__":
    main()