Borner le comblement du MNT à l'enveloppe des points, ajouter la couche précision et un affichage relief/précision, encoder les sous-tuiles une seule fois en q75

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Antoine Jacquin
2026-09-27 15:07:04 +02:00
parent c5097e21a0
commit 90dbe61f3b
17 changed files with 994 additions and 593 deletions

View File

@ -217,3 +217,52 @@ class TestCoreTileWindow:
(637900, 6626900, 639100, 6628100), 1200)
with rasterio.open(tif) as src:
assert _core_tile_window(tif, src) is None
class TestDensiteSolCrop:
"""Densité de points : WebP sans perte en niveaux de gris, sous-tuiles
écrites depuis l'image d'origine (un seul encodage)."""
def test_lossless_gray_levels_and_subtiles(self, tmp_path):
from PIL import Image as PILImage
from lidar_pipeline.rendering import tif_to_crop
base = "LHD_FXX_0660_6701_PTS_LAMB93_IGN69"
vis = tmp_path / "visualisations" / f"{base}_r0p2"
vis.mkdir(parents=True)
levels = np.tile(np.arange(16, dtype=np.float32).repeat(4), (64, 1)) # 64 × 64
tif = TestTifToCrop._write_named_tif(vis, f"{base}_densite_sol.tif", levels)
out = tif_to_crop(tif, vis, 0.2, output_format='avif', subtiles_dir=tmp_path)
assert out is not None and out.suffix == ".webp"
# WebP n'a pas de mode gris : relu en RGB à canaux égaux
rgb = np.asarray(PILImage.open(str(out)).convert("RGB")).astype(int)
assert (rgb[..., 0] == rgb[..., 1]).all() and (rgb[..., 1] == rgb[..., 2]).all()
img = PILImage.fromarray(rgb[..., 0].astype(np.uint8))
row = np.asarray(img)[0, ::4].astype(int)
assert len(set(row.tolist())) == 16 and np.all(np.diff(row) > 0)
# Sous-tuiles 2 × 2 (0,2 m/px) en WebP sans perte, identiques à la dalle
q = tmp_path / "index_subtiles" / f"{base}_r0p2_densite_sol_0_1.webp"
assert q.exists()
assert np.array_equal(np.asarray(PILImage.open(str(q)).convert("L")), np.asarray(img)[:32, :32])
assert (tmp_path / "index_subtiles" / f"{base}_r0p2_densite_sol_0_1_mid.webp").exists()
def test_relief_subtiles_encoded_from_source(self, tmp_path):
"""Relief : sous-tuiles AVIF écrites par tif_to_crop, plus récentes que la dalle."""
import pytest
from lidar_pipeline.rendering import tif_to_crop
base = "LHD_FXX_0660_6701_PTS_LAMB93_IGN69"
vis = tmp_path / "visualisations" / f"{base}_r0p2"
vis.mkdir(parents=True)
rgb = np.random.default_rng(1).integers(0, 255, (3, 64, 64)).astype('uint8')
tif = vis / f"{base}_relief_oriente.tif"
with rasterio.open(tif, 'w', driver='GTiff', height=64, width=64, count=3,
dtype='uint8', crs='EPSG:2154',
transform=from_bounds(660000, 6700000, 661000, 6701000, 64, 64)) as dst:
dst.write(rgb)
try:
out = tif_to_crop(tif, vis, 0.2, output_format='avif', subtiles_dir=tmp_path)
except Exception:
pytest.skip("encodeur AVIF indisponible")
sub = tmp_path / "index_subtiles"
quads = sorted(sub.glob(f"{base}_r0p2_relief_oriente_?_?.avif"))
assert len(quads) == 4
assert all(q.stat().st_mtime_ns >= out.stat().st_mtime_ns for q in quads)