fullseye

特徴抽出・テクスチャ・形状記述 — 使い方ガイド

この族は何をする道具箱か

この族は「画像を別の画像に変える」フィルタ群とは目的が違う。入力(region / contour(XLD) / image / color / volume)を受け取り、数えて測った“数値”を返す——「いくつ物体があるか」「どれだけ丸いか/細長いか」「明るさの平均・分散・エントロピー」「モーメント不変量」「キーポイントや直線・円の本数」「ざらつき(テクスチャ)記述子」——を一括で扱う計測・記述レイヤである。ほとんどの op は feature(有限スカラ、fullseye.apply は Python の float を返す)を出力し、Hough 変換系の 2 つ(hough_line_trans / hough_circle_trans)と自己相似の xmh_selfmatch だけは投票空間/相似マップという image を返す。

前段(2値化・領域分割・輪郭抽出)は別の族が担い、この族はその出力に対して「言い当てる」役に回る。典型的には gallery2d_segmentation の閾値・分割 op で image → region を作り、そこへ本族の region 計測をかける。あるいは edges_sub_pix などで image → contour(XLD) を作り、本族の *_xld 計測をかける。image を直接受けるグレー統計・キーポイント計数系はその前処理すら要らない。HALCON の count_obj / circularity / moments_region_* / *_xld / gray feature 群に対応し、加えて scikit-image・OpenCV・mahotas・PyWavelets 由来の blob/コーナー/ウェーブレット記述子を同じ registry に載せている。

代表的なパイプライン(op の繋がり)

flowchart LR
    IMG[image 濃淡画像] -->|"別族: threshold / otsu / watersheds"| REG[region 2値マスク]
    REG -->|count_obj / blob_count / euler_number| N[feature 個数・トポロジ]
    REG -->|circularity / eccentricity / roundness| S[feature 形状スカラ]
    REG -->|moments_region_2nd_invar / moments_region_central_invar| M[feature モーメント不変量]
    IMG -->|"別族: edges_sub_pix"| XLD[contour XLD 輪郭]
    XLD -->|total_length / circularity_xld / moments_xld| SC[feature 輪郭計測]
    IMG -->|intensity / entropy_gray / estimate_noise| G[feature グレー統計]
flowchart LR
    IMG[image 濃淡画像] -->|xcv3_sift_count / xcv2_fast_count / xsk_blob_log| K[feature キーポイント数]
    IMG -->|cv_hough_lines / cv_hough_circles| Hn[feature 直線・円の本数]
    IMG -->|hough_line_trans / hough_circle_trans| ACC[image 投票空間]
    IMG -->|xmh_zernike / xmh_pftas / xwt_detail_energy| D[feature テクスチャ・形状記述子]

呼び出しモデルはこの族でも 2-D パイプラインと同じ「1 入力 + 2 つのつまみ a,b∈[0,1]」: fullseye.apply(x, "op名", a, b)。region op に濃淡画像を渡すと 0.5 で自動 2 値化される(coerce=True)。contour は {'shape':(H,W), 'cs':[ (N,2) 配列 ... ]}、color は HxWx3、volume は Zx(H)x(W) をそのまま渡す。

使い方(op グループ別)

1. 数える・トポロジ(region / contour / volume → feature)

2. 形の丸み・細長さ(region → feature、skimage.regionprops ベース、最大領域について測る)

3. モーメント(region → feature、正規化中心モーメント/Hu 不変量)

4. 輪郭(XLD)計測(contour → feature、最長輪郭について測る)

5. グレー値統計(image → feature)

6. キーポイント・直線・円を数える(image → feature、Hough 2 つのみ → image)

7. テクスチャ・形状記述子・自己相似(image → feature、xmh_selfmatch のみ image)

8. カラー(color → feature)

動く最小例(検証済み gallery2d_features から)

repo 直下で py -3.11 実行可。個数・円形度・輪郭長・チャネル数・平均輝度の“零点を上回る”GT を確認する。

import numpy as np
import fullseye

n = 64
yy, xx = np.mgrid[0:n, 0:n]

# (a) 3 つに分かれた領域(2-D {0,1} float マスク)-> 個数はちょうど 3
three = np.zeros((n, n), np.float64)
for cy, cx in [(16, 16), (16, 48), (48, 32)]:
    three[((yy - cy) ** 2 + (xx - cx) ** 2) < 25] = 1.0
assert fullseye.apply(three, "count_obj") == 3.0
assert fullseye.apply(three, "blob_count") == 3.0

# (b) 円盤は細長い棒より桁違いに「丸い」
disk = (((yy - n // 2) ** 2 + (xx - n // 2) ** 2) < (n * 0.22) ** 2).astype(np.float64)
bar = np.zeros((n, n), np.float64); bar[28:36, 6:58] = 1.0
c_disk = fullseye.apply(disk, "circularity")
c_bar = fullseye.apply(bar, "circularity")
assert c_disk > 0.8 and c_disk > 2.0 * c_bar

# (c) 閉じた円輪郭(XLD dict)-> 総周長 ~= 2*pi*R
R = n * 0.28
t = np.linspace(0, 2 * np.pi, 200, endpoint=False)
circle = {"shape": (n, n),
          "cs": [np.column_stack([n / 2 + R * np.sin(t), n / 2 + R * np.cos(t)])]}
L = fullseye.apply(circle, "total_length")
assert abs(L - 2 * np.pi * R) < 0.02 * (2 * np.pi * R)

# (d) HxWx3 カラー画像はチャネル数ちょうど 3
color = np.stack([disk, 0.7 * disk + 0.1, 1 - disk], -1)
assert fullseye.apply(color, "count_channels") == 3.0

# (e) グレー統計: 明るい定数画像は暗い定数画像より平均が高い
assert fullseye.apply(np.full((n, n), 0.8), "intensity") > \
       fullseye.apply(np.full((n, n), 0.1), "intensity") + 0.5

print("PASS")

数式(必要な op のみ)

円形度(circularity / classify_shape / circularity_xld)。面積 $A$、周長 $P$:

\[C = \min\!\left(1,\ \frac{4\pi A}{P^2}\right)\]

真円度(roundness)と離心率(eccentricity / eccentricity_xld)。長軸 $a$、短軸 $b$:

\[\mathrm{roundness} = \min\!\left(1,\ \frac{4A}{\pi a^2}\right), \qquad e = \sqrt{1 - \left(\tfrac{b}{a}\right)^2}\]

Hu 第 1 不変量(moments_region_2nd_invar)。$\eta_{pq}$ は正規化中心モーメント:

\[\phi_1 = \eta_{20} + \eta_{02}\]

Shannon エントロピー(entropy_gray / xwt_packet_entropy)。ビン確率 $p_i$:

\[H = -\sum_i p_i \log_2 p_i\]

頑健ノイズ推定(estimate_noise)。ラプラシアン $L = \nabla^2 x$ の MAD を正規分布換算し、カーネルのノイズ利得で割って σ に戻す:

\[\hat{\sigma} = \frac{1.4826 \cdot \mathrm{median}\big|\,L - \mathrm{median}(L)\,\big|}{\sqrt{20}}\]

$\sqrt{20}$ は 5 点ラプラシアン $[[0,1,0],[1,-4,1],[0,1,0]]$ のノイズ利得(独立同分布ノイズ $\sigma$ を通すと分散が $(-4)^2 + 4\cdot 1^2 = 20$ 倍になる)。実測(平坦画像 + ガウス雑音 512×512、$\sigma = 0.01 \ldots 0.30$)で $1.4826\,\mathrm{MAD}/\sigma = 4.4501 \ldots 4.4816$、$\sqrt{20} = 4.4721$ と 0.5% 以内で一致する。★2026-09-02 以前は $\sqrt{20}$ で割る代わりに 3 を掛けて おり、σ の単位ですらないうえ σ≳0.08 で 1.0 に飽和していた。

折れ線長(total_length / length_xld)。頂点列 $(x_i, y_i)$:

\[L = \sum_i \sqrt{(x_{i+1}-x_i)^2 + (y_{i+1}-y_i)^2}\]

サンプルデータ

この族のデバッグには 2 値化しやすい合成図形と実写グレー画像が向く。../../SAMPLES.mdshapes / blobs(合成・個数と形状の GT が明快)、coins / cameraskimage.data、キーポイント・Hough・グレー統計の実写確認)を使う(import sample_images; sample_images.load('<name>'))。

参考文献(正典)

(台帳: ../../../REFERENCES.md


© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.