CCG 06-04:Jacobian 与畸变热图
本页只解决一个问题
怎样逐面计算奇异值、翻转和 Beltrami 畸变并正确可视化?
本页是原长篇讲义的单概念版本。第一次阅读只追踪本页定义的对象;看见未掌握的前置符号时,先沿链接退回,不要跳过定义硬背结论。
开始前
- 模块前置入口:先修页面
- 本页所属模块:Python 网格参数化实验
- 集中复习版:原长篇参考讲义
11. 逐三角形 Jacobian
原三角形局部边矩阵
UV 边矩阵
映射 Jacobian
def triangle_jacobian(points_3d, uv_triangle):
q = local_triangle_2d(*points_3d)
X = np.column_stack((q[1] - q[0], q[2] - q[0]))
U = np.column_stack((uv_triangle[1] - uv_triangle[0],
uv_triangle[2] - uv_triangle[0]))
return U @ np.linalg.inv(X)
def parameterization_metrics(vertices, faces, uv):
dets, conformal_K, mu_abs, areas_3d = [], [], [], []
for i, j, k in faces:
points = vertices[[i, j, k]]
J = triangle_jacobian(points, uv[[i, j, k]])
sigma = np.linalg.svd(J, compute_uv=False)
det = np.linalg.det(J)
K = np.inf if sigma[1] <= 1e-15 else sigma[0] / sigma[1]
mu = 1.0 if not np.isfinite(K) else (K - 1.0) / (K + 1.0)
area = 0.5 * np.linalg.norm(
np.cross(points[1] - points[0], points[2] - points[0])
)
dets.append(det)
conformal_K.append(K)
mu_abs.append(mu)
areas_3d.append(area)
dets = np.asarray(dets)
conformal_K = np.asarray(conformal_K)
mu_abs = np.asarray(mu_abs)
areas_3d = np.asarray(areas_3d)
finite_K = conformal_K[np.isfinite(conformal_K)]
return {
"flipped": int(np.sum(dets < 0.0)),
"degenerate": int(np.sum(np.abs(dets) <= 1e-14)),
"K_median": float(np.median(finite_K)),
"K_p95": float(np.percentile(finite_K, 95)),
"K_max": float(np.max(finite_K)),
"mu_p95": float(np.percentile(mu_abs, 95)),
"log_area_p95_abs": float(
np.percentile(np.abs(np.log(np.maximum(np.abs(dets), 1e-300))), 95)
),
"face_K": conformal_K,
"face_det": dets,
"face_area": areas_3d,
}11.1 为什么同时看 与
- 表示两个方向缩放相同,但可能是统一放大、缩小或反射;
- 给面积缩放和方向;
- 反射满足 但;
- 与 等价,只是压缩到。
12. 可视化网格与误差热图
def plot_parameterizations(faces, results):
fig, axes = plt.subplots(
len(results), 2, figsize=(11, 4 * len(results)), constrained_layout=True
)
if len(results) == 1:
axes = np.asarray([axes])
for row, (name, uv, metrics, diagnostics) in enumerate(results):
tri = mtri.Triangulation(uv[:, 0], uv[:, 1], faces)
axes[row, 0].triplot(tri, color="black", linewidth=0.35)
axes[row, 0].set_aspect("equal")
axes[row, 0].set_title(
f"{name}: flipped={metrics['flipped']}, "
f"residual={diagnostics['linear_residual_inf']:.2e}"
)
color = np.log(np.maximum(metrics["face_K"], 1.0))
image = axes[row, 1].tripcolor(
tri, facecolors=color, shading="flat", cmap="magma"
)
axes[row, 1].triplot(tri, color="white", alpha=0.18, linewidth=0.2)
axes[row, 1].set_aspect("equal")
axes[row, 1].set_title("log conformal distortion log(K)")
fig.colorbar(image, ax=axes[row, 1])
plt.show()读完必须能回答
- 不看公式,用自己的话回答开头的核心问题。
- 指出本页最重要公式中每个符号的类型:标量、向量、矩阵、映射还是集合。
- 找出定理成立所需的假设,并举一个删除某条假设后可能失败的例子。
- 对最小例子手算一遍;若本页含代码,再比较手算与程序输出。
前后课程
许可协议:CC BY
作者:Davids
本文链接:https://hustjjd.github.io/ccg/06-04-lesson/
更新于:2026年10月12日