Skip to content

Commit 9cd3196

Browse files
authored
Merge pull request #10 from IGNF/debug/indices-map
Debug/indices map
2 parents 24c828b + b0d2e76 commit 9cd3196

6 files changed

Lines changed: 131 additions & 32 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# CHANGELOG
22

3+
- génération de la carte d'indice même quand il n'y a pas de points à ajouter
4+
35
## 1.1.1
46
- lint
57
- ajout de pre-commit hooks pour appliquer le lint au moment des commits

environment.yml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ dependencies:
99
- numpy
1010
- geopandas==0.*
1111
- shapely>=2.0.3
12+
- gdal
13+
- pdal>=2.8
14+
- python-pdal
1215
- rasterio
1316
# ------------- logging ------------- #
1417
- loguru
@@ -18,4 +21,6 @@ dependencies:
1821
# ----------- linting --------------- #
1922
- pre-commit
2023
- black
21-
- flake8
24+
- flake8
25+
- pip:
26+
- ign-pdal-tools==1.8.1

patchwork/indices_map.py

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,38 +8,36 @@
88
from rasterio.transform import from_origin
99

1010
from patchwork.constants import PATCH_X_STR, PATCH_Y_STR
11-
from patchwork.tools import get_tile_origin_from_pointcloud
1211

1312

14-
def create_indices_grid(config: DictConfig, df_points: DataFrame) -> np.ndarray:
13+
def create_indices_grid(config: DictConfig, df_points: DataFrame, corner_x: int, corner_y: int) -> np.ndarray:
1514
"""create a binary grid matching the tile the points of df_points are from, where each patch is equal to:
1615
1 if the patch has at least one point of df_points
1716
0 if the patch has no point from df_points
1817
"""
1918
size_grid = int(config.TILE_SIZE / config.PATCH_SIZE)
2019

21-
corner_x, corner_y = get_tile_origin_from_pointcloud(config, df_points)
20+
grid = np.zeros((size_grid, size_grid))
2221

23-
list_coordinates_x = np.int32((df_points.x - corner_x) / config.PATCH_SIZE)
24-
list_coordinates_y = np.int32((corner_y - df_points.y) / config.PATCH_SIZE)
22+
if not df_points.empty:
23+
list_coordinates_x = np.int32((df_points.x - corner_x) / config.PATCH_SIZE)
24+
list_coordinates_y = np.int32((corner_y - df_points.y) / config.PATCH_SIZE)
2525

26-
# edge cases where points are exactly on the... edge of the tile, but still valid
27-
list_coordinates_x[list_coordinates_x == size_grid] = size_grid - 1
28-
list_coordinates_y[list_coordinates_y == size_grid] = size_grid - 1
26+
# edge cases where points are exactly on the... edge of the tile, but still valid
27+
list_coordinates_x[list_coordinates_x == size_grid] = size_grid - 1
28+
list_coordinates_y[list_coordinates_y == size_grid] = size_grid - 1
2929

30-
grid = np.zeros((size_grid, size_grid))
30+
grid[list_coordinates_x, list_coordinates_y] = 1
3131

32-
grid[list_coordinates_x, list_coordinates_y] = 1
3332
return grid.transpose()
3433

3534

36-
def create_indices_map(config: DictConfig, df_points: DataFrame):
35+
def create_indices_map(config: DictConfig, df_points: DataFrame, corner_x: int, corner_y: int):
3736
"""
3837
Save a binary grid for the tile into a geotiff
3938
"""
40-
corner_x, corner_y = get_tile_origin_from_pointcloud(config, df_points)
4139

42-
grid = create_indices_grid(config, df_points)
40+
grid = create_indices_grid(config, df_points, corner_x, corner_y)
4341
os.makedirs(config.filepath.OUTPUT_INDICES_MAP_DIR, exist_ok=True)
4442
output_indices_map_path = os.path.join(
4543
config.filepath.OUTPUT_INDICES_MAP_DIR, config.filepath.OUTPUT_INDICES_MAP_NAME

patchwork/patchwork.py

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import pandas as pd
99
from laspy import LasReader, ScaleAwarePointRecord
1010
from omegaconf import DictConfig
11+
from pdaltools.las_info import get_tile_origin_using_header_info
1112

1213
import patchwork.constants as c
1314
from patchwork.indices_map import create_indices_map
@@ -125,20 +126,20 @@ def get_field_from_header(las_file: LasReader) -> List[str]:
125126
return [dimension.name.lower() for dimension in header.point_format.dimensions]
126127

127128

128-
def test_field_exists(file_path: str, colmun: str) -> bool:
129+
def test_field_exists(file_path: str, column: str) -> bool:
129130
output_file = laspy.read(file_path)
130-
return colmun in get_field_from_header(output_file)
131+
return column in get_field_from_header(output_file)
131132

132133

133134
def append_points(config: DictConfig, extra_points: pd.DataFrame):
134135
# get field to copy :
135136
recipient_filepath = os.path.join(config.filepath.RECIPIENT_DIRECTORY, config.filepath.RECIPIENT_NAME)
136-
ouput_filepath = os.path.join(config.filepath.OUTPUT_DIR, config.filepath.OUTPUT_NAME)
137+
output_filepath = os.path.join(config.filepath.OUTPUT_DIR, config.filepath.OUTPUT_NAME)
137138
with laspy.open(recipient_filepath) as recipient_file:
138139
recipient_fields_list = get_field_from_header(recipient_file)
139140

140141
# get fields that are in the donor file we can transmit to the recipient without problem
141-
# classification is in the fields to exclude because it will be copy in a special way
142+
# classification is in the fields to exclude because it will be copied in a special way
142143
fields_to_exclude = [
143144
c.PATCH_X_STR,
144145
c.PATCH_Y_STR,
@@ -152,7 +153,7 @@ def append_points(config: DictConfig, extra_points: pd.DataFrame):
152153
if (field.lower() in extra_points.columns) and (field.lower() not in fields_to_exclude)
153154
]
154155

155-
copy2(recipient_filepath, ouput_filepath)
156+
copy2(recipient_filepath, output_filepath)
156157

157158
if len(extra_points) == 0: # if no point to add, the job is done after copying the recipient file
158159
return
@@ -165,11 +166,11 @@ def append_points(config: DictConfig, extra_points: pd.DataFrame):
165166
column name in {recipient_filepath}"
166167
)
167168
new_column_type = get_type(config.NEW_COLUMN_SIZE)
168-
output_las = laspy.read(ouput_filepath)
169+
output_las = laspy.read(output_filepath)
169170
output_las.add_extra_dim(laspy.ExtraBytesParams(name=config.NEW_COLUMN, type=new_column_type))
170-
output_las.write(ouput_filepath)
171+
output_las.write(output_filepath)
171172

172-
with laspy.open(ouput_filepath, mode="a") as output_las:
173+
with laspy.open(output_filepath, mode="a") as output_las:
173174
# put in a new table all extra points and their values on the fields we want to keep
174175
new_points = laspy.ScaleAwarePointRecord.zeros(extra_points.shape[0], header=output_las.header)
175176
for field in fields_to_keep:
@@ -227,12 +228,15 @@ def get_donor_path(config: DictConfig) -> Tuple[str, str]:
227228

228229
def patchwork(config: DictConfig):
229230
_, donor_name = get_donor_path(config)
230-
if not donor_name: # if no matching donor, we simply copy the recipient to the output without doing anything
231-
recipient_filepath = os.path.join(config.filepath.RECIPIENT_DIRECTORY, config.filepath.RECIPIENT_NAME)
232-
ouput_filepath = os.path.join(config.filepath.OUTPUT_DIR, config.filepath.OUTPUT_NAME)
233-
copy2(recipient_filepath, ouput_filepath)
234-
return
231+
recipient_filepath = os.path.join(config.filepath.RECIPIENT_DIRECTORY, config.filepath.RECIPIENT_NAME)
232+
if donor_name:
233+
complementary_bd_points = get_complementary_points(config)
234+
append_points(config, complementary_bd_points)
235+
236+
else: # if no matching donor, we simply copy the recipient to the output without doing anything
237+
output_filepath = os.path.join(config.filepath.OUTPUT_DIR, config.filepath.OUTPUT_NAME)
238+
copy2(recipient_filepath, output_filepath)
239+
complementary_bd_points = pd.DataFrame() # No points to add
235240

236-
complementary_bd_points = get_complementary_points(config)
237-
append_points(config, complementary_bd_points)
238-
create_indices_map(config, complementary_bd_points)
241+
corner_x, corner_y = get_tile_origin_using_header_info(filename=recipient_filepath, tile_width=config.TILE_SIZE)
242+
create_indices_map(config, complementary_bd_points, corner_x, corner_y)

test/test_indices_map.py

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515

1616
PATCH_SIZE = 1
1717
TILE_SIZE = 3
18+
CORNER_X = 0
19+
CORNER_Y = 3
1820

1921
DATA_POINTS = {"x": [0.0, 1.5, 3, 1.5, 2.5], "y": [0.0, 0.5, 0.5, 1.5, 3]}
2022
# we want y=0 at the bottom, but in a ndarray it's at the top, so grid['y'] = SIZE_Y - data_points['y']
@@ -28,7 +30,7 @@ def test_create_indices_points():
2830
config_name="configs_patchwork.yaml", overrides=[f"PATCH_SIZE={PATCH_SIZE}", f"TILE_SIZE={TILE_SIZE}"]
2931
)
3032
df_points = pd.DataFrame(data=DATA_POINTS)
31-
grid = create_indices_grid(config, df_points)
33+
grid = create_indices_grid(config, df_points, CORNER_X, CORNER_Y)
3234

3335
grid = grid.transpose() # indices aren't read the way we want otherwise
3436

@@ -54,18 +56,42 @@ def test_create_indices_map(tmp_path_factory):
5456
)
5557

5658
df_points = pd.DataFrame(data=DATA_POINTS)
57-
create_indices_map(config, df_points)
59+
create_indices_map(config, df_points, CORNER_X, CORNER_Y)
5860
raster = rs.open(os.path.join(tmp_file_dir, tmp_file_name))
5961
grid = raster.read()
6062

6163
grid = grid.transpose() # indices aren't read the way we want otherwise
64+
print(grid)
6265

6366
for point in POINTS_IN_GRID:
6467
assert grid[point] == 1
6568
for point in POINTS_NOT_IN_GRID:
6669
assert grid[point] == 0
6770

6871

72+
def test_create_indices_map_no_added_points(tmp_path_factory):
73+
tmp_file_dir = tmp_path_factory.mktemp("data")
74+
tmp_file_name = "empty_indices.tif"
75+
76+
with initialize(version_base="1.2", config_path="../configs"):
77+
config = compose(
78+
config_name="configs_patchwork.yaml",
79+
overrides=[
80+
f"PATCH_SIZE={PATCH_SIZE}",
81+
f"TILE_SIZE={TILE_SIZE}",
82+
f"filepath.OUTPUT_INDICES_MAP_DIR={tmp_file_dir}",
83+
f"filepath.OUTPUT_INDICES_MAP_NAME={tmp_file_name}",
84+
],
85+
)
86+
87+
df_points = pd.DataFrame() # Empty dataframe (no points to add)
88+
create_indices_map(config, df_points, CORNER_X, CORNER_Y)
89+
raster = rs.open(os.path.join(tmp_file_dir, tmp_file_name))
90+
grid = raster.read()
91+
92+
assert np.all(grid == 0)
93+
94+
6995
def test_read_indices_map(tmp_path_factory):
7096
tmp_file_dir = tmp_path_factory.mktemp("data")
7197
tmp_file_name = "indices.tif"

test/test_patchwork.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
get_field_from_header,
1717
get_selected_classes_points,
1818
get_type,
19+
patchwork,
1920
)
2021
from patchwork.tools import get_tile_origin_from_pointcloud
2122

@@ -366,3 +367,66 @@ def test_get_donor_path(tmp_path_factory):
366367
donor_dir, donor_name = get_donor_path(config)
367368
assert donor_dir == DONOR_MORE_FIELDS_TEST_DIR
368369
assert donor_name == DONOR_MORE_FIELDS_TEST_NAME
370+
371+
372+
def test_patchwork_default(tmp_path_factory):
373+
tmp_file_dir = tmp_path_factory.mktemp("data")
374+
tmp_output_las_name = "result_patchwork.laz"
375+
tmp_output_indices_map_name = "result_patchwerk_indices.tif"
376+
377+
with initialize(version_base="1.2", config_path="../configs"):
378+
config = compose(
379+
config_name="configs_patchwork.yaml",
380+
overrides=[
381+
f"filepath.RECIPIENT_DIRECTORY={RECIPIENT_TEST_DIR}",
382+
f"filepath.RECIPIENT_NAME={RECIPIENT_TEST_NAME}",
383+
f"filepath.DONOR_DIRECTORY={DONOR_TEST_DIR}",
384+
f"filepath.DONOR_NAME={DONOR_TEST_NAME}",
385+
f"filepath.OUTPUT_DIR={tmp_file_dir}",
386+
f"filepath.OUTPUT_NAME={tmp_output_las_name}",
387+
f"filepath.OUTPUT_INDICES_MAP_DIR={tmp_file_dir}",
388+
f"filepath.OUTPUT_INDICES_MAP_NAME={tmp_output_indices_map_name}",
389+
],
390+
)
391+
patchwork(config)
392+
recipient_path = os.path.join(config.filepath.RECIPIENT_DIRECTORY, config.filepath.RECIPIENT_NAME)
393+
output_path = os.path.join(tmp_file_dir, tmp_output_las_name)
394+
indices_map_path = os.path.join(tmp_file_dir, tmp_output_indices_map_name)
395+
assert os.path.isfile(output_path)
396+
assert os.path.isfile(indices_map_path)
397+
with laspy.open(recipient_path) as las_file:
398+
recipient_points = las_file.read().points
399+
with laspy.open(output_path) as las_file:
400+
output_points = las_file.read().points
401+
assert len(output_points) > len(recipient_points)
402+
403+
404+
def test_patchwork_empty_donor(tmp_path_factory):
405+
tmp_file_dir = tmp_path_factory.mktemp("data")
406+
tmp_output_las_name = "result_patchwork.laz"
407+
tmp_output_indices_map_name = "result_patchwerk_indices.tif"
408+
409+
with initialize(version_base="1.2", config_path="../configs"):
410+
config = compose(
411+
config_name="configs_patchwork.yaml",
412+
overrides=[
413+
f"filepath.RECIPIENT_DIRECTORY={RECIPIENT_TEST_DIR}",
414+
f"filepath.RECIPIENT_NAME={RECIPIENT_TEST_NAME}",
415+
f"filepath.OUTPUT_DIR={tmp_file_dir}",
416+
f"filepath.OUTPUT_NAME={tmp_output_las_name}",
417+
f"filepath.OUTPUT_INDICES_MAP_DIR={tmp_file_dir}",
418+
f"filepath.OUTPUT_INDICES_MAP_NAME={tmp_output_indices_map_name}",
419+
],
420+
)
421+
patchwork(config)
422+
recipient_path = os.path.join(config.filepath.RECIPIENT_DIRECTORY, config.filepath.RECIPIENT_NAME)
423+
output_path = os.path.join(tmp_file_dir, tmp_output_las_name)
424+
indices_map_path = os.path.join(tmp_file_dir, tmp_output_indices_map_name)
425+
assert os.path.isfile(output_path)
426+
assert os.path.isfile(indices_map_path)
427+
with laspy.open(recipient_path) as las_file:
428+
recipient_points = las_file.read().points
429+
with laspy.open(output_path) as las_file:
430+
output_points = las_file.read().points
431+
432+
assert len(output_points) == len(recipient_points)

0 commit comments

Comments
 (0)