[ad_1]
Vào đầu năm 2013, các tác giả từ Đại học Côte d’Azur và Max-Planck-Institut für Informatik đã xuất bản một bài báo có tựa đề “Tách Gaussian 3D để kết xuất trường thời gian thực”.¹ Bài báo trình bày một tiến bộ đáng kể trong kết xuất thần kinh thời gian thực, vượt qua tiện ích của các phương pháp trước đây như NeRF’s.² Gaussian splatting không chỉ giảm độ trễ mà còn phù hợp hoặc vượt quá chất lượng kết xuất của NeRF, khiến thế giới kết xuất thần kinh trở thành cơn bão.
Việc phân tán Gaussian, mặc dù hiệu quả, nhưng có thể khó hiểu đối với những người không quen với ma trận máy ảnh và kết xuất đồ họa. Hơn nữa, tôi nhận thấy rằng các tài nguyên để triển khai phân tách gaussian trong Python rất khan hiếm, vì ngay cả mã nguồn của tác giả cũng được viết bằng CUDA! Hướng dẫn này nhằm mục đích thu hẹp khoảng cách đó, cung cấp phần giới thiệu dựa trên Python về phân tách gaussian cho các kỹ sư thông thạo về python và học máy nhưng ít kinh nghiệm về kết xuất đồ họa. Mã đi kèm trên GitHub trình bày cách khởi tạo và hiển thị các điểm từ quá trình quét COLMAP thành hình ảnh cuối cùng giống với chuyển tiếp trong các ứng dụng phân tách (và một số mã CUDA bổ sung cho những người quan tâm). Hướng dẫn này cũng có một sổ ghi chép jupyter đồng hành (part_1.ipynb trong GitHub) có tất cả mã cần thiết để theo dõi. Mặc dù chúng tôi sẽ không xây dựng một cảnh biểu tượng gaussian đầy đủ, nhưng nếu làm theo, hướng dẫn này sẽ trang bị cho người đọc kiến thức nền tảng để tìm hiểu sâu hơn về kỹ thuật biểu tượng gaussian.
Để bắt đầu, chúng tôi sử dụng COLMAP, một phần mềm trích xuất các điểm được nhìn thấy nhất quán trên nhiều hình ảnh bằng cách sử dụng Cấu trúc từ Chuyển động (SfM).³ SfM về cơ bản xác định các điểm (ví dụ: cạnh trên bên phải của ô cửa) được tìm thấy trong nhiều hơn 1 hình ảnh. Bằng cách kết hợp các điểm này trên các hình ảnh khác nhau, chúng ta có thể ước tính độ sâu của từng điểm trong không gian 3D. Điều này mô phỏng chặt chẽ cách hoạt động của thị giác âm thanh nổi của con người, trong đó độ sâu được cảm nhận bằng cách so sánh các góc nhìn hơi khác nhau từ mỗi mắt. Do đó, SfM tạo ra một tập hợp các điểm 3D, mỗi điểm có tọa độ x, y và z, từ các điểm chung được tìm thấy trong nhiều hình ảnh, cung cấp cho chúng ta “cấu trúc” của cảnh.
Trong hướng dẫn này, chúng tôi sẽ sử dụng bản quét COLMAP dựng sẵn có sẵn cho tải xuống ở đây (Giấy phép Apache 2.0). Cụ thể là chúng tôi sẽ sử dụng thư mục Treehill trong tập dữ liệu đã tải xuống.
Thư mục bao gồm ba tệp tương ứng với các thông số digital camera, thông số hình ảnh và các điểm 3D thực tế. Chúng ta sẽ bắt đầu với các điểm 3D.
Tệp điểm bao gồm hàng nghìn điểm ở dạng 3D cùng với các màu liên quan. Các điểm được tập trung xung quanh cái được gọi là nguồn gốc thế giới, về cơ bản tọa độ x, y hoặc z của chúng dựa trên nơi chúng được quan sát có liên quan đến nguồn gốc thế giới này. Vị trí chính xác của nguồn gốc thế giới không quan trọng đối với mục đích của chúng tôi, vì vậy chúng tôi sẽ không tập trung vào nó vì nó có thể là bất kỳ điểm tùy ý nào trong không gian. Thay vào đó, điều cần thiết là phải biết bạn đang ở đâu trên thế giới liên quan đến nguồn gốc này. Đó là nơi tập tin hình ảnh trở nên hữu ích!
Nói rộng ra, tệp hình ảnh cho chúng ta biết hình ảnh được chụp ở đâu và hướng của máy ảnh, cả hai đều liên quan đến nguồn gốc thế giới. Vì vậy, các tham số chính mà chúng ta quan tâm là vectơ quaternion và vectơ tịnh tiến. Vectơ quaternion mô tả chuyển động quay của digital camera trong không gian bằng cách sử dụng 4 giá trị float riêng biệt có thể được sử dụng để tạo thành ma trận xoay (3Blue1Brown có một video tuyệt vời giải thích chính xác quaternion là gì đây). Sau đó, vectơ dịch cho chúng ta biết vị trí của máy ảnh so với điểm gốc. Cùng với nhau, các tham số này tạo thành ma trận bên ngoài, với các giá trị quaternion được sử dụng để tính toán ma trận xoay 3×3 (công thức) và vectơ dịch được thêm vào ma trận này.
Ma trận bên ngoài chuyển các điểm từ không gian thế giới (tọa độ trong tệp điểm) sang không gian digital camera, biến digital camera trở thành trung tâm mới của thế giới. Ví dụ: nếu máy ảnh được di chuyển lên 2 đơn vị theo hướng y mà không quay, chúng ta chỉ cần trừ 2 đơn vị khỏi tọa độ y của tất cả các điểm để thu được các điểm trong hệ tọa độ mới.
Khi chúng ta chuyển đổi tọa độ từ không gian thế giới sang không gian digital camera, chúng ta vẫn có vectơ 3D, trong đó tọa độ z biểu thị độ sâu trong chế độ xem của digital camera. Thông tin độ sâu này rất quan trọng để xác định thứ tự của các biểu tượng mà chúng ta cần để hiển thị sau này.
Chúng tôi kết thúc bài kiểm tra COLMAP bằng cách giải thích tệp thông số máy ảnh. Tệp digital camera cung cấp các thông số như chiều cao, chiều rộng, tiêu cự (x và y) và độ lệch (x và y). Sử dụng các tham số này, chúng ta có thể soạn ma trận nội tại, biểu thị tiêu cự theo hướng x và y và tọa độ điểm chính.
Nếu bạn hoàn toàn không quen với ma trận máy ảnh, tôi sẽ chỉ cho bạn Nguyên tắc đầu tiên của Bài giảng Thị giác máy tính được đưa ra bởi Shree Nayar. Đặc biệt là Pinhole và Phép chiếu tương lai bài học tiếp theo là ma trận bên trong và bên ngoài bài học.
Ma trận nội tại được sử dụng để chuyển đổi các điểm từ tọa độ digital camera (thu được bằng ma trận bên ngoài) sang mặt phẳng hình ảnh 2D, tức là. những gì bạn coi là “hình ảnh” của mình. Chỉ riêng các điểm trong tọa độ máy ảnh không cho biết diện mạo của chúng trong ảnh vì độ sâu phải được phản ánh để đánh giá chính xác những gì máy ảnh sẽ nhìn thấy.
Để chuyển đổi các điểm COLMAP thành hình ảnh 2D, trước tiên chúng tôi chiếu chúng thành tọa độ digital camera bằng ma trận bên ngoài, sau đó chiếu chúng thành 2D bằng ma trận bên trong. Tuy nhiên, một chi tiết quan trọng là chúng tôi sử dụng tọa độ đồng nhất cho quá trình này. Ma trận bên ngoài là 4×4, trong khi điểm đầu vào của chúng tôi là 3×1, vì vậy chúng tôi xếp chồng 1 với các điểm đầu vào để tạo thành 4×1.
Đây là quá trình từng bước:
- Chuyển đổi điểm thành tọa độ digital camera: nhân ma trận bên ngoài 4×4 với vectơ điểm 4×1.
- Chuyển đổi sang tọa độ hình ảnh: nhân ma trận nội tại 3×4 với vectơ 4×1 thu được.
Điều này dẫn đến một ma trận 3×1. Để có được tọa độ 2D cuối cùng, chúng ta chia cho tọa độ thứ ba của ma trận 3×1 này và thu được tọa độ x và y trong ảnh! Bạn có thể thấy chính xác điều này sẽ trông như thế nào đối với hình ảnh số 100 và mã để sao chép kết quả được hiển thị bên dưới.
def get_intrinsic_matrix(
f_x: float, f_y: float, c_x: float, c_y: float
) -> torch.Tensor:
"""
Get the homogenous intrinsic matrix for the digital camera
"""
return torch.Tensor(
(
(f_x, 0, c_x, 0),
(0, f_y, c_y, 0),
(0, 0, 1, 0),
)
)def get_extrinsic_matrix(R: torch.Tensor, t: torch.Tensor) -> torch.Tensor:
"""
Get the homogenous extrinsic matrix for the digital camera
"""
Rt = torch.zeros((4, 4))
Rt(:3, :3) = R
Rt(:3, 3) = t
Rt(3, 3) = 1.0
return Rt
def project_points(
factors: torch.Tensor, intrinsic_matrix: torch.Tensor, extrinsic_matrix: torch.Tensor
) -> torch.Tensor:
"""
Undertaking the factors to the picture aircraft
Args:
factors: Nx3 tensor
intrinsic_matrix: 3x4 tensor
extrinsic_matrix: 4x4 tensor
"""
homogeneous = torch.ones((4, factors.form(0)), system=factors.system)
homogeneous(:3, :) = factors.T
projected_to_camera_perspective = extrinsic_matrix @ homogeneous
projected_to_image_plane = (intrinsic_matrix @ projected_to_camera_perspective).T # Nx4
x = projected_to_image_plane(:, 0) / projected_to_image_plane(:, 2)
y = projected_to_image_plane(:, 1) / projected_to_image_plane(:, 2)
return x, y
colmap_path = "treehill/sparse/0"
reconstruction = pycolmap.Reconstruction(colmap_path)
points3d = reconstruction.points3D
photographs = read_images_binary(f"{colmap_path}/photographs.bin")
cameras = reconstruction.cameras
all_points3d = ()
all_point_colors = ()
for idx, level in enumerate(points3d.values()):
if level.monitor.size() >= 2:
all_points3d.append(level.xyz)
all_point_colors.append(level.colour)
gaussians = Gaussians(
torch.Tensor(all_points3d),
torch.Tensor(all_point_colors),
model_path="point_clouds"
)
# we are going to study the one hundredth picture
image_num = 100
image_dict = read_image_file(colmap_path)
camera_dict = read_camera_file(colmap_path)
# convert quaternion to rotation matrix
rotation_matrix = build_rotation(torch.Tensor(image_dict(image_num).qvec).unsqueeze(0))
translation = torch.Tensor(image_dict(image_num).tvec).unsqueeze(0)
extrinsic_matrix = get_extrinsic_matrix(
rotation_matrix, translation
)
focal_x, focal_y = camera_dict(image_dict(image_num).camera_id).params(:2)
c_x, c_y = camera_dict(image_dict(image_num).camera_id).params(2:4)
intrinsic_matrix = get_intrinsic_matrix(focal_x, focal_y, c_x, c_y)
factors = project_points(gaussians.factors, intrinsic_matrix, extrinsic_matrix)
Để xem xét, giờ đây chúng tôi có thể lấy bất kỳ tập hợp điểm và dự án 3D nào mà chúng sẽ xuất hiện trên mặt phẳng hình ảnh 2D miễn là chúng tôi có các thông số vị trí và digital camera khác nhau mà chúng tôi cần! Với điều đó trong tay, chúng ta có thể tiếp tục tìm hiểu phần “gaussian” của việc phân chia gaussian trong phần 2.
[ad_2]
Source link