-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
abd232e
commit 4c1080f
Showing
10 changed files
with
306 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
from coclico.malt0.malt0 import MALT0 | ||
from coclico.mobj0.mobj0 import MOBJ0 | ||
from coclico.mpap0.mpap0 import MPAP0 | ||
from coclico.mpla0.mpla0 import MPLA0 | ||
|
||
METRICS = {"mpap0": MPAP0, "mpla0": MPLA0, "malt0": MALT0} | ||
METRICS = {"mpap0": MPAP0, "mpla0": MPLA0, "malt0": MALT0, "mobj0": MOBJ0} |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
from pathlib import Path | ||
from typing import Dict, List | ||
|
||
import pandas as pd | ||
from gpao.job import Job | ||
|
||
from coclico.metrics.metric import Metric | ||
|
||
|
||
class MOBJ0(Metric): | ||
"""Metric MOBJ0 (for "Métrique par objet 0") | ||
TODO Description | ||
See doc/mobj0.md | ||
""" | ||
|
||
# Pixel size for occupancy map | ||
pixel_size = 0.5 | ||
metric_name = "mobj0" | ||
|
||
def create_metric_intrinsic_one_job(self, name: str, input: Path, output: Path, is_ref: bool): | ||
raise NotImplementedError | ||
|
||
def create_metric_relative_to_ref_jobs( | ||
self, name: str, out_c1: Path, out_ref: Path, output: Path, c1_jobs: List[Job], ref_jobs: List[Job] | ||
) -> Job: | ||
raise NotImplementedError | ||
|
||
@staticmethod | ||
def compute_note(metric_df: pd.DataFrame, note_config: Dict): | ||
raise NotImplementedError |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import argparse | ||
import logging | ||
from pathlib import Path | ||
|
||
import geopandas as gpd | ||
import numpy as np | ||
import pandas as pd | ||
import rasterio | ||
from osgeo import gdal | ||
from rasterio.features import shapes as rasterio_shapes | ||
from shapely.geometry import shape as shapely_shape | ||
|
||
import coclico.io | ||
from coclico.metrics.occupancy_map import create_occupancy_map_array, read_las | ||
from coclico.mobj0.mobj0 import MOBJ0 | ||
|
||
gdal.UseExceptions() | ||
|
||
|
||
def create_objects_array(las_file, pixel_size, class_weights): | ||
xs, ys, classifs, crs = read_las(las_file) | ||
|
||
binary_maps, x_min, y_max = create_occupancy_map_array(xs, ys, classifs, pixel_size, class_weights) | ||
|
||
return binary_maps, crs, x_min, y_max | ||
|
||
|
||
def vectorize_occupancy_map(binary_maps, crs, x_min, y_max, pixel_size): | ||
# Create empty dataframe | ||
gdf_list = [] | ||
|
||
for ii, map_layer in enumerate(binary_maps): | ||
shapes_layer = rasterio_shapes( | ||
map_layer, | ||
connectivity=8, | ||
transform=rasterio.transform.from_origin( | ||
x_min - pixel_size / 2, y_max + pixel_size / 2, pixel_size, pixel_size | ||
), | ||
) | ||
|
||
geometries = [shapely_shape(shapedict) for shapedict, value in shapes_layer if value != 0] | ||
nb_geometries = len(geometries) | ||
gdf_list.append( | ||
gpd.GeoDataFrame( | ||
{"layer": ii * np.ones(nb_geometries), "geometry": geometries}, | ||
geometry="geometry", | ||
crs=crs, | ||
) | ||
) | ||
|
||
gdf = pd.concat(gdf_list) | ||
|
||
return gdf | ||
|
||
|
||
def compute_metric_intrinsic(las_file: Path, config_file: Path, output_geojson: Path, pixel_size: float = 0.5): | ||
config_dict = coclico.io.read_config_file(config_file) | ||
class_weights = config_dict[MOBJ0.metric_name]["weights"] | ||
output_geojson.parent.mkdir(parents=True, exist_ok=True) | ||
obj_array, crs, x_min, y_max = create_objects_array(las_file, pixel_size, class_weights) | ||
polygons_gdf = vectorize_occupancy_map(obj_array, crs, x_min, y_max, pixel_size) | ||
polygons_gdf.to_file(output_geojson) | ||
|
||
|
||
def parse_args(): | ||
parser = argparse.ArgumentParser("Run malt0 intrinsic metric on one tile") | ||
parser.add_argument("-i", "--input-file", type=Path, required=True, help="Path to the LAS file") | ||
parser.add_argument("-o", "--output-geojson", type=Path, required=True, help="Path to the output geojson") | ||
parser.add_argument( | ||
"-c", | ||
"--config-file", | ||
type=Path, | ||
required=True, | ||
help="Coclico configuration file", | ||
) | ||
parser.add_argument( | ||
"-p", "--pixel-size", type=float, required=True, help="Pixel size of the intermediate occupancy map" | ||
) | ||
return parser.parse_args() | ||
|
||
|
||
if __name__ == "__main__": | ||
args = parse_args() | ||
logging.basicConfig(format="%(message)s", level=logging.DEBUG) | ||
compute_metric_intrinsic( | ||
las_file=Path(args.input_file), | ||
config_file=args.config_file, | ||
output_geojson=Path(args.output_geojson), | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import argparse | ||
import logging | ||
from pathlib import Path | ||
|
||
import pandas as pd | ||
|
||
from coclico.config import csv_separator | ||
from coclico.io import read_config_file | ||
from coclico.mobj0.mobj0 import MOBJ0 | ||
|
||
|
||
def compute_metric_relative( | ||
c1_dir: Path, ref_dir: Path, occupancy_dir: Path, config_file: str, output_csv: Path, output_csv_tile: Path | ||
): | ||
"""Compute metrics that describe the difference between c1 and ref height maps. | ||
The occupancy map is used to mask the pixels for which the difference is computed | ||
The metrics are: | ||
- mean_diff: the average difference in z between the height maps | ||
- max_diff: the maximum difference in z between the height maps | ||
- std_diff: the standard deviation of the difference in z betweeen the height maps | ||
These metrics are stored tile by tile and class by class in the output_csv_tile file | ||
These metrics are stored class by class for the whole data in the output_csv file | ||
Args: | ||
c1_dir (Path): path to the c1 classification directory, | ||
where there are json files with the result of mpap0 intrinsic metric | ||
ref_dir (Path): path to the reference classification directory, | ||
where there are json files with the result of mpap0 intrinsic metric | ||
class_weights (Dict): class weights dict | ||
output_csv (Path): path to output csv file | ||
output_csv_tile (Path): path to output csv file, result by tile | ||
""" | ||
config_dict = read_config_file(config_file) | ||
class_weights = config_dict[MOBJ0.metric_name]["weights"] | ||
classes = sorted(class_weights.keys()) | ||
classes | ||
csv_data = [] | ||
|
||
df = pd.DataFrame(csv_data) | ||
df.to_csv(output_csv, index=False, sep=csv_separator) | ||
|
||
logging.debug(df.to_markdown()) | ||
raise NotImplementedError | ||
|
||
|
||
def parse_args(): | ||
parser = argparse.ArgumentParser("Run malt0 metric on one tile") | ||
parser.add_argument( | ||
"-i", | ||
"--input-dir", | ||
required=True, | ||
type=Path, | ||
help="Path to the classification directory, \ | ||
where there are tif files with the result of malt0 intrinsic metric (MNx for each class)", | ||
) | ||
raise NotImplementedError | ||
return parser.parse_args() | ||
|
||
|
||
if __name__ == "__main__": | ||
args = parse_args() | ||
logging.basicConfig(format="%(message)s", level=logging.DEBUG) | ||
compute_metric_relative( | ||
c1_dir=Path(args.input_dir), | ||
ref_dir=Path(args.ref_dir), | ||
occupancy_dir=Path(args.occupancy_dir), | ||
config_file=args.config_file, | ||
output_csv=Path(args.output_csv), | ||
output_csv_tile=Path(args.output_csv_tile), | ||
) | ||
raise NotImplementedError |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ dependencies: | |
- laspy | ||
- rasterio | ||
- pandas | ||
- geopandas | ||
- tabulate | ||
- requests | ||
- pytest | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -99,3 +99,9 @@ malt0: | |
max_point: | ||
metric: 0.5 | ||
note: 0 | ||
|
||
mobj0: | ||
weights: | ||
"6": 2 | ||
"1": 1 | ||
notes: {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import shutil | ||
from pathlib import Path | ||
|
||
import pytest | ||
|
||
import coclico.io as io | ||
from coclico.mobj0.mobj0 import MOBJ0 | ||
|
||
pytestmark = pytest.mark.docker | ||
|
||
TMP_PATH = Path("./tmp/mobj0") | ||
CONFIG_FILE_METRICS = Path("./test/configs/config_test_metrics.yaml") | ||
|
||
|
||
def setup_module(module): | ||
if TMP_PATH.is_dir(): | ||
shutil.rmtree(TMP_PATH) | ||
|
||
|
||
def generate_metric_dataframes(): | ||
raise NotImplementedError | ||
|
||
|
||
def test_compute_note(): | ||
input_df, expected_out = generate_metric_dataframes() | ||
notes_config = io.read_config_file(CONFIG_FILE_METRICS)["mobj0"]["notes"] | ||
out_df = MOBJ0.compute_note(input_df, notes_config) | ||
assert out_df.equals(expected_out) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
import logging | ||
import shutil | ||
import subprocess as sp | ||
from pathlib import Path | ||
|
||
import geopandas as gpd | ||
import pytest | ||
|
||
import coclico.io | ||
from coclico.mobj0 import mobj0_intrinsic | ||
|
||
pytestmark = pytest.mark.docker | ||
|
||
TMP_PATH = Path("./tmp/mobj0_intrinsic") | ||
CONFIG_FILE_METRICS = Path("./test/configs/config_test_metrics.yaml") | ||
|
||
|
||
def setup_module(module): | ||
if TMP_PATH.is_dir(): | ||
shutil.rmtree(TMP_PATH) | ||
|
||
|
||
def test_compute_metric_intrinsic(ensure_test1_data): | ||
las_file = Path("./data/test1/niv1/tile_splitted_2818_32247.laz") | ||
pixel_size = 0.5 | ||
output_geojson = TMP_PATH / "intrinsic" / "unit_test_mpla0_intrinsic.geojson" | ||
config = coclico.io.read_config_file(CONFIG_FILE_METRICS) | ||
nb_layers = len(config["mobj0"]["weights"]) | ||
|
||
mobj0_intrinsic.compute_metric_intrinsic(las_file, CONFIG_FILE_METRICS, output_geojson, pixel_size=pixel_size) | ||
|
||
assert output_geojson.exists() | ||
gdf = gpd.read_file(output_geojson) | ||
logging.debug(gdf.to_markdown()) | ||
assert len(gdf.index) > 0 | ||
assert len(set(gdf["layer"])) == nb_layers | ||
|
||
|
||
def test_run_main(ensure_test1_data): | ||
pixel_size = 0.5 | ||
input_file = Path("./data/test1/niv1/tile_splitted_2818_32247.laz") | ||
output_geojson = TMP_PATH / "intrinsic" / "tile_splitted_2818_32247.geojson" | ||
|
||
cmd = f"""python -m coclico.mobj0.mobj0_intrinsic \ | ||
--input-file {input_file} \ | ||
--output-geojson {output_geojson} \ | ||
--config-file {CONFIG_FILE_METRICS} \ | ||
--pixel-size {pixel_size} | ||
""" | ||
sp.run(cmd, shell=True, check=True) | ||
|
||
logging.info(cmd) | ||
|
||
assert output_geojson.exists() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import shutil | ||
from pathlib import Path | ||
|
||
import pytest | ||
|
||
pytestmark = pytest.mark.docker | ||
|
||
TMP_PATH = Path("./tmp/mobj0_relative") | ||
CONFIG_FILE_METRICS = Path("./test/configs/config_test_metrics.yaml") | ||
|
||
|
||
def setup_module(module): | ||
if TMP_PATH.is_dir(): | ||
shutil.rmtree(TMP_PATH) | ||
|
||
|
||
def test_compute_metric_relative(ensure_mobj0_data): | ||
raise NotImplementedError | ||
|
||
|
||
def test_run_main(ensure_mobj0_data): | ||
raise NotImplementedError |