def unproject_points2d(points2d, inv_K, scale=1.0):
    """
    Parameters
    ----------
    points2d: Tensor
        xy coordinates. shape=(N, ..., 2)
        E.g., (N, 2) or (N, K, 2) or (N, H, W, 2)

    inv_K: Tensor
        Inverted intrinsics; shape=(N, 3, 3)

    scale: float, default: 1.0
        Scaling factor.

    Returns
    -------
    Tensor:
        Unprojected 3D point. shape=(N, ..., 3)
        E.g., (N, 3) or (N, K, 3) or (N, H, W, 3)
    """
    points2d = homogenize_points(points2d)
    siz = points2d.size()
    points2d = points2d.view(-1, 3).unsqueeze(-1)  # (N, 3, 1)
    unprojected = torch.matmul(inv_K, points2d)  # (N, 3, 3) x (N, 3, 1) -> (N, 3, 1)
    unprojected = unprojected.view(siz)

    return unprojected * scale

    Parameters
    ----------
    points2d: Tensor
        xy coordinates. shape=(N, ..., 2)
        E.g., (N, 2) or (N, K, 2) or (N, H, W, 2)

    inv_K: Tensor
        Inverted intrinsics; shape=(N, 3, 3)

    scale: float, default: 1.0
        Scaling factor.

    Returns
    -------
    Tensor:
        Unprojected 3D point. shape=(N, ..., 3)
        E.g., (N, 3) or (N, K, 3) or (N, H, W, 3)
    
tridet/utils/geometry.py