| 139 | |
| 140 | |
| 141 | class LearnableCamera: |
| 142 | def __init__( |
| 143 | self, |
| 144 | uid, |
| 145 | color, |
| 146 | depth, |
| 147 | gt_H_col, |
| 148 | H_col, |
| 149 | fx, |
| 150 | fy, |
| 151 | device="cuda:0", |
| 152 | ): |
| 153 | self.uid = uid |
| 154 | self.device = device |
| 155 | |
| 156 | self.R = torch.tensor(H_col[:3, :3], device=device) |
| 157 | self.T = torch.tensor(H_col[:3, 3], device=device) |
| 158 | self.R_gt = torch.tensor(gt_H_col[:3, :3], device=device) |
| 159 | self.T_gt = torch.tensor(gt_H_col[:3, 3], device=device) |
| 160 | self.zfar = 100.0 |
| 161 | self.znear = 0.01 |
| 162 | self.original_image = color |
| 163 | self.depth = depth |
| 164 | _, h, w = color.shape |
| 165 | self.intrinsic_matrix = torch.tensor([[fx, 0, w / 2], [0, fy, h / 2], [0, 0, 1]], device=device) |
| 166 | self.fx = fx |
| 167 | self.fy = fy |
| 168 | self.cx = w / 2 |
| 169 | self.cy = h / 2 |
| 170 | self.FoVx = focal2fov(fx, w) |
| 171 | self.FoVy = focal2fov(fy, h) |
| 172 | self.image_height = h |
| 173 | self.image_width = w |
| 174 | |
| 175 | self.cam_rot_delta = nn.Parameter( |
| 176 | torch.zeros(3, requires_grad=True, device=device) |
| 177 | ) |
| 178 | self.cam_trans_delta = nn.Parameter( |
| 179 | torch.zeros(3, requires_grad=True, device=device) |
| 180 | ) |
| 181 | |
| 182 | self.projection_matrix = get_projection_matrix(znear=self.znear, zfar=self.zfar, |
| 183 | fovX=self.FoVx, fovY=self.FoVy).cuda() |
| 184 | |
| 185 | self.optimizer = torch.optim.Adam([self.cam_rot_delta, self.cam_trans_delta], lr=0.001) |
| 186 | |
| 187 | @property |
| 188 | def world_view_transform(self): |
| 189 | return getWorld2View3(self.R, self.T) |
| 190 | |
| 191 | @property |
| 192 | def full_proj_transform(self): |
| 193 | return self.projection_matrix @ self.world_view_transform |
| 194 | |
| 195 | @property |
| 196 | def camera_center(self): |
| 197 | return self.world_view_transform.inverse()[:3, 3] |
| 198 | |