Spaces:
Running on Zero
Running on Zero
Download src/model/encoder/unimatch/matching.py from hugging-apps/codecsplat: direct link, hf CLI and curl.
- Browser
- Download file 3.48 kB
-
https://huggingface.co/spaces/hugging-apps/codecsplat/resolve/main/src/model/encoder/unimatch/matching.py
- Command line
-
hf download hf://spaces/hugging-apps/codecsplat/src/model/encoder/unimatch/matching.py
-
curl -L -o matching.py https://huggingface.co/spaces/hugging-apps/codecsplat/resolve/main/src/model/encoder/unimatch/matching.py
3.48 kB
| import torch | |
| import torch.nn.functional as F | |
| def coords_grid(b, h, w, homogeneous=False, device=None): | |
| y, x = torch.meshgrid( | |
| torch.arange(h), torch.arange(w), indexing="ij" | |
| ) # [H, W] | |
| stacks = [x, y] | |
| if homogeneous: | |
| ones = torch.ones_like(x) # [H, W] | |
| stacks.append(ones) | |
| grid = torch.stack(stacks, dim=0).float() # [2, H, W] or [3, H, W] | |
| grid = grid[None].expand(b, -1, -1, -1) # [B, 2, H, W] or [B, 3, H, W] | |
| if device is not None: | |
| grid = grid.to(device) | |
| return grid | |
| def warp_with_pose_depth_candidates( | |
| feature1, | |
| ref_intrinsics, | |
| tgt_intrinsics, | |
| pose, | |
| depth, | |
| clamp_min_depth=1e-3, | |
| grid_sample_disable_cudnn=False, | |
| ): | |
| """ | |
| feature1: [B, C, H, W] | |
| ref_intrinsics: [B, 3, 3], used to backproject reference pixels | |
| tgt_intrinsics: [B, 3, 3], used to reproject into target-view pixels | |
| pose: [B, 4, 4] | |
| depth: [B, D, H, W] | |
| """ | |
| assert ref_intrinsics.size(1) == ref_intrinsics.size(2) == 3 | |
| assert tgt_intrinsics.size(1) == tgt_intrinsics.size(2) == 3 | |
| assert pose.size(1) == pose.size(2) == 4 | |
| assert depth.dim() == 4 | |
| b, d, h, w = depth.size() | |
| c = feature1.size(1) | |
| feature_dtype = feature1.dtype | |
| with torch.no_grad(), torch.autocast( | |
| device_type=depth.device.type, enabled=False | |
| ): | |
| ref_intrinsics = ref_intrinsics.float() | |
| tgt_intrinsics = tgt_intrinsics.float() | |
| pose = pose.float() | |
| depth = depth.float() | |
| # pixel coordinates | |
| grid = coords_grid( | |
| b, h, w, homogeneous=True, device=depth.device | |
| ) # [B, 3, H, W] | |
| # back project to 3D and transform viewpoint | |
| points = torch.linalg.inv(ref_intrinsics).bmm( | |
| grid.reshape(b, 3, -1) | |
| ) # [B, 3, H*W] | |
| points = torch.bmm(pose[:, :3, :3], points).unsqueeze(2) * depth.reshape( | |
| b, 1, d, h * w | |
| ) # [B, 3, D, H*W] | |
| points = points + pose[:, :3, -1:].unsqueeze(-1) # [B, 3, D, H*W] | |
| # reproject to 2D image plane | |
| points = torch.bmm(tgt_intrinsics, points.view(b, 3, -1)).view( | |
| b, 3, d, h * w | |
| ) # [B, 3, D, H*W] | |
| pixel_coords = points[:, :2] / points[:, -1:].clamp( | |
| min=clamp_min_depth | |
| ) # [B, 2, D, H*W] | |
| # normalize to [-1, 1] | |
| x_grid = 2 * pixel_coords[:, 0] / (w - 1) - 1 | |
| y_grid = 2 * pixel_coords[:, 1] / (h - 1) - 1 | |
| grid = torch.stack([x_grid, y_grid], dim=-1) # [B, D, H*W, 2] | |
| # Disable cuDNN for large grid_sample inputs; this avoids a known PyTorch | |
| # issue while keeping the default path for smaller inputs. | |
| # Ref: https://github.com/pytorch/pytorch/issues/88380 | |
| if feature1.numel() > 1000000: | |
| grid_sample_disable_cudnn = True | |
| with torch.backends.cudnn.flags(enabled=not grid_sample_disable_cudnn): | |
| # grid_sample requires the feature and grid dtypes to match. Compute the | |
| # warp in FP32 for sub-pixel grid accuracy, then return to the feature dtype. | |
| with torch.autocast(device_type=feature1.device.type, enabled=False): | |
| warped_feature = F.grid_sample( | |
| feature1.float(), | |
| grid.view(b, d * h, w, 2), | |
| mode="bilinear", | |
| padding_mode="zeros", | |
| align_corners=True, | |
| ).view( | |
| b, c, d, h, w | |
| ) # [B, C, D, H, W] | |
| return warped_feature.to(feature_dtype) | |