fnruha0921's picture
HOT+greenhouse synth6.py
a3bbf71 verified
Raw History Blame Contribute Delete
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)
@staticmethod
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)))