//  [python]
def _depth_warping(depth_maps_1, depth_maps_2, img_masks, translation_vectors, rotation_matrices,
                   intrinsic_matrices, epsilon):
    # Generate a meshgrid for each depth map to calculate value
    # BxHxWxC
    depth_maps_1 = torch.mul(depth_maps_1, img_masks)
    depth_maps_2 = torch.mul(depth_maps_2, img_masks)

    depth_maps_1 = depth_maps_1.permute(0, 2, 3, 1)
    depth_maps_2 = depth_maps_2.permute(0, 2, 3, 1)
    img_masks = img_masks.permute(0, 2, 3, 1)

    num_batch, height, width, channels = depth_maps_1.shape

    y_grid, x_grid = torch.meshgrid(
        [torch.arange(start=0, end=height, dtype=torch.float32).cuda(),
         torch.arange(start=0, end=width, dtype=torch.float32).cuda()])

    x_grid = x_grid.reshape(1, height, width, 1)
    y_grid = y_grid.reshape(1, height, width, 1)

    ones_grid = torch.ones((1, height, width, 1), dtype=torch.float32).cuda()

    # intrinsic_matrix_inverse = intrinsic_matrix.inverse()
    eye = torch.eye(3).float().cuda().reshape(1, 3, 3).expand(intrinsic_matrices.shape[0], -1, -1)
    intrinsic_matrices_inverse, _ = torch.solve(eye, intrinsic_matrices)
    rotation_matrices_inverse = rotation_matrices.transpose(1, 2)

    # The following is when we have different intrinsic matrices for samples within a batch
    temp_mat = torch.bmm(intrinsic_matrices, rotation_matrices_inverse)
    W = torch.bmm(temp_mat, -translation_vectors)
    M = torch.bmm(temp_mat, intrinsic_matrices_inverse)

    mesh_grid = torch.cat((x_grid, y_grid, ones_grid), dim=-1).reshape(height, width, 3, 1)
    intermediate_result = torch.matmul(M.reshape(-1, 1, 1, 3, 3), mesh_grid).reshape(-1, height, width, 3)

    depth_maps_2_calculate = W.reshape(-1, 3).narrow(dim=-1, start=2, length=1).reshape(-1, 1, 1, 1) + torch.mul(
        depth_maps_1,
        intermediate_result.narrow(dim=-1, start=2, length=1).reshape(-1, height,
                                                                      width, 1))
    # expand operation doesn't allocate new memory (repeat does)
    depth_maps_2_calculate = torch.where(img_masks > 0.5, depth_maps_2_calculate, epsilon)
    depth_maps_2_calculate = torch.where(depth_maps_2_calculate > 0.0, depth_maps_2_calculate, epsilon)

    # This is the source coordinate in coordinate system 2 but ordered in coordinate system 1 in order to warp image 2 to coordinate system 1
    u_2 = (W.reshape(-1, 3).narrow(dim=-1, start=0, length=1).reshape(-1, 1, 1, 1) + torch.mul(depth_maps_1,
                                                                                               intermediate_result.narrow(
                                                                                                   dim=-1, start=0,
                                                                                                   length=1).reshape(-1,
                                                                                                                     height,
                                                                                                                     width,
                                                                                                                     1))) / (
              depth_maps_2_calculate)

    v_2 = (W.reshape(-1, 3).narrow(dim=-1, start=1, length=1).reshape(-1, 1, 1, 1) + torch.mul(depth_maps_1,
                                                                                               intermediate_result.narrow(
                                                                                                   dim=-1, start=1,
                                                                                                   length=1).reshape(-1,
                                                                                                                     height,
                                                                                                                     width,
                                                                                                                     1))) / (
              depth_maps_2_calculate)

    W_2 = torch.bmm(intrinsic_matrices, translation_vectors)
    M_2 = torch.bmm(torch.bmm(intrinsic_matrices, rotation_matrices), intrinsic_matrices_inverse)

    temp = torch.matmul(M_2.reshape(-1, 1, 1, 3, 3), mesh_grid).reshape(-1, height, width, 3).narrow(dim=-1, start=2,
                                                                                                     length=1).reshape(
        -1,
        height,
        width, 1)
    depth_maps_1_calculate = W_2.reshape(-1, 3).narrow(dim=-1, start=2, length=1).reshape(-1, 1, 1, 1) + torch.mul(
        depth_maps_2, temp)
    depth_maps_1_calculate = torch.mul(img_masks, depth_maps_1_calculate)

    u_2_flat = u_2.reshape(-1)
    v_2_flat = v_2.reshape(-1)

    warped_depth_maps_2 = _bilinear_interpolate(depth_maps_1_calculate, u_2_flat, v_2_flat).reshape(num_batch, 1,
                                                                                                    height,
                                                                                                    width)
    # binarize
    intersect_masks = torch.where(_bilinear_interpolate(img_masks, u_2_flat, v_2_flat) * img_masks >= 0.9,
                                  torch.tensor(1.0).float().cuda(),
                                  torch.tensor(0.0).float().cuda()).reshape(num_batch, 1, height, width)

    return [warped_depth_maps_2, intersect_masks]