File size: 3,966 Bytes
0ca05b5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
import numpy as np
import pycolmap


def _create_camera_params(frame_idx, cam_matrices, model_type, distortion_coeffs=None):
    """Build camera parameter array for different model types."""
    if model_type == "PINHOLE":
        return np.array([
            cam_matrices[frame_idx][0, 0], cam_matrices[frame_idx][1, 1], 
            cam_matrices[frame_idx][0, 2], cam_matrices[frame_idx][1, 2]
        ])
    elif model_type == "SIMPLE_PINHOLE":
        focal_avg = (cam_matrices[frame_idx][0, 0] + cam_matrices[frame_idx][1, 1]) / 2
        return np.array([focal_avg, cam_matrices[frame_idx][0, 2], cam_matrices[frame_idx][1, 2]])
    elif model_type == "SIMPLE_RADIAL":
        raise NotImplementedError("SIMPLE_RADIAL model not supported")
    else:
        raise ValueError(f"Unsupported camera model: {model_type}")


def _setup_camera_object(frame_idx, cam_matrices, img_dims, model_type, use_shared):
    """Create and configure camera object."""
    if use_shared and frame_idx > 0:
        return None
    
    params = _create_camera_params(frame_idx, cam_matrices, model_type)
    return pycolmap.Camera(
        model=model_type, 
        width=img_dims[0], 
        height=img_dims[1], 
        params=params, 
        camera_id=frame_idx + 1
    )


def _process_frame_points(scene_points, point_coords, frame_idx):
    """Extract and process 2D points belonging to specific frame."""
    frame_mask = point_coords[:, 2].astype(np.int32) == frame_idx
    valid_indices = np.nonzero(frame_mask)[0]
    
    point2d_list = []
    for idx, batch_idx in enumerate(valid_indices):
        point3d_id = batch_idx + 1
        xy_coords = point_coords[batch_idx][:2]
        point2d_list.append(pycolmap.Point2D(xy_coords, point3d_id))
        
        # Update track information
        track = scene_points.points3D[point3d_id].track
        track.add_element(frame_idx + 1, idx)
    
    return point2d_list


def build_pycolmap_reconstruction(
    points,
    pixel_coords,
    point_colors,
    poses,
    intrinsics,
    image_size,
    shared_camera_model=False,
    camera_model="SIMPLE_PINHOLE",
):
    """
    Convert numpy arrays to pycolmap reconstruction format.
    
    Creates 3D scene structure without track optimization.
    Suitable for initialization of neural rendering methods.
    """
    num_frames = len(poses)
    num_points = len(points)
    
    scene = pycolmap.Reconstruction()
    
    # Add 3D points to scene
    for pt_idx in range(num_points):
        scene.add_point3D(points[pt_idx], pycolmap.Track(), point_colors[pt_idx])
    
    current_camera = None
    
    # Process each frame
    for frame_idx in range(num_frames):
        # Setup camera if needed
        if current_camera is None or not shared_camera_model:
            current_camera = _setup_camera_object(
                frame_idx, intrinsics, image_size, camera_model, shared_camera_model
            )
            scene.add_camera(current_camera)
        
        # Create pose transformation
        rotation_matrix = poses[frame_idx][:3, :3]
        translation_vec = poses[frame_idx][:3, 3]
        world_to_cam = pycolmap.Rigid3d(pycolmap.Rotation3d(rotation_matrix), translation_vec)
        
        # Create image object
        frame_image = pycolmap.Image(
            id=frame_idx + 1,
            name=f"frame_{frame_idx + 1}",
            camera_id=current_camera.camera_id,
            cam_from_world=world_to_cam
        )
        
        # Process 2D points for this frame
        frame_points = _process_frame_points(scene, pixel_coords, frame_idx)
        
        # Set image points and registration status
        try:
            frame_image.points2D = pycolmap.ListPoint2D(frame_points)
            frame_image.registered = True
        except:
            print(f"Warning: Frame {frame_idx + 1} has no valid points")
            frame_image.registered = False
        
        scene.add_image(frame_image)
    
    return scene