Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add supportment for non-centralized pinhole cameras data #74

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions scene/cameras.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# GRAPHDECO research group, https://team.inria.fr/graphdeco
# All rights reserved.
#
# This software is free for non-commercial, research and evaluation use
# This software is free for non-commercial, research and evaluation use
# under the terms of the LICENSE.md file.
#
# For inquiries contact george.drettakis@inria.fr
Expand All @@ -12,11 +12,11 @@
import torch
from torch import nn
import numpy as np
from utils.graphics_utils import getWorld2View2, getProjectionMatrix
from utils.graphics_utils import getWorld2View2, getProjectionMatrixShift

class Camera(nn.Module):
def __init__(self, colmap_id, R, T, FoVx, FoVy, image, gt_alpha_mask,
image_name, uid,
image_name, uid, principal_point_ndc,
trans=np.array([0.0, 0.0, 0.0]), scale=1.0, data_device = "cuda"
):
super(Camera, self).__init__()
Expand Down Expand Up @@ -46,22 +46,22 @@ def __init__(self, colmap_id, R, T, FoVx, FoVy, image, gt_alpha_mask,
else:
self.original_image *= torch.ones((1, self.image_height, self.image_width), device=self.data_device)
self.gt_alpha_mask = None

self.zfar = 100.0
self.znear = 0.01

self.trans = trans
self.scale = scale

self.world_view_transform = torch.tensor(getWorld2View2(R, T, trans, scale)).transpose(0, 1).cuda()
self.projection_matrix = getProjectionMatrix(znear=self.znear, zfar=self.zfar, fovX=self.FoVx, fovY=self.FoVy).transpose(0,1).cuda()
self.projection_matrix = getProjectionMatrixShift(znear=self.znear, zfar=self.zfar, fovX=self.FoVx, fovY=self.FoVy, width=self.image_width, height=self.image_height, principal_point_ndc=principal_point_ndc).transpose(0,1).cuda()
self.full_proj_transform = (self.world_view_transform.unsqueeze(0).bmm(self.projection_matrix.unsqueeze(0))).squeeze(0)
self.camera_center = self.world_view_transform.inverse()[3, :3]

class MiniCam:
def __init__(self, width, height, fovy, fovx, znear, zfar, world_view_transform, full_proj_transform):
self.image_width = width
self.image_height = height
self.image_height = height
self.FoVy = fovy
self.FoVx = fovx
self.znear = znear
Expand Down
22 changes: 15 additions & 7 deletions scene/dataset_readers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# GRAPHDECO research group, https://team.inria.fr/graphdeco
# All rights reserved.
#
# This software is free for non-commercial, research and evaluation use
# This software is free for non-commercial, research and evaluation use
# under the terms of the LICENSE.md file.
#
# For inquiries contact george.drettakis@inria.fr
Expand Down Expand Up @@ -34,6 +34,7 @@ class CameraInfo(NamedTuple):
image_name: str
width: int
height: int
principal_point_ndc: np.array

class SceneInfo(NamedTuple):
point_cloud: BasicPointCloud
Expand Down Expand Up @@ -84,22 +85,29 @@ def readColmapCameras(cam_extrinsics, cam_intrinsics, images_folder):

if intr.model=="SIMPLE_PINHOLE":
focal_length_x = intr.params[0]
cx = intr.params[1]
cy = intr.params[2]
FovY = focal2fov(focal_length_x, height)
FovX = focal2fov(focal_length_x, width)
elif intr.model=="PINHOLE":
focal_length_x = intr.params[0]
focal_length_y = intr.params[1]
cx = intr.params[2]
cy = intr.params[3]
FovY = focal2fov(focal_length_y, height)
FovX = focal2fov(focal_length_x, width)
else:
assert False, "Colmap camera model not handled: only undistorted datasets (PINHOLE or SIMPLE_PINHOLE cameras) supported!"

principal_point_ndc = np.array([cx / width, cy / height])

image_path = os.path.join(images_folder, os.path.basename(extr.name))
image_name = os.path.basename(image_path).split(".")[0]
image = Image.open(image_path)

cam_info = CameraInfo(uid=uid, R=R, T=T, FovY=FovY, FovX=FovX, image=image,
image_path=image_path, image_name=image_name, width=width, height=height)
image_path=image_path, image_name=image_name, width=width, height=height,
principal_point_ndc=principal_point_ndc)
cam_infos.append(cam_info)
sys.stdout.write('\n')
return cam_infos
Expand All @@ -117,7 +125,7 @@ def storePly(path, xyz, rgb):
dtype = [('x', 'f4'), ('y', 'f4'), ('z', 'f4'),
('nx', 'f4'), ('ny', 'f4'), ('nz', 'f4'),
('red', 'u1'), ('green', 'u1'), ('blue', 'u1')]

normals = np.zeros_like(xyz)

elements = np.empty(xyz.shape[0], dtype=dtype)
Expand Down Expand Up @@ -210,20 +218,20 @@ def readCamerasFromTransforms(path, transformsfile, white_background, extension=
image = Image.fromarray(np.array(arr*255.0, dtype=np.byte), "RGB")

fovy = focal2fov(fov2focal(fovx, image.size[0]), image.size[1])
FovY = fovy
FovY = fovy
FovX = fovx

cam_infos.append(CameraInfo(uid=idx, R=R, T=T, FovY=FovY, FovX=FovX, image=image,
image_path=image_path, image_name=image_name, width=image.size[0], height=image.size[1]))

return cam_infos

def readNerfSyntheticInfo(path, white_background, eval, extension=".png"):
print("Reading Training Transforms")
train_cam_infos = readCamerasFromTransforms(path, "transforms_train.json", white_background, extension)
print("Reading Test Transforms")
test_cam_infos = readCamerasFromTransforms(path, "transforms_test.json", white_background, extension)

if not eval:
train_cam_infos.extend(test_cam_infos)
test_cam_infos = []
Expand All @@ -235,7 +243,7 @@ def readNerfSyntheticInfo(path, white_background, eval, extension=".png"):
# Since this data set has no colmap data, we start with random points
num_pts = 100_000
print(f"Generating random point cloud ({num_pts})...")

# We create random points inside the bounds of the synthetic Blender scenes
xyz = np.random.random((num_pts, 3)) * 2.6 - 1.3
shs = np.random.random((num_pts, 3)) / 255.0
Expand Down
10 changes: 6 additions & 4 deletions utils/camera_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# GRAPHDECO research group, https://team.inria.fr/graphdeco
# All rights reserved.
#
# This software is free for non-commercial, research and evaluation use
# This software is free for non-commercial, research and evaluation use
# under the terms of the LICENSE.md file.
#
# For inquiries contact george.drettakis@inria.fr
Expand Down Expand Up @@ -48,10 +48,12 @@ def loadCam(args, id, cam_info, resolution_scale):
loaded_mask = None
gt_image = resized_image_rgb

return Camera(colmap_id=cam_info.uid, R=cam_info.R, T=cam_info.T,
FoVx=cam_info.FovX, FoVy=cam_info.FovY,
return Camera(colmap_id=cam_info.uid, R=cam_info.R, T=cam_info.T,
FoVx=cam_info.FovX, FoVy=cam_info.FovY,
image=gt_image, gt_alpha_mask=loaded_mask,
image_name=cam_info.image_name, uid=id, data_device=args.data_device)
image_name=cam_info.image_name, uid=id,
principal_point_ndc=cam_info.principal_point_ndc,
data_device=args.data_device)

def cameraList_from_camInfos(cam_infos, resolution_scale, args):
camera_list = []
Expand Down
40 changes: 39 additions & 1 deletion utils/graphics_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# GRAPHDECO research group, https://team.inria.fr/graphdeco
# All rights reserved.
#
# This software is free for non-commercial, research and evaluation use
# This software is free for non-commercial, research and evaluation use
# under the terms of the LICENSE.md file.
#
# For inquiries contact george.drettakis@inria.fr
Expand Down Expand Up @@ -70,6 +70,44 @@ def getProjectionMatrix(znear, zfar, fovX, fovY):
P[2, 3] = -(zfar * znear) / (zfar - znear)
return P

def getProjectionMatrixShift(znear, zfar, fovX, fovY, width, height, principal_point_ndc):
tanHalfFovY = math.tan((fovY / 2))
tanHalfFovX = math.tan((fovX / 2))

# the origin at center of image plane
top = tanHalfFovY * znear
bottom = -top
right = tanHalfFovX * znear
left = -right

# shift the frame window due to the non-zero principle point offsets
cx = width * principal_point_ndc[0]
cy = height * principal_point_ndc[1]
focal_x = fov2focal(fovX, width)
focal_y = fov2focal(fovY, height)
offset_x = cx - (width / 2)
offset_x = (offset_x / focal_x) * znear
offset_y = cy - (height / 2)
offset_y = (offset_y / focal_y) * znear

top = top + offset_y
left = left + offset_x
right = right + offset_x
bottom = bottom + offset_y

P = torch.zeros(4, 4)

z_sign = 1.0

P[0, 0] = 2.0 * znear / (right - left)
P[1, 1] = 2.0 * znear / (top - bottom)
P[0, 2] = (right + left) / (right - left)
P[1, 2] = (top + bottom) / (top - bottom)
P[3, 2] = z_sign
P[2, 2] = z_sign * zfar / (zfar - znear)
P[2, 3] = -(zfar * znear) / (zfar - znear)
return P

def fov2focal(fov, pixels):
return pixels / (2 * math.tan(fov / 2))

Expand Down