Amélioration du rendu: interpolation DTM et affichage haute résolution
- DTM: interpolation des NaN avec rasterio.fill.fillnodata après binned_statistic_2d — comble les trous entre les cellules sans données - Rendering: interpolation='bilinear' sur imshow pour lisser le sous-échantillonnage des données haute résolution - Rendering: fig_width adaptatif (20-40 pouces) selon la taille des données - Rendering: DPI 200 pour les images > 3000px de large Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@ -285,10 +285,25 @@ def create_dtm_fast(las_file, basename, dtm_dir, resolution):
|
|||||||
dtm = stat.statistic.T
|
dtm = stat.statistic.T
|
||||||
dtm = dtm[::-1, :] # Flip Y so north is at top
|
dtm = dtm[::-1, :] # Flip Y so north is at top
|
||||||
|
|
||||||
# No interpolation: keep NaN for zones without LiDAR data
|
# Interpolate NaN gaps using distance-weighted nearest-neighbor fill
|
||||||
nan_count = np.count_nonzero(np.isnan(dtm))
|
nan_count = np.count_nonzero(np.isnan(dtm))
|
||||||
if nan_count > 0:
|
if nan_count > 0:
|
||||||
logger.info(f" {nan_count:,} pixels sans données (conservés en NaN)")
|
total = dtm.size
|
||||||
|
nan_pct = 100.0 * nan_count / total
|
||||||
|
logger.info(f" {nan_count:,} pixels sans données ({nan_pct:.1f}%) — interpolation...")
|
||||||
|
|
||||||
|
from rasterio.fill import fillnodata
|
||||||
|
# rasterio.fill.fillnodata uses GDAL's interpolation:
|
||||||
|
# fills gaps from surrounding valid pixels with distance weighting
|
||||||
|
dtm_filled = fillnodata(dtm.astype(np.float32), mask=~np.isnan(dtm),
|
||||||
|
max_search_distance=max(width, height) // 4)
|
||||||
|
dtm = dtm_filled.astype(np.float64)
|
||||||
|
|
||||||
|
remaining = np.count_nonzero(np.isnan(dtm))
|
||||||
|
if remaining > 0:
|
||||||
|
logger.warning(f" {remaining:,} pixels encore sans données après interpolation")
|
||||||
|
else:
|
||||||
|
logger.info(f" ✓ Interpolation terminée — tous les trous comblés")
|
||||||
|
|
||||||
# Save as GeoTIFF
|
# Save as GeoTIFF
|
||||||
output_tif = dtm_dir / f"{basename}_dtm.tif"
|
output_tif = dtm_dir / f"{basename}_dtm.tif"
|
||||||
|
|||||||
@ -324,8 +324,10 @@ def tif_to_png(tif_file, vis_dir, resolution):
|
|||||||
# Apply colormap
|
# Apply colormap
|
||||||
data, cmap, title, legend_label, description, is_rgb_result = _apply_colormap(data, tif_file)
|
data, cmap, title, legend_label, description, is_rgb_result = _apply_colormap(data, tif_file)
|
||||||
|
|
||||||
# Create figure
|
# Create figure — adapt width to data resolution for sharp rendering
|
||||||
fig_width = 20
|
# At high res (5000+px wide), we need a larger figure to avoid downsampling artifacts
|
||||||
|
fig_width = max(20, width / 150)
|
||||||
|
fig_width = min(fig_width, 40) # cap at 40 inches
|
||||||
map_aspect = height / width
|
map_aspect = height / width
|
||||||
fig = plt.figure(figsize=(fig_width, fig_width * map_aspect * 0.7 + 2.5),
|
fig = plt.figure(figsize=(fig_width, fig_width * map_aspect * 0.7 + 2.5),
|
||||||
facecolor='white')
|
facecolor='white')
|
||||||
@ -335,9 +337,11 @@ def tif_to_png(tif_file, vis_dir, resolution):
|
|||||||
|
|
||||||
ax = fig.add_subplot(gs[0])
|
ax = fig.add_subplot(gs[0])
|
||||||
if is_rgb:
|
if is_rgb:
|
||||||
im = ax.imshow(data, aspect='equal', origin='upper')
|
im = ax.imshow(data, aspect='equal', origin='upper',
|
||||||
|
interpolation='bilinear')
|
||||||
else:
|
else:
|
||||||
im = ax.imshow(data, cmap=cmap, aspect='equal', origin='upper')
|
im = ax.imshow(data, cmap=cmap, aspect='equal', origin='upper',
|
||||||
|
interpolation='bilinear')
|
||||||
|
|
||||||
ax.set_title(f"{title}\n{description}", fontsize=15, fontweight='bold', pad=10)
|
ax.set_title(f"{title}\n{description}", fontsize=15, fontweight='bold', pad=10)
|
||||||
|
|
||||||
@ -450,9 +454,10 @@ def tif_to_png(tif_file, vis_dir, resolution):
|
|||||||
|
|
||||||
fig.patch.set_facecolor('white')
|
fig.patch.set_facecolor('white')
|
||||||
|
|
||||||
# Save as PNG then convert to WebP
|
# Save as PNG then convert to WebP — use higher DPI for large data
|
||||||
|
save_dpi = 200 if width > 3000 else 150
|
||||||
png_temp = vis_dir / f"{tif_file.stem}_temp.png"
|
png_temp = vis_dir / f"{tif_file.stem}_temp.png"
|
||||||
plt.savefig(png_temp, dpi=150, bbox_inches='tight', pad_inches=0.15,
|
plt.savefig(png_temp, dpi=save_dpi, bbox_inches='tight', pad_inches=0.15,
|
||||||
facecolor='white', format='png')
|
facecolor='white', format='png')
|
||||||
plt.close()
|
plt.close()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user