Skip to content

Commit b08e083

Browse files
jb-yeJianbo Ye
authored andcommitted
Fix projection for images with non-centered camera (e.g. crops)
1 parent 2d45698 commit b08e083

File tree

7 files changed

+51
-20
lines changed

7 files changed

+51
-20
lines changed

gsplat/_torch_impl.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,8 @@ def project_cov3d_ewa(
245245
viewmat: Tensor,
246246
fx: float,
247247
fy: float,
248-
tan_fovx: float,
249-
tan_fovy: float,
248+
lim_x: Tuple[float, float],
249+
lim_y: Tuple[float, float],
250250
is_valid: Optional[Tensor] = None,
251251
) -> Tuple[Tensor, Tensor]:
252252
assert mean3d.shape[-1] == 3, mean3d.shape
@@ -263,10 +263,8 @@ def project_cov3d_ewa(
263263
rz = 1.0 / t[..., 2] # (...,)
264264
rz2 = rz**2 # (...,)
265265

266-
lim_x = 1.3 * torch.tensor([tan_fovx], device=mean3d.device)
267-
lim_y = 1.3 * torch.tensor([tan_fovy], device=mean3d.device)
268-
x_clamp = t[..., 2] * torch.clamp(t[..., 0] * rz, min=-lim_x, max=lim_x)
269-
y_clamp = t[..., 2] * torch.clamp(t[..., 1] * rz, min=-lim_y, max=lim_y)
266+
x_clamp = t[..., 2] * torch.clamp(t[..., 0] * rz, min=-lim_x[1], max=lim_x[0])
267+
y_clamp = t[..., 2] * torch.clamp(t[..., 1] * rz, min=-lim_y[1], max=lim_y[0])
270268
t = torch.stack([x_clamp, y_clamp, t[..., 2]], dim=-1)
271269

272270
O = torch.zeros_like(rz)
@@ -352,7 +350,7 @@ def project_pix(fxfy, p_view, center, eps=1e-6):
352350
return torch.stack([u, v], dim=-1)
353351

354352

355-
def clip_near_plane(p, viewmat, clip_thresh=0.01):
353+
def clip_near_plane(p, viewmat, clip_thresh=0.01) -> Tuple[Tensor, Tensor]:
356354
R = viewmat[:3, :3]
357355
T = viewmat[:3, 3]
358356
p_view = torch.einsum("ij,nj->ni", R, p) + T[None]
@@ -404,10 +402,12 @@ def project_gaussians_forward(
404402
fx, fy, cx, cy = intrins
405403
tan_fovx = 0.5 * img_size[0] / fx
406404
tan_fovy = 0.5 * img_size[1] / fy
405+
lim_x = ((img_size[0] - cx) / fx + 0.3 * tan_fovx, cx / fx + 0.3 * tan_fovx)
406+
lim_y = ((img_size[1] - cy) / fy + 0.3 * tan_fovy, cy / fy + 0.3 * tan_fovy)
407407
p_view, is_close = clip_near_plane(means3d, viewmat, clip_thresh)
408408
cov3d = scale_rot_to_cov3d(scales, glob_scale, quats)
409409
cov2d, compensation = project_cov3d_ewa(
410-
means3d, cov3d, viewmat, fx, fy, tan_fovx, tan_fovy, ~is_close
410+
means3d, cov3d, viewmat, fx, fy, lim_x, lim_y, ~is_close
411411
)
412412
conic, radius, det_valid = compute_cov2d_bounds(cov2d, ~is_close)
413413
xys = project_pix((fx, fy), p_view, (cx, cy))

gsplat/cuda/csrc/backward.cu

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,10 @@ __global__ void project_gaussians_backward_kernel(
357357
float3 p_world = means3d[idx];
358358
float fx = intrins.x;
359359
float fy = intrins.y;
360+
float cx = intrins.z;
361+
float cy = intrins.w;
362+
float tan_fovx = 0.5 * img_size.x / fx;
363+
float tan_fovy = 0.5 * img_size.y / fy;
360364
float3 p_view = transform_4x3(viewmat, p_world);
361365
// get v_mean3d from v_xy
362366
v_mean3d[idx] = transform_4x3_rot_only_transposed(
@@ -375,12 +379,20 @@ __global__ void project_gaussians_backward_kernel(
375379
cov2d_to_conic_vjp(conics[idx], v_conic[idx], v_cov2d[idx]);
376380
cov2d_to_compensation_vjp(compensation[idx], conics[idx], v_compensation[idx], v_cov2d[idx]);
377381
// get v_cov3d (and v_mean3d contribution)
382+
float lim_x_pos = (img_size.x - cx) / fx + 0.3f * tan_fovx;
383+
float lim_x_neg = cx / fx + 0.3f * tan_fovx;
384+
float lim_y_pos = (img_size.y - cy) / fy + 0.3f * tan_fovy;
385+
float lim_y_neg = cy / fy + 0.3f * tan_fovy;
378386
project_cov3d_ewa_vjp(
379387
p_world,
380388
&(cov3d[6 * idx]),
381389
viewmat,
382390
fx,
383391
fy,
392+
lim_x_pos,
393+
lim_x_neg,
394+
lim_y_pos,
395+
lim_y_neg,
384396
v_cov2d[idx],
385397
v_mean3d[idx],
386398
&(v_cov3d[6 * idx])
@@ -403,6 +415,10 @@ __device__ void project_cov3d_ewa_vjp(
403415
const float* __restrict__ viewmat,
404416
const float fx,
405417
const float fy,
418+
const float lim_x_pos,
419+
const float lim_x_neg,
420+
const float lim_y_pos,
421+
const float lim_y_neg,
406422
const float3& __restrict__ v_cov2d,
407423
float3& __restrict__ v_mean3d,
408424
float* __restrict__ v_cov3d
@@ -418,6 +434,10 @@ __device__ void project_cov3d_ewa_vjp(
418434
// clang-format on
419435
glm::vec3 p = glm::vec3(viewmat[3], viewmat[7], viewmat[11]);
420436
glm::vec3 t = W * glm::vec3(mean3d.x, mean3d.y, mean3d.z) + p;
437+
438+
t.x = t.z * std::min(lim_x_pos, std::max(-lim_x_neg, t.x / t.z));
439+
t.y = t.z * std::min(lim_y_pos, std::max(-lim_y_neg, t.y / t.z));
440+
421441
float rz = 1.f / t.z;
422442
float rz2 = rz * rz;
423443

gsplat/cuda/csrc/backward.cuh

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ __device__ void project_cov3d_ewa_vjp(
7979
const float *viewmat,
8080
const float fx,
8181
const float fy,
82+
const float lim_x_pos,
83+
const float lim_x_neg,
84+
const float lim_y_pos,
85+
const float lim_y_neg,
8286
const float3 &v_cov2d,
8387
float3 &v_mean3d,
8488
float *v_cov3d

gsplat/cuda/csrc/forward.cu

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,14 @@ __global__ void project_gaussians_forward_kernel(
6363
float cy = intrins.w;
6464
float tan_fovx = 0.5 * img_size.x / fx;
6565
float tan_fovy = 0.5 * img_size.y / fy;
66+
float lim_x_pos = (img_size.x - cx) / fx + 0.3f * tan_fovx;
67+
float lim_x_neg = cx / fx + 0.3f * tan_fovx;
68+
float lim_y_pos = (img_size.y - cy) / fy + 0.3f * tan_fovy;
69+
float lim_y_neg = cy / fy + 0.3f * tan_fovy;
6670
float3 cov2d;
6771
float comp;
6872
project_cov3d_ewa(
69-
p_world, cur_cov3d, viewmat, fx, fy, tan_fovx, tan_fovy,
73+
p_world, cur_cov3d, viewmat, fx, fy, lim_x_pos, lim_x_neg, lim_y_pos, lim_y_neg,
7074
cov2d, comp
7175
);
7276
// printf("cov2d %d, %.2f %.2f %.2f\n", idx, cov2d.x, cov2d.y, cov2d.z);
@@ -425,8 +429,10 @@ __device__ void project_cov3d_ewa(
425429
const float* __restrict__ viewmat,
426430
const float fx,
427431
const float fy,
428-
const float tan_fovx,
429-
const float tan_fovy,
432+
const float lim_x_pos,
433+
const float lim_x_neg,
434+
const float lim_y_pos,
435+
const float lim_y_neg,
430436
float3 &cov2d,
431437
float &compensation
432438
) {
@@ -447,11 +453,8 @@ __device__ void project_cov3d_ewa(
447453
glm::vec3 p = glm::vec3(viewmat[3], viewmat[7], viewmat[11]);
448454
glm::vec3 t = W * glm::vec3(mean3d.x, mean3d.y, mean3d.z) + p;
449455

450-
// clip so that the covariance
451-
float lim_x = 1.3f * tan_fovx;
452-
float lim_y = 1.3f * tan_fovy;
453-
t.x = t.z * std::min(lim_x, std::max(-lim_x, t.x / t.z));
454-
t.y = t.z * std::min(lim_y, std::max(-lim_y, t.y / t.z));
456+
t.x = t.z * std::min(lim_x_pos, std::max(-lim_x_neg, t.x / t.z));
457+
t.y = t.z * std::min(lim_y_pos, std::max(-lim_y_neg, t.y / t.z));
455458

456459
float rz = 1.f / t.z;
457460
float rz2 = rz * rz;

gsplat/cuda/csrc/forward.cuh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,10 @@ __device__ void project_cov3d_ewa(
6464
const float *viewmat,
6565
const float fx,
6666
const float fy,
67-
const float tan_fovx,
68-
const float tan_fovy,
67+
const float lim_x_pos,
68+
const float lim_x_neg,
69+
const float lim_y_pos,
70+
const float lim_y_neg,
6971
float3 &cov2d,
7072
float &comp
7173
);

gsplat/version.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
__version__ = "0.1.12"
1+
__version__ = "0.1.13"

tests/test_project_gaussians.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,13 +217,15 @@ def project_cov3d_ewa_partial(mean3d, cov3d):
217217
"""
218218
tan_fovx = 0.5 * W / fx
219219
tan_fovy = 0.5 * H / fy
220+
lim_x = ((W - cx) / fx + 0.3 * tan_fovx, cx / fx + 0.3 * tan_fovx)
221+
lim_y = ((H - cy) / fy + 0.3 * tan_fovy, cy / fy + 0.3 * tan_fovy)
220222

221223
cov3d_mat = torch.zeros(*cov3d.shape[:-1], 3, 3, device=device)
222224
i, j = torch.triu_indices(3, 3)
223225
cov3d_mat[..., i, j] = cov3d
224226
cov3d_mat[..., [1, 2, 2], [0, 0, 1]] = cov3d[..., [1, 2, 4]]
225227
cov2d, _ = _torch_impl.project_cov3d_ewa(
226-
mean3d, cov3d_mat, viewmat, fx, fy, tan_fovx, tan_fovy
228+
mean3d, cov3d_mat, viewmat, fx, fy, lim_x, lim_y
227229
)
228230
ii, jj = torch.triu_indices(2, 2)
229231
return cov2d[..., ii, jj]

0 commit comments

Comments
 (0)