import torch


def depth_to_world(projection, depth):
    """ backprojects depth maps to point clouds
    Args:
        projection: 3x4 projection matrix
        depth: hxw depth map

    Returns:
        tensor of 3d points 3x(h*w)
    """

    # add row to projection 3x4 -> 4x4
    eye_row = torch.tensor([[0,0,0,1]]).type_as(depth)
    projection = torch.cat((projection, eye_row))

    # pixel grid
    py, px = torch.meshgrid(torch.arange(depth.size(-2)).type_as(depth),
                            torch.arange(depth.size(-1)).type_as(depth))
    pz = torch.ones_like(px)
    p = torch.cat((px.unsqueeze(0), py.unsqueeze(0), pz.unsqueeze(0), 
                   1/depth.unsqueeze(0)))

    # backproject
    P = (projection.inverse() @ p.view(4,-1)).view(p.size())
    P = P[:3]/P[3:]
    return P