prepare op• 数据种类:depth → depth
• 调用: import fullseye as fs; fs.ledger.surface_filter(z, dx, lambda_c=None, lambda_s=None, kind='gaussian', end_effect='reject', dy=None)(要直接调用实现,import roughness; roughness.surface_filter(z, dx, lambda_c=None, lambda_s=None, kind='gaussian', end_effect='reject', dy=None);从台账取用则 opsroughness.get("surface_filter"))
• 经台账调用的返回值: fullseye.ledger.surface_filter(...) 只返回声明的 out 类型 depth 的值(底层函数还会返回辅助信息)。需要被丢弃的部分时,使用 fullseye.ledger.surface_filter.raw(...),或直接调用 roughness.surface_filter。
• 底层返回: (roughness, waviness)
将高度场分解为粗糙度和波纹度(ISO 16610-21 的高斯滤波器)。
返回值为 (roughness, waviness)。roughness 是比 λc 短的成分,waviness 是长的成分;只要不是 end_effect="reject",roughness + waviness 就与输入(施加 λs 之后的原始形状)严格一致。
参数
z 高度场 z[i, j](行 = y,列 = x)。
dx, dy 采样间隔。dy=None 为正方形像素。
lambda_c 长波长侧截止(粗糙度 / 波纹度的分界)。为 None 时不分离
(waviness 为全零数组)。
lambda_s 短波长侧截止(去除噪声的 S 滤波器)。None 时无效。
kind 仅 "gaussian"。传入其他值时不会悄悄替代,而是抛出异常。
end_effect "reject"(默认) / "mirror" / "wrap"。见下文。
dy 行方向的采样间隔(None = dx)。
★ 端部处理(end_effect)—— 这正是编写此 op 的理由
卷积在端部需要核半径 λc/2 范围内“不存在之处的数据”。
标准(ISO 16610-28)以评定区域两端各削去 λc/2 为前提。
• "reject"(默认)—— 舍弃两端各 ceil(λc/2/pitch) 个样本。输出是比输入小的数组。被舍弃的区域“没有测量”,所以这是唯一不说谎的选项。
• "mirror" —— 以镜像延拓并返回相同形状。假定面在端部是偶函数。
• "wrap" —— 循环卷积(与 FFT 相同)。假定左端的延续就是右端。
实测。真值是对 704x704 的面先滤波、再切出中央 512x512
的结果(在端部外侧有真实数据的状态下计算的答案)。dx=1,λc=80,
端部带 = 外周 40 个样本,该处真值的 rms 为 0.1932。
面的状态 end_effect 端部带的 rms 误差 中央部的 rms 误差
有倾斜 wrap 4.3883 (2272 %) 0.0e+00 (0.000 %)
有倾斜 mirror 0.1765 ( 91 %) 0.0e+00 (0.000 %)
已去倾斜 wrap 0.0111 ( 5.7 %) 4.4e-15 (0.000 %)
已去倾斜 mirror 0.0115 ( 5.9 %) 4.4e-15 (0.000 %)
(任意) reject —— 不返回 —— 0.0e+00 (0.000 %)
可以读出 4 点:
1. 端部处理只在端部起作用。 中央部无论哪种都与真值严格一致(核够不到端部,这是理所当然的,但做了确认)。
2. 最糟的组合是“保留倾斜直接 wrap” —— 端部误差达到真值本身的 23 倍。因为假定左端的延续就是右端,在高度不同的 2 条边的接缝处会出现台阶。
3. 只要去掉倾斜,wrap 与 mirror 就没有差别(5.7 % 对 5.9 %,wrap 略好)。正确的说法不是“循环卷积总是不好”,而是 “不去倾斜就使用才不好”。
4. reject 的代价是面积。512x512、λc=80 时舍弃 28.8 % (剩下 432x432)。舍弃比例按 1 - (1 - λc/L)² 增长,因此 λc 超过评定长度的 1/4 时会失去近一半。
★ 传递率是否符合标准(实测,λc=80,dx=1,用投影测量整数周期的正弦)
λ 波纹度侧 ISO 标准值 差
16 0.000806 0.000000 +8.1e-04
32 0.017206 0.013139 +4.1e-03
40 0.058676 0.062500 -3.8e-03
64 0.342826 0.338564 +4.3e-03
80 0.509549 0.500000 +9.6e-03 ← 最大
128 0.772150 0.762799 +9.4e-03
256 0.937944 0.934550 +3.4e-03
在截止波长本身处不是 0.5000 而是 0.5095(相对 +1.9 %)。原因是
标准规定的截断 ±λc/2(= 2.67 σ),使尾部的 0.8 % 被丢掉。
若把截断放宽到 4 σ(±0.75 λc),最大误差降到 9e-05
(实测),但 reject 舍弃的带会变成 1.5 倍。选择了遵循标准、并写明偏差的做法。粗糙度与波纹度之和始终与输入严格一致
(上表中 roughness + waviness = 1.000000),所以只是分配的分界
偏移 1.9 %,能量既不会消失也不会凭空出现。
fail-closed(失败即拒绝)
• kind 不是 "gaussian" / end_effect 不是已知的 3 种之一。
• lambda_c 与 lambda_s 都是 None(什么也不做的调用)。
• 截止低于 Nyquist 波长 2*pitch,或超过评定长度。
• lambda_s >= lambda_c(频带为空)。
• "reject" 削去后数组一点不剩。
• 示例数据目录(下载 URL / 许可证) —— 2-D 用 skimage.data(BSD/公有领域)加合成图,3-D 给出真实数据源(Stanford/PDS 等)的下载 URL。
• 算子来历与参考文献 —— 该算子族所依据的研究/方法出处。
• 算法的正典(作者、年份)与用途见上面的族使用指南。
• poc_surface_roughness — py -3.11 examples/poc_surface_roughness.py
depth 作为输入)surface_form_remove · surface_params · surface_psd
prepare)*Provenance: roughness.py — ROUGHNESS 算子登记表。本条目由 tools/opdocs.py md 自动生成(请勿手工编辑)。*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.