news 2026/9/24 19:42:46

PyTorch3D 点云光栅化完全指南:rasterize_points 参数、原理与实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PyTorch3D 点云光栅化完全指南:rasterize_points 参数、原理与实战

PyTorch3D 点云光栅化完全指南:rasterize_points 参数、原理与实战

【免费下载链接】pytorch3dPyTorch3D is FAIR's library of reusable components for deep learning with 3D data项目地址: https://gitcode.com/gh_mirrors/py/pytorch3d

导读

本文围绕 PyTorch3D 渲染管线中的核心算子pytorch3d.renderer.points.rasterize_points展开,系统讲解点云光栅化的输入约定、五个核心参数、三类返回张量以及"朴素—分箱(coarse-to-fine)—纯 Python"三种实现路径。读完本文,你将能独立完成任意点云的光栅化调用、正确设置半径与points_per_pixel、处理非方形图像的高宽比,并理解其可微反向传播与上层PointsRasterizer/PointsRenderer的组装方式。

一、模块定位:点云渲染管线中的光栅化环节

rasterize_points是 PyTorch3D 点云渲染三阶段管线中的核心阶段。以 pytorch3d/renderer/points/renderer.py 中的PointsRenderer为例,一次完整的点云渲染被拆解为:

  1. 变换(transform):由PointsRasterizer.transform将世界坐标点变换到 NDC 空间(见 pytorch3d/renderer/points/rasterizer.py);
  2. 光栅化(rasterize):调用rasterize_points把每个点绘制为屏幕上的圆盘,并为每个像素找出最近的 K 个点,输出idx / zbuf / dists三类片段(fragments)数据;
  3. 合成(composite)AlphaCompositorNormWeightedCompositor依据距离权重混合颜色(见 pytorch3d/renderer/points/compositor.py 与底层实现 pytorch3d/renderer/compositing.py)。

模块的公开 API 在 pytorch3d/renderer/points/init.py 中统一导出,本文关联文档 docs/modules/renderer/points/rasterize_points.rst 即通过automodule自动提取rasterize_points.py的完整文档字符串。

PyTorch3D 点云光栅化到非方形矩形图像(1024x512)的渲染结果

二、函数签名与核心参数

rasterize_points定义于 pytorch3d/renderer/points/rasterize_points.py,签名如下:

def rasterize_points( pointclouds, image_size: Union[int, List[int], Tuple[int, int]] = 256, radius: Union[float, List, Tuple, torch.Tensor] = 0.01, points_per_pixel: int = 8, bin_size: Optional[int] = None, max_points_per_bin: Optional[int] = None, ):

每个点云会被光栅化到一张独立图像上:当image_size为整数时输出(image_size, image_size)的方形图像,为(H, W)元组时输出(H, W)的矩形图像。

2.1pointclouds:输入的点云批次

  • 类型为Pointclouds对象(见 pytorch3d/structures/pointclouds.py),代表一批 N 个点云;
  • 批内每个点云可以有不同数量的点,点的坐标为(x, y, z)
  • 坐标必须位于NDC(归一化设备坐标)空间,即[-1, 1]^3,相机位于原点(0, 0, 0)
  • 相机坐标系约定:x 轴从右指向左、y 轴从下指向上、z 轴从后指向前(即常见的"右/上/后向观察者"约定)。

函数内部通过pointclouds.points_packed()cloud_to_packed_first_idx()num_points_per_cloud()将异构点云摊平为紧凑(packed)张量参与计算(rasterize_points.py)。

2.2image_size:输出图像尺寸与高宽比

  • 支持整数(方形)或(H, W)元组(非方形);
  • 非方形图像涉及两个高宽比:像素高宽比与输出图像高宽比。光栅化器假设像素为正方形,但允许图像本身为矩形;
  • 文档明确建议:多数场景下应将相机的像素高宽比设为1.0,仅通过image_size调整输出图像尺寸;
  • NDC 范围在非方形图像下会被缩放以保持高宽比:较小维度保持[-1, 1],另一维度按H:W比例缩放。例如(H, W) = (64, 128)时,高度 NDC 范围为[-1, 1],宽度范围为[-2, 2]。像素到 NDC 的换算由 pytorch3d/renderer/mesh/rasterize_meshes.py 的pix_to_non_square_ndc实现,CUDA 内核中的PixToNonSquareNdc与之对应(pytorch3d/csrc/rasterize_points/rasterization_utils.cuh);
  • H != W时,代码使用max_image_size = max(H, W)推导bin_size,以适配分箱光栅化器中"每维度 bin 数"的约束(rasterize_points.py)。

2.3radius:圆盘半径(NDC 单位)

  • 默认0.01,即每个点被光栅化为 NDC 空间下半径为0.01的圆盘;
  • 支持逐点半径:传入 shape 为(N, P)torch.Tensor,其中 N 为批大小、P 为每个点云的填充后点数,即可为批内每个点指定不同半径;
  • 内部经_format_radius(rasterize_points.py)统一格式化为 shape(P_packed,)的紧凑张量:float 被广播为全同值张量,list/tuple被转为张量,(N, P_padded)张量则通过padded_to_packed_idx()索引映射为 packed 形式;形状不符时抛出ValueError
  • 该参数直接影响渲染的"软边界"权重:PointsRenderer.forward中权重定义为1 - dists2 / (r * r)(renderer.py),用于软化硬决策边界、保证可微性。

2.4points_per_pixel:每像素保留的点数

  • 默认8,即每个像素沿 z 轴保留最近的 K 个点,并按 z 升序排列;
  • 该值即返回张量的第 4 维长度K
  • 内核中硬上限为kMaxPointsPerPixel = 150(pytorch3d/csrc/rasterize_points/rasterization_utils.cuh),超出会报错 "Must have points_per_pixel <= 150"(rasterize_points.cu)。

2.5bin_sizemax_points_per_bin:coarse-to-fine 分箱

  • bin_size=0:使用朴素光栅化(naive),逐像素遍历该点云的全部点;
  • bin_size=None启发式自动选择。CPU 上强制回退为0("Binned CPU rasterization not fully implemented",分箱 CPU 光栅化未完整实现);CUDA 上取2 ** max(ceil(log2(max_image_size)) - 4, 4)(rasterize_points.py);
  • bin_size > 0:启用分箱粗光栅化(_C._rasterize_points_coarse),先把每个点按空间位置分配到 bin 网格,再由细光栅化内核只检查本 bin 内的点,不改变输出值,只影响前向速度
  • 分箱模式下每维 bin 数为1 + (max_image_size - 1) // bin_size,受全局上限kMaxPointsPerBin = 22约束(rasterize_points.py),过小会抛出"bin_size too small, number of points per bin must be less than 22"(对应测试见 tests/test_rasterize_points.py);
  • max_points_per_bin:仅分箱模式生效,表示每个 bin 允许的最大点数,不影响输出值,只影响前向内存占用;默认取max(10000, _P / 5)(rasterize_points.py)。

三、返回值:idx / zbuf / dists2 三元组

函数返回(idx, zbuf, dists2)三元素元组,image_size(H, W)时三个张量的空间维度均为(N, H, W, ...)

返回张量形状含义
idx(N, H, W, points_per_pixel),int32每个像素处最近点的索引,按 z 升序。idx[n, y, x, k] = p表示 packed 点points[p]是像素(y, x)沿 z 方向第 k 近的点;未被points_per_pixel个点覆盖的像素用-1填充
zbuf(N, H, W, points_per_pixel),float32对应点的z 坐标,排序方式与idx一致;未覆盖处填充-1
dists2(N, H, W, points_per_pixel),float32像素中心与该点在x/y 平面欧氏距离平方(NDC 单位);未覆盖处填充-1

3.1 可微性与自定义 autograd Function

_RasterizePoints继承torch.autograd.Function(rasterize_points.py):

  • 前向:调用_C.rasterize_points,通过ctx.save_for_backward(points, idx)保存输入,并用ctx.mark_non_differentiable(idx)标记idx不可微;
  • 反向:调用_C.rasterize_points_backward,仅对zbufdists2的梯度回传到点坐标;
  • CUDA 反向内核按(N, H, W, K)逐像素并行,对grad_points使用atomicAdd累加(rasterize_points.cu),因此该算子被标记为alertNotDeterministic(非确定性)。

3.2 三种实现路径与一致性保证

实现入口适用平台说明
朴素 CUDA/CPUrasterize_points(..., bin_size=0)GPU / CPU每个像素一个线程(CUDA),遍历全部点
分箱 CUDArasterize_points(..., bin_size>0)GPU先粗分箱后细光栅化,加速不改变结果
纯 Pythonrasterize_points_pythonCPU教学/对照用,三层 for 循环逐像素检查

纯 Python 版本rasterize_points_python(rasterize_points.py)逻辑完全对应朴素内核:对每个点云、每行每列像素,跳过pz < 0(相机后的点),计算dist2 < radius2则插入 top-k 列表并排序截断。测试 tests/test_rasterize_points.py 的test_cpp_vs_naive_vs_binned对 CPU 朴素 / CUDA 朴素 / CUDA 分箱三条路径做了严格的输出与梯度一致性校验(idxzbuf完全相等,dists与梯度误差在1e-6/5e-6量级内)。

四、结合源码看内核实现

4.1 像素判点逻辑CheckPixelInsidePoint

朴素与细光栅化内核共享同一设备端判定函数(rasterize_points.cu):

  1. 读取点的(px, py, pz)与该点半径p_radius,计算radius2 = p_radius²
  2. pz < 0直接返回——不渲染相机后方的点
  3. 计算像素中心与点的平面距离平方dist2 = dx² + dy²,当dist2 < radius2时该点覆盖此像素;
  4. 用数组维护最多 K 个Pix{z, idx, dist2},当满 K 个后若新点 z 更小则覆盖当前最大 z 的槽位并重新扫描最大值——由于K <= 150且通常很小,这是比 STL 堆更轻量、低发散的选择;
  5. 最终用BubbleSort按 z 升序输出。

4.2 细光栅化与分箱协同

RasterizePointsFineCudaKernel(rasterize_points.cu)从粗光栅化产出的bin_points(shape(N, BH, BW, T)-1为哨兵值)中只读取当前 bin 的点,从而把每个像素的候选点数从"全点云"降到"本 bin 内点数"。像素 id 的排布让相邻线程落入同一 bin,以获得合并访存(coalesced memory reads)。粗光栅化的 CPU 参考实现见 pytorch3d/csrc/rasterize_points/rasterize_points_cpu.cpp,其中同样对超过max_points_per_bin的点进行了截断处理。

4.3 坐标轴翻转约定

CUDA 内核在计算输出索引时对 x/y 做了翻转(yi = H - 1 - pix_idx / Wxi = W - 1 - pix_idx % W,见 rasterize_points.cu),这是因为相机坐标假设 +Y 向上、+X 向左,而图像行索引自上而下——与纯 Python 实现中yfix = H - 1 - yi的翻转逻辑一致。

五、上层封装:PointsRasterizationSettings 与 PointsRasterizer

rasterize_points通常不直接调用,而是通过高层封装使用:

from pytorch3d.renderer import ( PointsRasterizationSettings, PointsRasterizer, PointsRenderer, AlphaCompositor, PerspectiveCameras, ) from pytorch3d.structures import Pointclouds raster_settings = PointsRasterizationSettings( image_size=512, radius=0.01, points_per_pixel=8, bin_size=None, # 启发式;0 为朴素模式 max_points_per_bin=None, ) rasterizer = PointsRasterizer(cameras=cameras, raster_settings=raster_settings) renderer = PointsRenderer(rasterizer=rasterizer, compositor=AlphaCompositor()) images = renderer(pointclouds)
  • PointsRasterizationSettings(rasterizer.py)是以 dataclass 形式存储的参数字典,五个字段与rasterize_points一一对应,默认值完全一致(image_size=256, radius=0.01, points_per_pixel=8, bin_size=None, max_points_per_bin=None);
  • PointsRasterizer(rasterizer.py)的forward先经transform用相机把世界坐标变换到 NDC(保留 view 空间的 z 值),再展开raster_settings调用rasterize_points,返回PointFragments(idx, zbuf, dists)具名元组;相机既可在初始化时传入,也可在前向时以cameras=关键字覆盖;
  • PointsRenderer依据radiusdists2转为[0,1]的软权重,交由AlphaCompositor(alpha 合成,cum_alpha_k = alpha_k * prod_{l<k}(1 - alpha_l))或NormWeightedCompositor(归一化加权和)完成着色,两个合成器均支持background_color背景填充(compositor.py)。

六、验证与参考

  • 正确性测试:tests/test_rasterize_points.py 覆盖简单用例、相机后点剔除、变半径、三条实现路径一致性、bin_size过小报错等场景;
  • 非方形图像测试:tests/test_rasterize_rectangle_images.py 中的TestRasterizeRectangleImagesPointclouds对比方形与非方形图像下rasterize_points的片段输出与梯度;
  • 顶层 API 导出:pytorch3d/renderer/points/init.py;
  • 文档索引:docs/modules/renderer/points/index.rst 收录了本文关联的 rasterize_points.rst 及其配套的 rasterizer、renderer、compositor 文档。

七、注意事项小结

  1. 输入必须是 NDC 空间坐标:世界坐标需先经相机变换,直接传入原始世界坐标会得到错误结果;
  2. CPU 上不要依赖分箱bin_size=None在 CPU 上会退化为朴素模式,加速只在 CUDA 上生效;
  3. bin_size与图像尺寸联动:图像很大而bin_size过小时会触发kMaxPointsPerBin=22的报错,可按报错提示增大bin_size
  4. points_per_pixel有 150 的上限:需要更多候选点时需自行调整策略(如分多次光栅化);
  5. 矩形图像注意高宽比:像素保持正方形假设,图像高宽比由 NDC 范围缩放吸收,相机侧请保持像素高宽比为 1.0;
  6. 反向传播非确定性:CUDA 反向使用atomicAdd累加梯度,多次运行梯度可能略有差异,追求完全确定性时需注意此限制。

【免费下载链接】pytorch3dPyTorch3D is FAIR's library of reusable components for deep learning with 3D data项目地址: https://gitcode.com/gh_mirrors/py/pytorch3d

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 19:42:34

草图大师SketchUp下载安装全攻略:从版本选型到插件渲染

打开搜索引擎&#xff0c;输入“草图大师下载安装”&#xff0c;跳出来的结果保守估计有几十个标着“官方版”“中文版”“永久激活”的下载站&#xff0c;真正能让人安心的却不多。这个现象本身就说明了问题&#xff1a;草图大师&#xff08;SketchUp&#xff09;确实是国内建…

作者头像 李华
网站建设 2026/9/24 19:42:31

Kingscada链接外部数据库:从ODBC配置到报表系统集成实战

我最早接触kingscada是做一个水处理项目的数据归档&#xff0c;现场流程倒不复杂&#xff0c;麻烦的是甲方要求把所有关键工艺参数落到外部数据库里&#xff0c;还要能按班次、按天出产量报表。当时第一反应是用citect&#xff0c;但现场早期组态已经用kingscada做了大半&#…

作者头像 李华
网站建设 2026/9/24 19:41:59

过程建模要快而不完美:五步建模法及灰度验收指南

开头我见过太多团队栽在过程建模这件事上&#xff0c;不是不会做&#xff0c;而是太想一次做对。会议室里一群人围着白板抠了三个小时&#xff0c;就为了争论某个节点该用菱形还是圆角矩形、某个分支该不该画出来、某个字段到底叫"申请人"还是"发起人"。结…

作者头像 李华
网站建设 2026/9/24 19:41:40

单北斗GNSS变形监测在水库大坝安全监测中的应用与选型指南

这两年做水库大坝安全监测的朋友&#xff0c;几乎都遇到过“单北斗”这个要求&#xff1a;系统设计说明里写着“接收机需独立支持北斗工作”&#xff0c;招标文件里明确“单北斗优先”。很多人第一反应是疑惑&#xff1a;多星座融合明明信号更多、精度更稳&#xff0c;为什么偏…

作者头像 李华
网站建设 2026/9/24 19:41:22

MySQL索引实战:从B+树原理到慢查询优化,一次讲透

干这一行久了&#xff0c;你会发现一个特别有意思的现象&#xff1a;面试的时候"MySQL索引"人人都能聊两句&#xff0c;B树、最左前缀、回表这些词张口就来&#xff1b;可真到了线上&#xff0c;一条慢SQL把数据库拖到CPU飙满、连接堆积&#xff0c;能快速定位并解决…

作者头像 李华
网站建设 2026/9/24 19:41:06

DBeaver连MySQL8.0的PublicKeyRetrieval报错解决

前两天准备把一台开发机的 MySQL 从 5.7 升到 8.0&#xff0c;升级完顺手打开 DBeaver 想连上去看下数据表结构&#xff0c;结果“连接测试”直接甩给我一行红字&#xff1a;Public Key Retrieval is not allowed。紧接着就是一大段英文堆栈。第一次遇到这个报错的人&#xff0…

作者头像 李华