solid op• 数据种类:image2d × image2d → image2d
• 调用: import fullseye as fs; fs.ledger.strain_from_displacement(u: 'Any', v: 'Any', window: 'int', method: 'str', spacing: 'float' = 1.0) -> 'tuple[np.ndarray, np.ndarray, np.ndarray]'(要直接调用实现,import dic; dic.strain_from_displacement(u: 'Any', v: 'Any', window: 'int', method: 'str', spacing: 'float' = 1.0) -> 'tuple[np.ndarray, np.ndarray, np.ndarray]';从台账取用则 opspiv.get("strain_from_displacement"))
• 经台账调用的返回值: fullseye.ledger.strain_from_displacement(...) 只返回声明的 out 类型 image2d 的值(底层函数还会返回辅助信息)。需要被丢弃的部分时,使用 fullseye.ledger.strain_from_displacement.raw(...),或直接调用 dic.strain_from_displacement。
由位移场求应变场。返回 (exx, eyy, exy)。
参数(window 和 method 没有默认值。理由见下)
u x 方向(列)的位移场 [px]。2 维。
v y 方向(行)的位移场 [px]。与 u 同形。
window 局部最小二乘窗口的边长。单位是网格节点数(不是像素)。
奇数。
method "infinitesimal" 或 "green"。其他抛异常。
spacing 节点间隔 [px]。全像素的稠密场为 1.0(默认)。
若是 piv_cross_correlate 的网格则为 info["step"]。
★ 从 pivops 传入时 —— 分量顺序弄错会悄悄出错 flow2d 是 (dy, dx) 的顺序。正确写法::
flow, info = piv_cross_correlate(a, b, window=32, overlap=0.75)
exx, eyy, exy = strain_from_displacement(
flow[1], flow[0], 9, "green", spacing=info["step"])
把 flow[0] 传给 u 会使 x 和 y 互换,不报异常而返回看似合理的另一个答案。只有直接传入 3 维数组时才能附带修正方法加以拒绝,因此对此做了检查。
定义用 window x window 的平面拟合求出 ux = ∂u/∂x 等,
• "infinitesimal"(微小应变、工程应变) exx = ux, eyy = vy, exy = ½(uy + vx)
• "green"(Green-Lagrange) exx = ux + ½(ux² + vx²), eyy = vy + ½(uy² + vy²), exy = ½(uy + vx + ux·uy + vx·vy)
★★ 为什么 method 不设默认值 —— 刚体转动造成的假象设试样只是转动了 θ,材料连 1 微米也没有伸长。真实应变为 0。把严格的刚体转动位移场 u = (cosθ-1)x - sinθ·y, v = sinθ·x + (cosθ-1)y 不经过图像直接输入的实测(单位 µε = 1e-6):
θ [度] cosθ-1 infinitesimal piv_velocity_gradient green
0.5 -38.1 -38.1 -38.1 5.3e-14
1.0 -152.3 -152.3 -152.3 9.3e-14
2.0 -609.2 -609.2 -609.2 2.0e-13
5.0 -3805.3 -3805.3 -3805.3 6.5e-13
2 度时 -609 µε,是钢的屈服应变(约 2000 µε)的 3 成。 Green-Lagrange 中 exx = (cosθ-1) + ½((cosθ-1)² + sin²θ) = 0 在代数上严格成立,因此降到 1e-13。现有的 piv_velocity_gradient 返回与微小应变相同的值(= 带着同样的假象),piv_strain_rate 在 2 度时返回 +1218 µε (2|cosθ-1|) —— 对于流体的线性化转动 u=-ωy, v=ωx,这个量为 0,但在有限转动下不为 0。
反过来,在材料试验报告、标准、与应变片的对照中,微小应变是标准,若默默返回 Green-Lagrange,数字就对不上。哪个正确会随场景而反转。所以让使用者选择。
★ 但并不是“用 green 就安全” —— 估计误差会原样通过 Green 的修正项 ½(ux²+vx²) 由估计的梯度构成,因此梯度估计不好,修正也不好。实测(解析散斑 256²、刚体转动、MARGIN 40 内侧的平均 ± 离散,单位 µε):
θ [度] cosθ-1 | piv+LS w=9 微小 green | lk+LS w=31 微小 green
2.0 -609.2 | -42.9 ± 428 564.7 ± 429 | -698.8 ± 2122 -84.4 ± 2132
5.0 -3805.3 | 364.9 ± 9532 3843.4 ± 9638 | -1372.9 ±22909 2759.6 ±25685
lk 的 2 度与教科书一致(-699 ≒ -609 的假象 → 用 green 减到 -84)。但 piv 的 2 度连微小应变都只返回 -42.9 —— 因为转动的子区使相关变钝,梯度估计本身在 ±500 µε 范围内晃动,在此之上再加 +609 µε 的 Green 修正,反而变成 +565 µε。5 度以上时两种估计器的离散都超过 1e4 µε,平均值没有意义。 关于定义的讨论,只有在梯度能以那种精度测出时才起作用。
★ window 就是空间分辨率本身从同一个 piv 位移场读回均匀应变的实测(µε):
真值 piv_velocity_gradient w=3 w=5 w=9
100 100.4 ± 21.8 100.4 ± 16.0 100.3 ± 6.4 100.3 ± 1.7
500 501.8 ± 107.2 502.0 ± 78.9 501.4 ± 31.3 501.2 ± 8.6
2000 1996.3 ± 342.0 1996.6 ± 259.5 1994.8 ± 99.3 1995.6 ± 25.9
20000 19768.8 ± 2909.9 19768.9 ± 2210.5 19742.7 ± 790.9 19754.1 ± 209.6
平均全都相同。只有离散随 w 缩小,最多缩小到 13.9 分之一。 代价是 w=9 把 9 个节点(step=8 时为 72 px)视为平坦,因此在缺口尖端这类有曲率的应变场中会低估峰值。对称窗口的最小二乘对 1 次应变场严格返回,但对弯曲的场会变钝。若设默认值,数字就会建立在你不记得选过的权衡之上。
★ NaN 的处理 —— 不用 0 填补 u 或 v 中有 NaN 时,包含该点的 window x window 拟合无法定义。含 NaN 的窗口的输出全部设为 NaN (把 u/v 两者的缺测合并成 1 个掩模,应用于 3 个分量)。若把 NaN 视为 0,测不到的点会作为“位移 0 的点”影响拟合,在周围造出看似真实的虚假应变梯度。
fail-closed
• u / v 不是 2 维、形状不同、小于 4x4。
• 把 (2, h, w) 的 flow2d 整个传给了 u(附带修正方法拒绝)。
• window 为偶数、小于 3、比场还大。
• spacing 非正、非有限。
• method 不是 "infinitesimal" / "green"。
• 省略 window 和 method 的调用会得到 TypeError (因为没有设默认值,直接在 Python 的参数机制中失败)。
• 示例数据目录(下载 URL / 许可证) —— 2-D 用 skimage.data(BSD/公有领域)加合成图,3-D 给出真实数据源(Stanford/PDS 等)的下载 URL。
• 算子来历与参考文献 —— 该算子族所依据的研究/方法出处。
• 算法的正典(作者、年份)与用途见上面的族使用指南。
• poc_dic_strain — py -3.11 examples/poc_dic_strain.py
image2d 作为输入)piv_cross_correlate · piv_multipass · piv_deform_pass · correlation_quality · speckle_quality
solid)correlation_quality · speckle_quality
*Provenance: dic.py — PIV 算子登记表。本条目由 tools/opdocs.py md 自动生成(请勿手工编辑)。*
© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.