fly_expansion_readout — FLYVISION looming op

• 데이터 종류: matrix × table → table

• 호출: import fullseye as fs; fs.ledger.fly_expansion_readout(flow, lattice, axis=None, weights=None)(구현을 직접 호출하려면 import flyvision; flyvision.fly_expansion_readout(flow, lattice, axis=None, weights=None), 원장에서 가져오려면 opsflyvision.get("fly_expansion_readout"))

사용법

눈 전체의 흐름에서 충돌까지의 시간을 읽음 —— 조리개 효과는 정확히 2배.

> 아래 상세 설명은 원문입니다 —— 요약과 제목은 번역되어 있습니다.

A fronto-parallel surface approached at speed v from distance d moves the line of sight at polar angle theta outward at sin theta cos theta / tau with tau = d/v. This op projects the measured flow onto the outward radial direction and fits that one number, 1/tau, by weighted least

squares::

1/tau = sum w f_r sin cos / sum w (sin cos)^2

and, independently, fits a linear field f = A x + b on the gnomonic plane and reads the divergence tr A, which sceneflow converts the same way (ttc = 2/div).

The reason to have both: a correlation-type detector only sees the motion component across a contrast edge. Over vertical stripes every edge is vertical, so the elevation component of the flow is lost (the aperture problem), the radial projection keeps on average half the expansion, and both readouts return 2 tau — the surface looks twice as far as it is. A checkerboard has edges in both directions and returns tau. That is the identity How et al. (2020) argued from, written as a number.

flow: (n, 2) azimuth/elevation flow per ommatidium (radians per

second), the return of fly_flow_from_directions.

lattice: the eye it was measured on (hexagonal or Vogel).

axis: the direction of travel = focus of expansion, body coordinates;

None = the lattice's optical axis.

weights: None or (n,) non-negative weights (e.g. 0 on the rim, where

fly_flow_from_directions reports nothing).

Returns a dict {"tau_s", "rate_1_s", "tau_div_s", "divergence_1_s", "aperture_ratio", "residual_rms", "n_ommatidia"} — the radial-fit time-to-contact and its rate, the divergence-fit time-to-contact and the divergence, the ratio of the smaller to the larger diagonal of A (1 for isotropic expansion, 0 under a pure aperture effect), the rms of the radial residual and how many ommatidia voted. A non-expanding field (rate <= 0) returns NaN for the time-to-contact — a documented non-finite, as in fly_tau_from_expansion: a receding surface has no time-to-contact.

Ground truth (pinned in the tests): the exact plane flow returns tau_s == tau and tau_div_s == tau to 1e-9 (the divergence is fitted on gnomonic velocities, where a plane approach is exactly linear); the same flow with its elevation component removed returns 2 tau from both readouts within 1% on a 10-degree field (aperture_ratio 0) — a hexagonal lattice is 6-fold symmetric, so sum cos^2 phi = sum sin^2 phi over it, and the residual is the sphere's departure from that plane.

Raises ValueError: a *flow* that is not (n, 2) for this lattice (an empty *flow* is refused), non-finite entries, a malformed *lattice* / *axis* / *weights*, all-zero weights, and fewer than 6 voting ommatidia.

자세한 사용 가이드

• fly_vision 패밀리 가이드

참고(샘플 데이터·문헌)

• 샘플 데이터 카탈로그(DL URL / 라이선스) —— 2-D 는 skimage.data(BSD/public)+ 합성, 3-D 는 실데이터 소스(Stanford/PDS 등)의 DL URL.

• 연산자의 내력·참고문헌 —— 이 연산자 족의 바탕이 된 연구/기법의 출처.

• 알고리즘의 정전(저자·연도)과 용도는 위의 패밀리 사용 가이드에 적혀 있습니다.

실행 가능한 예제(이 연산자를 실제로 호출하는 검증된 샘플)

• poc_zebra_stripes_fly_eye — py -3.11 examples/poc_zebra_stripes_fly_eye.py

타입이 이어지는 다음 연산자(table 를 입력으로 받는 것)

fly_t4t5_field · fly_flow_from_directions · fly_matched_filter · fly_egomotion_from_flow · fly_eye_merge · fly_view_plane_texture · fly_hex_resample · lattice_moire_peak

같은 카테고리(looming)

fly_lgmd_eta · fly_tau_from_expansion


*Provenance: flyvision.py — FLYVISION 연산자 레지스트리. 이 op 노트는 tools/opdocs.py md 가 자동 생성합니다(직접 편집하지 마세요).*

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