Example #1
0
def test_resolution(clouds_list, expected_dsm, r=4):
    raster, _ = plyflatten_from_plyfiles_list(clouds_list, resolution=r)
    raster = raster[:, :, 0]

    reference, (rx, ry) = expected_dsm
    assert abs(raster.shape[0] * r - reference.shape[0] * rx) <= 2 * max(r, rx)
    assert abs(raster.shape[1] * r - reference.shape[1] * ry) <= 2 * max(r, ry)
Example #2
0
def test_plyflatten():
    # Test data
    f = data_path("input_ply/cloud.ply")
    raster, profile = plyflatten_from_plyfiles_list([f], resolution=0.4)
    test_raster = raster[:, :, 0]  # keep only band with height

    # Expected data
    e = data_path("expected_output/plyflatten/dsm_40cm.tiff")
    with rasterio.open(e) as src:
        expected_raster = src.read(1)
        expected_crs = src.crs
        expected_transform = src.transform
        expected_is_tiled = src.is_tiled
        expected_nodata = src.nodata

    # Check that both rasters are equal pixel-wise within a tolerance
    assert np.allclose(test_raster, expected_raster, equal_nan=True)

    # Check that both images have the same CRS
    test_crs = profile['crs']
    assert test_crs == expected_crs

    # Check that both images have the same transform
    test_transform = profile['transform']
    assert np.allclose(test_transform, expected_transform)

    test_is_tiled = profile['tiled']
    assert test_is_tiled == expected_is_tiled

    test_nodata = profile.get('nodata')
    if expected_nodata and math.isnan(expected_nodata):
        assert math.isnan(test_nodata)
    else:
        assert test_nodata == expected_nodata
Example #3
0
def main():
    parser = argparse.ArgumentParser(
        description=(f"{__title__}: {__description__}"))
    parser.add_argument("list_plys",
                        nargs="+",
                        help=("Space-separated list of .ply files"))
    parser.add_argument("dsm_path", help=("Path to output DSM file"))
    parser.add_argument(
        "--resolution",
        default=1,
        type=float,
        help=("Resolution of the DSM in meters (defaults to 1m)"),
    )
    args = parser.parse_args()
    raster, profile = plyflatten_from_plyfiles_list(args.list_plys,
                                                    args.resolution)
    raster = raster[:, :, 0]
    profile["dtype"] = raster.dtype
    profile["height"] = raster.shape[0]
    profile["width"] = raster.shape[1]
    profile["count"] = 1
    profile["driver"] = "GTiff"

    with rasterio.open(args.dsm_path, "w", **profile) as f:
        f.write(raster, 1)
Example #4
0
def test_std(clouds_list, expected_std):
    raster, _ = plyflatten_from_plyfiles_list(clouds_list,
                                              resolution=1,
                                              std=True)
    assert raster.shape[2] == 2
    raster = raster[:, :, 1]

    np.testing.assert_allclose(expected_std, raster, equal_nan=True)
Example #5
0
def plys_to_dsm(tile):
    """
    Generates DSM from plyfiles (cloud.ply)

    Args:
        tile: a dictionary that provides all you need to process a tile
    """
    out_dsm = os.path.join(tile['dir'], 'dsm.tif')
    out_conf = os.path.join(tile['dir'], 'confidence.tif')
    r = cfg['dsm_resolution']
    xmin, xmax, ymin, ymax = np.loadtxt(
        os.path.join(tile['dir'], "plyextrema.txt"))

    if not all(np.isfinite([xmin, xmax, ymin, ymax])):  # then the ply is empty
        return

    # compute xoff, yoff, xsize, ysize on a grid of unit r
    xoff = np.floor(xmin / r) * r
    xsize = int(1 + np.floor((xmax - xoff) / r))

    yoff = np.ceil(ymax / r) * r
    ysize = int(1 - np.floor((ymin - yoff) / r))

    roi = xoff, yoff, xsize, ysize

    clouds = [
        os.path.join(tile['dir'], n_dir, 'cloud.ply')
        for n_dir in tile['neighborhood_dirs']
    ]
    raster, profile = plyflatten_from_plyfiles_list(clouds,
                                                    resolution=r,
                                                    roi=roi,
                                                    radius=cfg['dsm_radius'],
                                                    sigma=cfg['dsm_sigma'])

    # save output image with utm georeferencing
    common.rasterio_write(out_dsm, raster[:, :, 0], profile=profile)

    # export confidence (optional)
    # note that the plys are assumed to contain the fields:
    # [x(float32), y(float32), z(float32), r(uint8), g(uint8), b(uint8), confidence(optional, float32)]
    # so the raster has 4 or 5 columns: [z, r, g, b, confidence (optional)]
    if raster.shape[-1] == 5:
        common.rasterio_write(out_conf, raster[:, :, 4], profile=profile)
Example #6
0
def main():
    parser = argparse.ArgumentParser(
        description=(f"{__title__}: {__description__}"))
    parser.add_argument("list_plys",
                        nargs="+",
                        help=("Space-separated list of .ply files"))
    parser.add_argument("dsm_path", help=("Path to output DSM file"))
    parser.add_argument(
        "--std", help=("Path to (optional) output standard deviation map"))
    parser.add_argument(
        "--cnt", help=("Path to (optional) output counts per grid point map"))
    parser.add_argument(
        "--resolution",
        default=1,
        type=float,
        help=("Resolution of the DSM in meters (defaults to 1m)"),
    )
    args = parser.parse_args()
    raster, profile = plyflatten_from_plyfiles_list(args.list_plys,
                                                    args.resolution,
                                                    std=args.std is not None
                                                    or args.cnt is not None)
    profile["dtype"] = raster.dtype
    profile["height"] = raster.shape[0]
    profile["width"] = raster.shape[1]
    profile["count"] = 1
    profile["driver"] = "GTiff"

    with rasterio.open(args.dsm_path, "w", **profile) as f:
        f.write(raster[:, :, 0], 1)

    if args.cnt:
        with rasterio.open(args.cnt, "w", **profile) as f:
            f.write(raster[:, :, -1], 1)

    if args.std:
        raster = raster[:, :, :-1]
        n = raster.shape[2]
        assert n % 2 == 0
        with rasterio.open(args.std, "w", **profile) as f:
            f.write(raster[:, :, n // 2], 1)
Example #7
0
def test_distributed_plyflatten():

    print('Running end2end with distributed plyflatten dsm ...')
    test_cfg = s2p.read_config_file(data_path('input_triplet/config.json'))
    s2p.main(test_cfg)

    outdir = test_cfg['out_dir']
    computed = common.gdal_read_as_array_with_nans(
        os.path.join(outdir, 'dsm.tif'))

    print('Running plyflatten dsm reference ...')

    clouds_list = glob.glob(
        os.path.join(outdir, "tiles", "*", "*", "cloud.ply"))

    res = test_cfg['dsm_resolution']
    roi = None

    raster, _ = plyflatten_from_plyfiles_list(clouds_list,
                                              resolution=res,
                                              roi=roi)
    expected = raster[:, :, 0]

    compare_dsm(computed, expected, 0, 0)
Example #8
0
def test_plyflatten_from_plyfiles_list(clouds_list, expected_dsm):
    raster, _ = plyflatten_from_plyfiles_list(clouds_list, resolution=2)
    raster = raster[:, :, 0]

    expected_raster, _ = expected_dsm
    np.testing.assert_allclose(expected_raster, raster, equal_nan=True)
Example #9
0
def test_resolution(clouds_list, expected_raster):
    raster, _ = plyflatten_from_plyfiles_list(clouds_list, resolution=4)
    raster = raster[:, :, 0]

    assert raster.shape[0] == expected_raster.shape[0] / 2
    assert raster.shape[1] == expected_raster.shape[1] / 2