Download code/synth6.py from fnruha0921/knps-change-detection-tmp: direct link, hf CLI and curl.
- Browser
- Download file 4.96 kB
-
https://huggingface.co/fnruha0921/knps-change-detection-tmp/resolve/main/code/synth6.py
- Command line
-
hf download hf://fnruha0921/knps-change-detection-tmp/code/synth6.py
-
curl -L -o synth6.py https://huggingface.co/fnruha0921/knps-change-detection-tmp/resolve/main/code/synth6.py
4.96 kB
| """Synth6 = Synth4 (EarthView negatives, p_ev) + HOT building scenes (p_hot of building scenes) + Korean-style vinyl greenhouse synthesis (p_gh).""" | |
| import os, time, math | |
| import cv2, numpy as np, torch | |
| from train2 import CROP | |
| from train3 import degrade | |
| from ev_synth import Synth4 | |
| class Synth6(Synth4): | |
| def __init__(self, n, p_ev=0.2, p_hot=0.5, p_gh=0.12): | |
| super().__init__(n, p_ev) | |
| self.p_hot, self.p_gh = p_hot, p_gh | |
| self.hx = np.load("/workspace/prep/hot_x.npy", mmap_mode="r"); self.hy = np.load("/workspace/prep/hot_y.npy", mmap_mode="r") | |
| print("HOT scenes", self.hx.shape, flush=True) | |
| def scene(self, rng, kind): | |
| if kind == "b" and rng.random() < self.p_hot: | |
| i = rng.integers(len(self.hx)); s = rng.uniform(0.85, 1.15); size = min(256, int(round(CROP / s))) | |
| r, c = rng.integers(0, 257 - size, 2) | |
| x = cv2.resize(np.ascontiguousarray(self.hx[i, r:r + size, c:c + size]), (CROP, CROP), interpolation=cv2.INTER_AREA) | |
| y = cv2.resize(np.ascontiguousarray(self.hy[i, r:r + size, c:c + size]), (CROP, CROP), interpolation=cv2.INTER_NEAREST) | |
| return x.copy(), y.astype(np.uint8) # code 1 = building (others unlabeled) | |
| return super().scene(rng, kind) | |
| def greenhouses(rng, shape): | |
| """Rows of long, narrow tunnel greenhouses: returns (mask, rendered rgb layer).""" | |
| m = np.zeros(shape, np.uint8); lay = np.zeros(shape + (3,), np.float32) | |
| th = rng.uniform(0, np.pi); u = np.array([np.cos(th), np.sin(th)]); v = np.array([-u[1], u[0]]) | |
| n = int(rng.integers(2, 9)); w = rng.uniform(8, 14); gap = rng.uniform(1.5, 5); L = rng.uniform(30, 140) | |
| c0 = np.array([rng.uniform(40, shape[1] - 40), rng.uniform(40, shape[0] - 40)]) | |
| base = rng.uniform(185, 245); tint = rng.uniform(-12, 12, 3) | |
| yy, xx = np.mgrid[:shape[0], :shape[1]].astype(np.float32) | |
| for k in range(n): | |
| ck = c0 + v * (k - n / 2) * (w + gap) + u * rng.uniform(-6, 6) | |
| Lk = L * rng.uniform(0.8, 1.0) | |
| pts = np.array([ck + u * Lk / 2 + v * w / 2, ck + u * Lk / 2 - v * w / 2, ck - u * Lk / 2 - v * w / 2, ck - u * Lk / 2 + v * w / 2], np.int32) | |
| mk = np.zeros(shape, np.uint8); cv2.fillPoly(mk, [pts], 1) | |
| dv = ((xx - ck[0]) * v[0] + (yy - ck[1]) * v[1]) / (w / 2) # -1..1 across the tunnel | |
| shade = 0.78 + 0.22 * np.cos(np.clip(dv, -1, 1) * np.pi / 2) # bright ridge, darker sides | |
| for ch in range(3): | |
| lay[..., ch] = np.where(mk > 0, (base + tint[ch]) * shade + rng.normal(0, 3, shape), lay[..., ch]) | |
| m |= mk | |
| return m, np.clip(lay, 0, 255) | |
| def __getitem__(self, idx): | |
| rng = np.random.default_rng((idx * 7919 + os.getpid() * 104729 + time.time_ns()) % 2**32) | |
| if rng.random() >= self.p_gh: | |
| return super().__getitem__(idx) | |
| x, y = self.scene(rng, "g" if rng.random() < 0.6 else "any") | |
| pre = x.copy(); sem = np.zeros(y.shape, np.uint8); sem[y == 1] = 1; sem[y == 2] = 2 | |
| if rng.random() < 0.3: # pre-existing greenhouses in both images (not a change) | |
| m0, l0 = self.greenhouses(rng, y.shape); a = (m0[..., None] * rng.uniform(0.85, 0.95)) | |
| pre = (pre * (1 - a) + l0 * a).astype(np.uint8); sem[m0 > 0] = 1 | |
| post = pre.copy(); m, lay = self.greenhouses(rng, y.shape) | |
| m[sem == 1] = 0 | |
| a = cv2.GaussianBlur(m.astype(np.float32), (0, 0), 0.6)[..., None] * rng.uniform(0.85, 0.97) | |
| post = (post * (1 - a) + lay * a).astype(np.uint8) | |
| lb = m.copy(); lt = np.zeros_like(m); sem_pre = sem.copy(); sem_post = sem.copy(); sem_post[m > 0] = 1 | |
| if rng.random() < 0.15: # demolition: reversed pair is not a target | |
| pre, post = post, pre; sem_pre, sem_post = sem_post, sem_pre; lb[:] = 0 | |
| pre = degrade(self.photo(pre, rng), rng); post = degrade(self.photo(post, rng), rng) | |
| if rng.random() < 0.8: | |
| M = cv2.getRotationMatrix2D((CROP / 2, CROP / 2), rng.uniform(-1.5, 1.5), rng.uniform(0.98, 1.02)); M[:, 2] += rng.uniform(-4, 4, 2) | |
| pre = cv2.warpAffine(pre, M, (CROP, CROP), borderMode=cv2.BORDER_REFLECT) | |
| sem_pre = cv2.warpAffine(sem_pre, M, (CROP, CROP), flags=cv2.INTER_NEAREST, borderMode=cv2.BORDER_REFLECT) | |
| k = rng.integers(8) | |
| def d4(a): | |
| a = np.rot90(a, k % 4) | |
| return np.ascontiguousarray(a[:, ::-1] if k >= 4 else a) | |
| pre, post, lb, lt, sem_pre, sem_post = map(d4, (pre, post, lb, lt, sem_pre, sem_post)) | |
| t = lambda a: torch.from_numpy(a.transpose(2, 0, 1).copy()) | |
| pres = np.array([lb.sum() >= 20, 0], np.float32) | |
| return (t(pre), t(post), torch.from_numpy(np.stack([lb, lt]).astype(np.float32)), torch.from_numpy(pres), | |
| torch.from_numpy(sem_pre.astype(np.int64)), torch.from_numpy(sem_post.astype(np.int64))) | |