如何基于三维轨迹集生成2D及3D热力图?
解决方案:基于3D轨迹生成热力图(统计跨网格轨迹数)
嘿,我来给你梳理一下如何实现这个需求——从独立文件的3D轨迹出发,生成统计穿过每个网格的不同轨迹数量的2D(XY/XZ)和3D热力图,顺便把你提到的额外矩阵用法讲清楚~
核心思路先明确
我们要统计的不是轨迹点的密度,而是「有多少条不同的轨迹穿过了某个网格」——哪怕一条轨迹来回穿同一个网格十次,也只算1次。所以核心步骤是:
- 把整个空间(比如你说的100×100,实际480×640)划分成10×10的网格单元(X/Y/Z轴各分10段,2D对应10×10个网格,3D对应10×10×10个)。
- 对每条轨迹,找出它穿过的所有网格,去重后给对应网格的计数+1。
- 用计数矩阵生成热力图。
你需要的3个矩阵(对应不同维度)
xy_grid_count:(10,10)的2D矩阵,存储XY平面每个网格被多少条不同轨迹穿过。xz_grid_count:(10,10)的2D矩阵,对应XZ平面的统计结果。xyz_grid_count:(10,10,10)的3D矩阵,统计3D空间每个网格的轨迹穿过数(用来做3D热力图)。
具体实现步骤
第一步:预处理轨迹数据
- 先把每个轨迹文件的3D点序列(比如
(x1,y1,z1), (x2,y2,z2), ...)读进内存,给每条轨迹分配唯一ID(比如从0开始递增)——这样方便后续去重和计数。 - 坐标映射(可选):如果要把实际的480×640映射到100×100的讨论范围,用简单的线性缩放就行,比如
x_scaled = x * 100 / 480,Y轴同理。当然也可以直接用实际尺寸划分网格(X轴每48单位一个网格,Y轴每64单位一个),结果是一致的。
第二步:判断轨迹穿过的网格(关键!)
对每条轨迹,我们要找出它在不同平面/空间穿过的所有网格:
以XY平面为例:
- 遍历轨迹的连续两个点
(x_i,y_i)和(x_{i+1},y_{i+1}),计算这条线段穿过了哪些XY网格。这里可以用Bresenham算法的扩展版(专门处理线段穿网格),或者更简单的:先算出线段的包围盒覆盖的所有网格,再逐个判断线段是否穿过该网格。 - 把这条轨迹穿过的所有XY网格存在一个集合里(自动去重,避免同一条轨迹多次穿同一个网格重复计数)。
- 遍历这个集合,给
xy_grid_count中对应网格的数值加1。
XZ平面和3D网格的判断逻辑完全同理:
- XZ平面:把Y坐标换成Z,重复上述步骤,更新
xz_grid_count。 - 3D网格:判断线段穿过的3D空间网格,去重后更新
xyz_grid_count。
第三步:生成2D热力图(XY/XZ)
用Python的seaborn或者matplotlib就能快速实现,举个例子:
import seaborn as sns import matplotlib.pyplot as plt # 假设xy_grid_count是已经填充好的(10,10)矩阵 plt.figure(figsize=(8,8)) # 热力图+标注数值,颜色用橙红渐变 sns.heatmap(xy_grid_count, annot=True, cmap='YlOrRd', xticklabels=10, yticklabels=10) plt.title('XY平面热力图(穿过网格的不同轨迹数)') plt.xlabel('X轴网格编号') plt.ylabel('Y轴网格编号') plt.show()
把xy_grid_count换成xz_grid_count,改一下坐标轴标签,就能得到XZ平面的热力图。
第四步:生成3D热力图
3D热力图可以用plotly做交互式体素图,或者matplotlib做3D散点可视化:
用Plotly做交互式3D体素图:
import plotly.graph_objects as go import numpy as np # 假设xyz_grid_count是(10,10,10)的3D矩阵 x, y, z = np.meshgrid(np.arange(10), np.arange(10), np.arange(10)) fig = go.Figure(data=go.Volume( x=x.flatten(), y=y.flatten(), z=z.flatten(), value=xyz_grid_count.flatten(), isomin=1, isomax=xyz_grid_count.max(), opacity=0.3, # 调整透明度,方便看内部 surface_count=20, # 控制表面精细度 colorscale='YlOrRd' )) fig.update_layout(title='3D热力图(穿过网格的不同轨迹数)') fig.show()
用Matplotlib做3D散点图(更轻量化):
import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D fig = plt.figure(figsize=(10,8)) ax = fig.add_subplot(111, projection='3d') # 遍历每个3D网格 for i in range(10): for j in range(10): for k in range(10): count = xyz_grid_count[i][j][k] if count > 0: # 取网格中心坐标 x_center = i*10 + 5 y_center = j*10 + 5 z_center = k*10 + 5 # 用点的大小表示轨迹数量,颜色深浅辅助 ax.scatter(x_center, y_center, z_center, s=count*15, c='darkred', alpha=0.6) ax.set_title('3D热力图(轨迹数可视化)') ax.set_xlabel('X轴') ax.set_ylabel('Y轴') ax.set_zlabel('Z轴') plt.show()
几个实用小提示
- 去重必须重视:一定要用集合存储每条轨迹穿过的网格,不然同一条轨迹穿同一个网格多次会重复计数,结果就不准了。
- 效率优化:如果轨迹数量特别多,用numpy矩阵存储计数(比Python列表快N倍);判断线段穿网格的算法可以用快速的射线法,避免遍历所有网格浪费时间。
- 坐标对齐:确保所有轨迹的坐标系统一,不然划分网格后统计会乱套。
内容的提问来源于stack exchange,提问作者Philip Bal
相关产品推荐
相关产品推荐

