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() 将这个代码的插值改成多项式拟合方法