watervision op• 数据种类:无 → table(仅由参数决定的算子 —— 不接受图像或数据输入)
• 调用: import fullseye as fs; fs.ledger.bottle_image(radius_mm, wall_mm, height_mm, fill_fraction, n_glass, n_liquid, meniscus_mm=0.0, bubbles=None, camera_distance_mm=500.0, pixel_pitch_um=20.0, size=None, light='backlight', n_air=1.0) -> 'dict'(要直接调用实现,import watervision; watervision.bottle_image(radius_mm, wall_mm, height_mm, fill_fraction, n_glass, n_liquid, meniscus_mm=0.0, bubbles=None, camera_distance_mm=500.0, pixel_pitch_um=20.0, size=None, light='backlight', n_air=1.0) -> 'dict';从台账取用则 opsoptics.get("bottle_image"))
部分装有液体的圆柱形瓶子的侧视图,逐行进行光线追迹 -> 字典。
> 以下的详细说明为原文 —— 摘要与标题已翻译。
The bottle (outer radius radius_mm, glass wall wall_mm, height height_mm, axis vertical, base at z = 0) is looked at by a pinhole camera camera_distance_mm from the axis. Every image row is the horizontal cross-section at its height: the ray of a pixel is traced through the circles of the section (outer wall, inner wall, the edge of the liquid in a meniscus row, bubbles) with the vector form of Snell's law and the unpolarised Fresnel transmittance at each interface. Total internal reflection reflects the ray (at most 24 interface events are followed; a ray still wandering then is counted in unresolved_rays and left dark). The liquid (n_liquid) fills the bottle up to fill_fraction * height_mm; meniscus_mm lets it climb the wall by that much as (rho / r_inner)^6. bubbles is a list of (x_mm, z_mm, r_mm) (or with a fourth y_mm along the viewing axis; default 0): air spheres in the liquid, drawn as their circle in each row they cross. pixel_pitch_um is the sampling pitch in the plane of the axis, so 1000 / pixel_pitch_um pixels are 1 mm there; size is (rows, cols) (default: the rows exactly cover the height, the width is 1.15 times the diameter); row j is at z = height - (j + 0.5) pitch.
light="backlight": a diffuse panel of radiance 1 behind the bottle that emits only within +-8 degrees of the viewing axis (soft edge 1 degree): a pixel is lit when its ray leaves the bottle inside that cone, times the product of the Fresnel transmittances. The empty bottle bends rays little and is lit to near the edges; the filled one is a cylindrical lens, so only a central band (half width alpha / (1/f - 1/dc) with the paraxial focal length f of watermedia.cylinder_lens_caustic) is lit and the flanks go dark; an air bubble in the liquid is a diverging lens and shows as a dark ring. light="frontlight": a matt wall of radiance 0.8 behind, a dim dome plus a soft box at 35 degrees, and the first Fresnel reflection of the outer wall (R times the environment radiance), which gives the glint and the bright rim at grazing view. Interior reflections other than total internal reflection are not followed, the rows are independent (no vertical refraction at the shoulder or the base), and rows without bubbles or meniscus are computed once per kind (the empty and the full section), so rows of equal geometry are bit identical.
The table has image (rows, cols; no pixel exceeds 1), x_mm, z_mm, pixel_pitch_mm, magnification_px_per_mm, fill_row_from_top (the first liquid row), liquid_rows (rows with liquid; about fill_fraction height / pitch), fill_z_mm, paraxial_efl_mm and band_half_width_mm_paraxial (the predicted half width of the lit band of the filled bottle, inf when the lens does not converge within the camera distance), central_transmittance_empty / ..._filled (the product of the normal-incidence Fresnel transmittances of the four interfaces on the axis), unresolved_rays and the inputs echoed. n_glass <= 1, n_liquid <= 1, n_air < 1 or not below both, a fill outside [0, 1], a wall not thinner than the radius, a meniscus that does not fit and a bubble outside the liquid are refused.
optics 的每个算子都先校验输入再计算(不让任何东西无声通过):
• 单位写进参数名 —— _mm / _um / _deg / _mrad。把 mm 和 µm 弄混不会崩溃,而是给出「看着合理却是错的答案」,所以用命名来防。这里绝不从数值大小去猜单位。
• 字符串一律 ValueError —— float('50') 会成功,于是未解析的配置值会被当成长度混进来(实测:thin_lens('50', '200') 曾返回看着合理的 66.667 mm)。bool 也按 True == 1 的隐式提升拒绝。
• complex / masked array 一律 ValueError(仅接受实数槽位;拒绝无声丢弃虚部或剥掉掩码)。所有输入中的 NaN/Inf 一律 ValueError。
• 逐项点名拒绝除零及其近亲:焦距 0、曲率半径 0、折射率 <= 0、全不透明光阑(全为 0,归一化变成 0/0)、总和 <= 0 的 PSF、S0 = 0 的 Stokes 矢量、物体位于前焦点(像在无穷远)。
• 只有两个算子会返回非有限值,而且都写进了契约:depth_of_field 在超焦距以外返回 far_mm = inf(这正是超焦距的定义),gaussian_beam 在束腰处返回 wavefront_radius_mm = inf(平面波前的曲率半径)。两者都同时返回一个有限的搭档(far_is_infinite / curvature_per_mm)。除此之外的无声 NaN/Inf 都在内部检出并 ValueError ——「float64 溢出了」和「答案是无穷大」是两种不同的主张,不能拿后者的脸去交付前者。
• 尺寸上限:生成网格受 optics.MAX_GRID(4096)限制,传入的场/PSF/光阑受 optics.MAX_FIELD_ELEMENTS(2^24),ABCD 元件序列受 optics.MAX_SYSTEM_ELEMENTS(1024),Zernike 受 MAX_ZERNIKE_TERMS(512)/ MAX_ZERNIKE_ORDER(40)/ MAX_ZERNIKE_BASIS(2^25)。以 fail-closed 堵住「小参数引发巨大内部分配」的路径(实测:n_max=40 × 4096² 需要 108 GB)。
• 物理上不可能的状态同样拒绝:偏振度 > 1 的 Stokes 矢量、负透过率、负强度、n-|m| 为奇数等非法 Zernike 指标。
• 示例数据目录(下载 URL / 许可证) —— 2-D 用 skimage.data(BSD/公有领域)加合成图,3-D 给出真实数据源(Stanford/PDS 等)的下载 URL。
• 算子来历与参考文献 —— 该算子族所依据的研究/方法出处。
• 算法的正典(作者、年份)与用途见上面的族使用指南。
• poc_water_inspection_images — py -3.11 examples/poc_water_inspection_images.py
table 作为输入)abcd_matrix · wavefront_stats · sfr_from_edge · paraxial_trace · seidel_coefficients · spot_stats · tolerance_analysis · wavefront_from_opd
watervision)caustic_irradiance · fill_level_from_image · wet_surface_appearance · wet_dry_inspection_pair · underwater_inspection_image · caustic_floor_segmentation
*Provenance: watervision.py — OPTICS 算子登记表。本条目由 tools/opdocs.py md 自动生成(请勿手工编辑)。*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.