pyvista 3D Smoothing

PyVista 3D 模型平滑技巧

Preface:

vtk style of pipeline programming is often tedius and obscure. What makes it worse is that most authors tend to throw at you a huge junk of code contains mostly boilerplate code,  with no explanation on why certain filter is used.

Here I would recommend this vtk artile, showing how vtk articles should be written.

VTK introduction

Why Smoothing:

Point cloud data contains noises, which makes recontructed surface to be coarse and bumpy. Smoothing is often the first step to obtain a better model to work with.

Here I quote from VTK User Guide:

Polygonal meshes often contain noise or excessive roughness that affect the quality of the rendered image.

For example, isosurfacing low resolution data can sho

import numpy as np import pandas as pd import pyvista as pv import os from scipy.interpolate import griddata from scipy.ndimage import gaussian_filter # 读取CSV文件(只包含坐标数据) def load_data(file_path): """ 从CSV文件加载坐标数据 格式:x(第一列), y(第二列), z(第三列) """ print(f"正在加载文件: {os.path.abspath(file_path)}") if not os.path.exists(file_path): raise FileNotFoundError(f"数据文件 {file_path} 未找到!") # 加载只有三列的数据 df = pd.read_csv(file_path, header=None, names=['x', 'y', 'z']) print(f"数据加载成功,共 {len(df)} 个点") print(f"坐标范围: x({df.x.min():.2f}~{df.x.max():.2f}), " f"y({df.y.min():.2f}~{df.y.max():.2f}), " f"z({df.z.min():.2f}~{df.z.max():.2f})") return df[['x', 'y', 'z']].values # 创建插值网格 def create_interpolation_grid(points, resolution=500): """ 根据点云数据创建插值网格 """ # 计算点云边界 min_coords = np.min(points, axis=0) max_coords = np.max(points, axis=0) # 创建网格 x = np.linspace(min_coords[0], max_coords[0], resolution) y = np.linspace(min_coords[1], max_coords[1], resolution) z = np.linspace(min_coords[2], max_coords[2], resolution) # 生成网格点 X, Y, Z = np.meshgrid(x, y, z) grid_points = np.vstack((X.ravel(), Y.ravel(), Z.ravel())).T return grid_points, (X, Y, Z), (x, y, z) # 创建虚拟标量场(修改为使用y坐标) def create_virtual_scalar_field(points): """ 基于y坐标创建虚拟标量场(仅用于曲面重建) """ # 使用y坐标作为基础值 return points[:, 1] # 修改这里:从points[:, 2]改为points[:, 1] # 插值函数(添加有效点比例计算) def interpolate_data(points, values, grid_points, method='linear', sigma=3): """ 使用指定方法进行插值,并计算有效点比例 """ print(f"开始 {method} 插值,网格点数量: {len(grid_points)}...") # 执行插值(不填充NaN值) interpolated_values = griddata( points, values, grid_points, method=method ) # 计算有效插值点的比例(非NaN值) valid_mask = ~np.isnan(interpolated_values) valid_count = np.sum(valid_mask) total_count = len(interpolated_values) valid_ratio = valid_count / total_count * 100 print(f"{method} 插值完成!") print(f"有效插值点比例: {valid_ratio:.2f}% ({valid_count}/{total_count})") # 将NaN值替换为0 interpolated_values[~valid_mask] = 0 # 应用高斯平滑 if sigma > 0: print(f"应用高斯平滑 (sigma={sigma})...") # 重塑为3D数组进行平滑 dims = [len(np.unique(grid_points[:, i])) for i in range(3)] values_3d = interpolated_values.reshape(dims) smoothed_values = gaussian_filter(values_3d, sigma=sigma, mode='reflect') interpolated_values = smoothed_values.ravel() print("高斯平滑完成!") return interpolated_values, valid_ratio # 使用PyVista可视化曲面(无颜色) def visualize_with_pyvista(grid_points, interpolated_values, valid_ratio, original_points=None): """ 使用PyVista创建三维曲面图(无颜色),并显示有效点比例 """ # 创建点云对象 grid = pv.StructuredGrid() grid.points = grid_points grid.dimensions = [len(np.unique(grid_points[:, i])) for i in range(3)] # 添加虚拟标量(必须添加标量才能创建等值面) grid["virtual_scalar"] = interpolated_values # 创建绘图对象 plotter = pv.Plotter(window_size=(1200, 800)) plotter.set_background("white") # 添加标题 plotter.add_title("三维曲面云图 (基于Y坐标重建)", font_size=20) # 更新标题说明 # 创建等值面(使用虚拟标量) contours = grid.contour( scalars="virtual_scalar", isosurfaces=50, # 增加等值面数量 rng=[np.min(interpolated_values) * 0.9, np.max(interpolated_values) * 1.1]) # 应用网格平滑 smoothed_contours = contours.smooth( n_iter=300, # 增加迭代次数 relaxation_factor=0.05, # 减小松弛因子 boundary_smoothing=True # 启用边界平滑 ) # 添加曲面(使用单一灰色) plotter.add_mesh( smoothed_contours, color="lightgray", # 使用单一颜色 opacity=0.9, show_scalar_bar=False # 不显示颜色条 ) # 添加原始数据点(可选) if original_points is not None: point_cloud = pv.PolyData(original_points) plotter.add_mesh( point_cloud, color="darkblue", point_size=3.0, render_points_as_spheres=True, opacity=0.7 ) # 添加坐标轴 plotter.add_axes(line_width=5, labels_off=False) # 添加信息框(包含有效点比例) info_text = ( f"数据点数量: {len(original_points)}\n" f"网格分辨率: {grid.dimensions}\n" f"有效插值点比例: {valid_ratio:.2f}%\n" f"标量场: Y坐标" # 添加标量场说明 ) plotter.add_text( info_text, position='lower_right', font_size=12, color='black' ) # 设置相机位置 plotter.camera_position = 'iso' # 保存截图 screenshot_file = "3d_surface_cloud_y_scalar.png" # 更新文件名 plotter.show(screenshot=screenshot_file) print(f"截图已保存为: {screenshot_file}") # 保存交互式HTML html_file = "interactive_3d_surface_y_scalar.html" # 更新文件名 plotter.export_html(html_file) print(f"交互式HTML已保存为: {html_file}") return plotter # 主函数 def main(): # 文件路径 - 替换为您的CSV文件路径 csv_file = "danmian.csv" # 示例文件名 # 加载数据(只包含坐标) points = load_data(csv_file) # 创建虚拟标量场(基于y坐标) scalar_values = create_virtual_scalar_field(points) # 创建插值网格 grid_points, grid_shape, grid_axes = create_interpolation_grid(points, resolution=100) # 进行插值(获取插值结果和有效点比例) interpolated_values, valid_ratio = interpolate_data( points, scalar_values, grid_points, method='linear', sigma=1.0 ) # 可视化结果(使用单一颜色) plotter = visualize_with_pyvista( grid_points, interpolated_values, valid_ratio, # 传递有效点比例 original_points=points ) # 关闭绘图以释放内存 plotter.close() if __name__ == "__main__": main() 将这个代码的插值改成多项式拟合方法
08-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值