深度图得到多视角虚拟深度图
前提知识
[H, W]存的是深度信息,那这里的H,W对应的是u,v而不是x和y。
这里的H, W对应的是图像坐标里的v, u,不是三维空间坐标里的X, Y。
更准确地说:
depth.shape = [H, W] depth[v, u] = Z其中:
H:图像高度,对应行方向;W:图像宽度,对应列方向;v:行索引,范围是0 ~ H-1;u:列索引,范围是0 ~ W-1;Z:该像素对应的深度值。
所以:
[H, W] 是二维图像网格 (v, u) 是图像上的像素位置 depth[v, u] 存的是深度 Z而三维空间坐标是:
(X, Y, Z)其中:
X = (u - u0) * Z / fx Y = (v - v0) * Z / fy Z = depth[v, u]所以u, v和X, Y不是一回事。
可以这样理解:
u, v:图片上第几列、第几行 X, Y:真实三维空间里左右、上下方向的位置 Z:离相机远近举个例子:
depth[80, 120] = 700表示:
图像第 80 行、第 120 列这个像素, 对应的物体表面点距离相机 700mm。然后再结合相机内参,才能算出这个点在三维空间里的:
X, Y, Z[H, W]存的是深度信息,这个深度信息就是Z
Z = depth(u, v)深度图[H, W]中,每个位置(v, u)存的值就是这个像素对应空间点的深度Z。
更准确一点:
depth[v, u] = Z其中:
u:图像横坐标,也就是列索引;v:图像纵坐标,也就是行索引;Z:该像素对应的三维点在相机坐标系下的深度,通常单位是 mm 或 m。
然后根据相机内参,可以把它还原成三维点:
X = (u - u0) * Z / fx Y = (v - v0) * Z / fy Z = depth[v, u]所以深度图本身不是[X, Y, Z],它只直接存了Z。X和Y是通过像素坐标(u, v)加上相机内参反算出来的。
一句话:
深度图像素值 = Z 像素位置 (u, v) + Z + 相机内参 = 三维点 (X, Y, Z)深度图得到多视角虚拟深度图
你可以把深度图理解成“一张带距离信息的灰度图”。普通灰度图里每个像素只是亮暗,深度图里每个像素值表示这个位置离相机有多远。
比如深度图中某个像素是:
u = 120, v = 80, depth = 700mm意思是:图像第(120, 80)个像素看到的手部表面点,距离相机大约700mm。
1. 深度图为什么能变成点云
相机拍到的是二维像素坐标(u, v),但深度图还给了距离z。有了相机内参,就可以把这个二维点还原成三维点。
相机内参通常包括:
fx, fy: 焦距 u0, v0: 图像中心点反投影公式是:
X = (u - u0) * Z / fx Y = (v - v0) * Z / fy Z = depth(u, v)所以每个有效深度像素(u, v, Z)都能变成一个三维点(X, Y, Z)。
整张深度图里有很多有效像素,把它们都转成三维点,就得到一堆三维点。这一堆点就叫点云。
深度图 [H, W] 每个有效像素 -> 一个三维点 [X, Y, Z] 所有点合起来 -> 点云 [N, 3]N是有效深度像素数量,不一定等于H × W,因为背景或无效区域可能被过滤掉。
2. 什么是“以手部中心为旋转中心”
如果直接绕相机原点旋转,手可能会被甩到图像外面,所以通常会先找一个手部中心点,比如手掌中心或裁剪框中心,记为:
C = (Cx, Cy, Cz)然后每个点先减去这个中心:
P_centered = P - C这样就相当于把手移动到坐标系中心附近。
之后对这些点做旋转,比如绕 x 轴、y 轴旋转:
P_rotated = R * (P - C) + C其中:
P: 原始三维点 C: 手部中心 R: 旋转矩阵 P_rotated: 旋转后的三维点这一步的直观意思是:不是手真的动了,而是我们假装从另一个方向看这只手。
3. 旋转矩阵是什么意思
比如你想生成左右不同角度的视图,就绕 y 轴旋转;想生成上下不同角度的视图,就绕 x 轴旋转。
项目中通常会生成一组角度,比如:
水平角度: -60°, -30°, 0°, 30°, 60° 垂直角度: -60°, -30°, 0°, 30°, 60°组合后就是:
5 × 5 = 25 个虚拟视角每个角度组合都会生成一个旋转矩阵R,然后对点云里的所有点做同样的旋转。
4. 旋转后的点云怎么重新变回深度图
旋转后,每个三维点还是(X, Y, Z)。要重新生成图像,需要把三维点投影回二维像素平面。
投影公式和反投影相反:
u' = fx * X' / Z' + u0 v' = fy * Y' / Z' + v0 depth'(u', v') = Z'也就是说,每个旋转后的三维点都会落到新图像上的某个像素位置(u', v'),它的深度值就是Z'。
把所有点都投影回去,就得到一张新的深度图。这张图相当于“从另一个角度看到的手”。
5. 为什么要处理遮挡和重叠
投影时可能出现多个三维点落到同一个像素。例如:
点 A -> 像素 (100, 80), 深度 650mm 点 B -> 像素 (100, 80), 深度 720mm相机只能看到离自己更近的点,所以应该保留较小的深度值:
depth'(100, 80) = 650mm这叫 z-buffer 或深度缓冲思想。你的项目里的 CUDA 操作大概率就是为了高效完成深度图和点云之间的转换。
6. 整个过程直观理解
可以把它想象成这样:
原始深度图 = 从正面看到的一只手 反投影成点云 = 把这只手表面的像素恢复成三维空间里的一堆点 旋转点云 = 假装换一个角度看这只手 重新投影成深度图 = 把新角度下看到的三维点重新拍成一张深度图所以最终得到:
原始深度图: [H, W] 生成 25 个虚拟视角后: 多视角深度图: [25, H, W]这就是你项目里“虚拟多视角”的核心。它不是简单把图片旋转,而是先恢复三维几何,再从不同角度重新投影。
