File size: 5,527 Bytes
387a20d 7a2d30b 387a20d 7a2d30b 387a20d 7a2d30b 387a20d 7a2d30b 387a20d 7a2d30b 387a20d 7a2d30b 387a20d 7a2d30b 387a20d 7a2d30b 387a20d 7a2d30b 387a20d 7a2d30b 387a20d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 | import argparse
from pathlib import Path
import numpy as np
import yaml
def real_images(paths, size, scale_factor):
import tifffile
if not paths:
raise FileNotFoundError("No TIFF files supplied")
images = []
scale_factors = []
for path in paths:
image = tifffile.imread(path)
original_dtype = image.dtype
if image.ndim != 3:
raise ValueError(f"Expected a 13-band TIFF, got {image.shape} from {path}")
if image.shape[0] == 13:
image = image.transpose(1, 2, 0)
if image.shape[-1] != 13:
raise ValueError(f"Expected 13 Sentinel-2 bands, got {image.shape} from {path}")
image = np.delete(image, 10, axis=-1) # Exclude Sentinel-2 B10 as in the paper.
y = np.linspace(0, image.shape[0] - 1, size).round().astype(int)
x = np.linspace(0, image.shape[1] - 1, size).round().astype(int)
image = image[y][:, x]
factor = scale_factor
if factor is None:
minimum = float(np.nanmin(image))
maximum = float(np.nanmax(image))
already_normalized = minimum >= 0.0 and maximum <= 1.0
factor = 10000.0 if not already_normalized and (
np.issubdtype(original_dtype, np.integer) or maximum > 1.0
) else 1.0
images.append(np.clip(image.astype(np.float32) / factor, 0, 1).transpose(2, 0, 1))
scale_factors.append(factor)
return np.asarray(images, dtype=np.float32), np.asarray(scale_factors, dtype=np.float32)
def synthetic_images(count, size, seed):
rng = np.random.default_rng(seed)
y, x = np.mgrid[0:size, 0:size].astype(np.float32) / max(size - 1, 1)
images = []
for index in range(count):
phase = rng.uniform(0, 2 * np.pi)
bands = []
for band in range(12):
pattern = 0.45 + 0.22 * np.sin((band + 1) * x + phase)
pattern += 0.18 * np.cos((band / 3 + 1) * y - phase)
pattern += rng.normal(0, 0.025, (size, size))
bands.append(np.clip(pattern, 0, 1))
images.append(bands)
return np.asarray(images, dtype=np.float32)
def save_npz(output, images, source, protocol, normalization, scale_factors, stage):
band_order = np.asarray(["B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B8A", "B9", "B11", "B12"])
output.parent.mkdir(parents=True, exist_ok=True)
np.savez_compressed(output, images=images, data_source=np.asarray(source),
protocol=np.asarray(protocol), band_order=band_order,
normalization=np.asarray(normalization), scale_factors=scale_factors,
stage=np.asarray(stage))
print(f"saved: {output} shape={images.shape} stage={stage} data_source={source}")
def main():
parser = argparse.ArgumentParser(description="Generate compact 12-band spectral data")
parser.add_argument("--config", default="conf/config.yaml")
parser.add_argument("--real-dir", help="Convert official 13-band Sentinel-2 TIFF files")
parser.add_argument("--scale-factor", default="auto",
help="TIFF divisor, or 'auto' (10000 for integer/range > 1; otherwise 1)")
parser.add_argument("--stage", choices=("stage1", "stage2"), default="stage2",
help="Target stage for real TIFF conversion")
args = parser.parse_args()
with open(args.config, encoding="utf-8") as handle:
config = yaml.safe_load(handle)
if args.scale_factor == "auto":
scale_factor = None
else:
scale_factor = float(args.scale_factor)
if not np.isfinite(scale_factor) or scale_factor <= 0:
raise ValueError("--scale-factor must be a positive finite number or 'auto'")
if args.real_dir:
stage = next(item for item in config["stages"] if item["name"] == args.stage)
count = stage["train_samples"] + (config["data"]["test_samples"] if args.stage == "stage2" else 0)
paths = sorted(Path(args.real_dir).rglob("*.tif"))
if len(paths) < count:
raise ValueError(f"Need at least {count} TIFF files, found {len(paths)}")
images, scale_factors = real_images(paths[:count], stage["image_size"], scale_factor)
normalization = "divide_by_scale_factor_then_clip_0_1"
save_npz(Path(stage["train_path"]), images[:stage["train_samples"]], "real",
config["data"]["protocol"], normalization,
scale_factors[:stage["train_samples"]], args.stage)
if args.stage == "stage2":
save_npz(Path(config["data"]["test_path"]), images[stage["train_samples"]:], "real",
config["data"]["protocol"], normalization,
scale_factors[stage["train_samples"]:], "stage2")
else:
for index, stage in enumerate(config["stages"]):
images = synthetic_images(stage["train_samples"], stage["image_size"], config["runtime"]["seed"] + index)
save_npz(Path(stage["train_path"]), images, "synthetic", config["data"]["protocol"],
"already_0_1", np.ones(len(images), np.float32), stage["name"])
test_size = config["stages"][-1]["image_size"]
images = synthetic_images(config["data"]["test_samples"], test_size, config["runtime"]["seed"] + 2)
save_npz(Path(config["data"]["test_path"]), images, "synthetic", config["data"]["protocol"],
"already_0_1", np.ones(len(images), np.float32), "stage2")
if __name__ == "__main__":
main()
|