fullseye

円形部品の内径を mm まで測る

できること

穴・リング・ピンの内径を、粗い中心出し → サブピクセルの円当てはめ → 実寸校正 → mm、まで一気通貫で出します。文書だけを渡した AI は measure_pairs / apply_metrology_model で px のまま止まっていた(2026-09-15)ので、最後の 2 段(mm_per_px_from_reference / pixel_to_world)を op として型連鎖に置いてあります。

What it does

Bore, ring and pin diameters end to end: a coarse centre, a sub-pixel circle fit on radial measurement lines, a calibration from a reference of known size, and the result in millimetres. The last two steps exist as typed operators because an assistant working from the notes alone stopped at pixels.

向くところ / 向かないところ

向く: 平面視で撮った穴・リング・ピン。縁が背景と十分なコントラストを持ち、参照半径を ±6 px 以内で置けるとき。

向かない: ★透視の効く斜め撮影(円が楕円に写る —— add_metrology_object_ellipse_measure へ)。★縁が面取り・丸みを持つ実物では「どこが縁か」が定義依存で、面取り 5 → 6 px で答えが 11.7 px 飛ぶ(subpixel_measuring.md §3)。★円周の一部が欠けていても当てはめは通る —— rms を必ず門にする。

推奨パイプライン

gaussian → otsu → area_center → create_metrology_model → add_metrology_object_circle_measure → apply_metrology_model → mm_per_px_from_reference → pixel_to_world

gaussian で雑音を落とし → otsu で穴を 2 値化 → area_center で粗い中心と面積(半径の初期値 √(面積/π))→ create_metrology_model に add_metrology_object_circle_measure(row, col, radius, n) で参照円を積み → apply_metrology_model で半径方向の測定線からサブピクセル円フィット(params["radius"]、rms)。校正は同じ opで既知径の的を測って mm_per_px_from_reference → pixel_to_world(2 * radius, mm_per_px)。

代替

円周の一部だけ測るなら gen_measure_arc → measure_pos。輪郭からの当てはめは hx_fit_circle_contour、粗探索は cv_hough_circles / hough_circle_trans(半径レンジが直書きで峰が立たないことがある —— poc_real_coin_metrology)。結果の表ごと mm にするなら table_px_to_mm。

限界

実寸校正

既知径の的(リングゲージ・基準穴・コイン)を同じ光学系・同じ作動距離・同じ円 opで測り、mm_per_px_from_reference(2 * radius_px, known_mm) で mm/px を出す。example_inner_diameter_mm は 10.00 mm の的と 6.13 mm の被測定を同じ画素ピッチで描き、mm で真値に戻ること(および公称倍率で置いたときのずれ)を示す。

最初の 1 本

import fullseye as fs
import numpy as np

yy, xx = np.mgrid[0:160, 0:160].astype(float)
img = np.where(np.hypot(yy - 80.4, xx - 79.6) < 40.0, 0.2, 0.8)   # 暗い穴 R=40 px
model = fs.ledger.create_metrology_model()
fs.ledger.add_metrology_object_circle_measure(model, 80.0, 80.0, 41.0, n=72)
r = fs.ledger.apply_metrology_model(model, img, measure_length=6.0)[0]
mm_per_px = fs.ledger.mm_per_px_from_reference(2 * 100.0, 10.0)     # 的 10 mm = 200 px
print(fs.ledger.pixel_to_world(2 * r["params"]["radius"], mm_per_px), "mm  rms", r["rms"])

裏づけ