surface_filter — ROUGHNESS 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" 削去后数组一点不剩。

详细使用指南

• surface_roughness 族使用指南

参考(示例数据、文献)

• 示例数据目录(下载 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)

surface_form_remove


*Provenance: roughness.py — ROUGHNESS 算子登记表。本条目由 tools/opdocs.py md 自动生成(请勿手工编辑)。*

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