Copyright (c) 2026 Kazufumi Furuse.
OpenVX 1.3.1(Khronos の視覚処理 API の規格)は、視覚関数ごとに何を受け取り何を返すかを番号つきの規範文 [REQ-NNNN] で決めています。
2026-09-25 に 61 本を本文まで読んで照合したら、17 本は「Fullseye にも似た op はあるが、入口か出口の形が違う」でした。たとえば sobel_mag は
大きさを [0, 1] に正規化して返すので、規格の順序 —— Sobel で gx と gy を出し、別々に大きさと位相へ —— では使えません。
この族は、その素の口を規範文どおりに開けます(合成 op は消しません)。第 1 陣 6 op と第 2 陣 4 op:
vx_sobel3x3(REQ-0415 の核で gx・gy を別々に、境界は必須の引数)/ vx_magnitude(REQ-0270: uint16(sqrt(x²+y²) + 0.5)、32767 で飽和)/
vx_phase(REQ-0364: 0 ≤ ϕ < 2π を 0〜255 へ。★規格は丸めを決めていないので mapping="floor"|"round" を呼び手が選ぶ)。vx_table_lookup(REQ-0421: 任意の表を引く、S16 は offset を足して引く、表の外は止める)/ vx_histogram(REQ-0230: (I − offset) × numBins / range の升)。suppress(1) — vx_nonmax_suppression(REQ-0337: 窓の中で前の隣には ≥、後ろの隣には > で勝てば残る。マスクの画素は比べない REQ-0336、抑制した S16 は INT16_MIN REQ-0335)。
vx_warp_affine(REQ-0498)/ vx_warp_perspective(REQ-0508)/ vx_remap(REQ-0392): どれも逆写像(出力の画素がどこから来るか)。標本は画素の中心、補間は最近傍か双線形、境界は UNDEFINED か CONSTANT だけ(REQ-0506)。★規格の C の宣言は行列を転置した並び(mat[3][2])で持つので、そのまま渡すと形が (3, 2) になって止まります —— 渡すのは数学の並びの 2×3。vx_nonlinear_filter(REQ-0325〜0330): 任意の形のマスクで中央値・最小(収縮)・最大(膨張)。マスクの画素数が偶数のときの中央値は規格に無いので上側(n // 2 番目)を取ります。画像は U8 / S16 の dtype を規格どおりに受け、合わなければ止めます(黙って丸めません)。
flowchart LR
U8[U8 画像] --> S[vx_sobel3x3]
S -->|gx| M[vx_magnitude]
S -->|gy| M
S -->|gx| P[vx_phase]
S -->|gy| P
M --> N[vx_nonmax_suppression]
U8 --> H[vx_histogram]
U8 --> L[vx_table_lookup]
import numpy as np
import vxcore as V
img = np.zeros((7, 9), np.uint8)
img[:, 4:] = 100 # 縦の段差(左 0 → 右 100)
g = V.vx_sobel3x3(img, border="replicate") # REQ-0415 の核、gx と gy を別々に
print(g["gx"][3, 2:7].tolist(), int(g["gy"].max())) # [0, 400, 400, 0, 0] 0
mag = V.vx_magnitude(g["gx"], g["gy"]) # REQ-0270: sqrt + 0.5 を切り捨て、32767 で飽和
print(mag[3, 3:5].tolist(), V.vx_phase(g["gx"], g["gy"], mapping="floor")[3, 3]) # [400, 400] 0(右向きの勾配 = 位相 0)
peaks = V.vx_nonmax_suppression(mag, window=3) # REQ-0337: 前の隣に ≥、後ろの隣に >
print(int((peaks > 0).sum())) # 1 —— 幅 2・長さ 7 の平らな稜線が右下の 1 画素に潰れる
print(V.vx_histogram(img, num_bins=4, offset=0, range_=256)[:, 1].tolist()) # [28.0, 35.0, 0.0, 0.0] —— REQ-0230 の升
hx_nonmax_dir)を使います。floor と round は 2π の直前で 255 と 0 に分かれます。他の実装と突き合わせるときは、どちらかを確かめてから。map_coordinates(mode="constant") は標本点が格子の外に出ると丸ごと定数にするので、縁の 1 画素で食い違います。同じ約束は mode="grid-constant"。試験(tests/test_vxcore.py)は、規範文の式を画素ごとの素朴なループで写した別の実装と突き合わせます: Sobel は scipy の相関、大きさは REQ-0270 の C の式、
位相は math.atan2、ヒストグラムは REQ-0230 の式、非極大の抑制は 3.39 節の 8 つの不等式。≥ と > を入れ替えた壊れた版で 3 件落ちることも確かめてあります。