fnruha0921's picture
Upload code/chm/chm_fuse.py with huggingface_hub
4ed7709 verified
Raw History Blame Contribute Delete
2.16 kB
"""Canopy-height cue for tree_removal from Meta CHMv2 (DINOv3 ViT-L/16 SAT-493M + DPT head, DINOv3 License).
heights(pre) and heights(post) are canopy-height maps in metres; a pixel is a tree-removal cue when the
pre canopy was tall and the post surface is near the ground.
"""
import numpy as np
import torch
import torch.nn.functional as F
from PIL import Image
from transformers import AutoImageProcessor, AutoModelForDepthEstimation
class CHM:
def __init__(self, path, device, flip_tta=True, scale=1.0):
self.proc = AutoImageProcessor.from_pretrained(path)
self.m = AutoModelForDepthEstimation.from_pretrained(path).to(device).eval()
self.device, self.flip_tta, self.scale = device, flip_tta, scale
@torch.no_grad()
def _run(self, imgs):
h, w = imgs[0].shape[:2]
if self.scale != 1.0:
sz = (int(round(w * self.scale / 16)) * 16, int(round(h * self.scale / 16)) * 16)
imgs = [np.asarray(Image.fromarray(im).resize(sz, Image.BICUBIC)) for im in imgs]
inp = {k: v.to(self.device) for k, v in self.proc(images=list(imgs), return_tensors="pt").items()}
out = self.m(**inp)
res = self.proc.post_process_depth_estimation(out, target_sizes=[(h, w)] * len(imgs))
return torch.stack([r["predicted_depth"].float().reshape(h, w) for r in res])
@torch.no_grad()
def heights(self, imgs):
"""list of (H,W,3) uint8 -> (N,H,W) float32 tensor (metres)."""
h = self._run(imgs)
if self.flip_tta:
h = (h + self._run([im[:, ::-1].copy() for im in imgs]).flip(-1)) / 2
return h
def _smooth(h, k):
return F.avg_pool2d(h[:, None], k, 1, k // 2, count_include_pad=False)[:, 0]
def cue_abs(hp, hq, k=7, lo=3.0, span=4.0, gmax=4.0, gspan=3.0):
"""tall before (>= lo+span m -> 1) and near ground after (<= gmax-gspan m -> 1)."""
hp, hq = _smooth(hp, k), _smooth(hq, k)
return ((hp - lo) / span).clamp(0, 1) * ((gmax - hq) / gspan).clamp(0, 1)
def cue_diff(hp, hq, k=7, lo=2.0, span=4.0):
"""height drop >= lo+span m -> 1."""
return ((_smooth(hp, k) - _smooth(hq, k) - lo) / span).clamp(0, 1)