|
|
|
|
|
""" |
|
|
Preprocess Synscapes Data |
|
|
|
|
|
This script processes Synscapes data by: |
|
|
1. Copying the RGB images. |
|
|
2. Reading the EXR depth data and saving it as .npy. |
|
|
3. Generating a sky mask using the class labels. |
|
|
4. Extracting camera intrinsics from the meta file. |
|
|
|
|
|
The directory structure is expected to be: |
|
|
synscapes_dir/ |
|
|
img/ |
|
|
rgb/ |
|
|
depth/ |
|
|
class/ |
|
|
meta/ |
|
|
Each file shares the same base name, e.g. 000000.png/exr in corresponding folders. |
|
|
|
|
|
Usage: |
|
|
python preprocess_synscapes.py \ |
|
|
--synscapes_dir /path/to/Synscapes/Synscapes \ |
|
|
--output_dir /path/to/processed_synscapes |
|
|
""" |
|
|
|
|
|
import os |
|
|
import json |
|
|
import shutil |
|
|
import argparse |
|
|
import numpy as np |
|
|
import cv2 |
|
|
import OpenEXR |
|
|
from tqdm import tqdm |
|
|
|
|
|
|
|
|
os.environ["OPENCV_IO_ENABLE_OPENEXR"] = "1" |
|
|
|
|
|
|
|
|
def process_basename( |
|
|
basename, |
|
|
rgb_dir, |
|
|
depth_dir, |
|
|
class_dir, |
|
|
meta_dir, |
|
|
out_rgb_dir, |
|
|
out_depth_dir, |
|
|
out_mask_dir, |
|
|
out_cam_dir, |
|
|
sky_id=23, |
|
|
): |
|
|
""" |
|
|
Process a single sample of the Synscapes dataset: |
|
|
1. Reads an RGB .png and depth .exr file. |
|
|
2. Reads a class label .png, generating a sky mask. |
|
|
3. Reads camera intrinsics from the meta .json file. |
|
|
4. Saves the resulting data to the specified output folders. |
|
|
|
|
|
Args: |
|
|
basename (str): The base filename (without extension). |
|
|
rgb_dir (str): Directory containing RGB .png files. |
|
|
depth_dir (str): Directory containing depth .exr files. |
|
|
class_dir (str): Directory containing class .png files. |
|
|
meta_dir (str): Directory containing camera metadata .json files. |
|
|
out_rgb_dir (str): Output directory for RGB files. |
|
|
out_depth_dir (str): Output directory for depth .npy files. |
|
|
out_mask_dir (str): Output directory for sky masks. |
|
|
out_cam_dir (str): Output directory for camera intrinsics (.npz). |
|
|
sky_id (int): Class ID for sky pixels in the class label images. |
|
|
|
|
|
Returns: |
|
|
None or str: |
|
|
If an error occurs, returns an error message (str). Otherwise, returns None. |
|
|
""" |
|
|
try: |
|
|
|
|
|
rgb_file = os.path.join(rgb_dir, f"{basename}.png") |
|
|
depth_file = os.path.join(depth_dir, f"{basename}.exr") |
|
|
class_file = os.path.join(class_dir, f"{basename}.png") |
|
|
meta_file = os.path.join(meta_dir, f"{basename}.json") |
|
|
|
|
|
|
|
|
out_img_path = os.path.join(out_rgb_dir, f"{basename}.png") |
|
|
out_depth_path = os.path.join(out_depth_dir, f"{basename}.npy") |
|
|
out_mask_path = os.path.join(out_mask_dir, f"{basename}.png") |
|
|
out_cam_path = os.path.join(out_cam_dir, f"{basename}.npz") |
|
|
|
|
|
|
|
|
|
|
|
exr_file = OpenEXR.InputFile(depth_file) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
depth = np.array(OpenEXR.InputFile(depth_file).parts[0].channels["Z"].pixels) |
|
|
|
|
|
|
|
|
class_img = cv2.imread(class_file, cv2.IMREAD_UNCHANGED) |
|
|
|
|
|
sky_mask = (class_img == sky_id).astype(np.uint8) * 255 |
|
|
|
|
|
|
|
|
with open(meta_file, "r") as f: |
|
|
cam_info = json.load(f)["camera"] |
|
|
intrinsic = cam_info["intrinsic"] |
|
|
fx, fy, cx, cy = ( |
|
|
intrinsic["fx"], |
|
|
intrinsic["fy"], |
|
|
intrinsic["u0"], |
|
|
intrinsic["v0"], |
|
|
) |
|
|
|
|
|
K = np.eye(3, dtype=np.float32) |
|
|
K[0, 0] = fx |
|
|
K[1, 1] = fy |
|
|
K[0, 2] = cx |
|
|
K[1, 2] = cy |
|
|
|
|
|
|
|
|
shutil.copy(rgb_file, out_img_path) |
|
|
|
|
|
|
|
|
np.save(out_depth_path, depth) |
|
|
cv2.imwrite(out_mask_path, sky_mask) |
|
|
np.savez(out_cam_path, intrinsics=K) |
|
|
|
|
|
except Exception as e: |
|
|
return f"Error processing {basename}: {e}" |
|
|
|
|
|
return None |
|
|
|
|
|
|
|
|
def main(): |
|
|
parser = argparse.ArgumentParser(description="Preprocess Synscapes data.") |
|
|
parser.add_argument( |
|
|
"--synscapes_dir", |
|
|
required=True, |
|
|
help="Path to the main Synscapes directory (contains 'img' and 'meta' folders).", |
|
|
) |
|
|
parser.add_argument( |
|
|
"--output_dir", |
|
|
required=True, |
|
|
help="Path to the output directory for processed data.", |
|
|
) |
|
|
parser.add_argument( |
|
|
"--sky_id", |
|
|
type=int, |
|
|
default=23, |
|
|
help="Class ID for sky pixels in class .png. Default is 23.", |
|
|
) |
|
|
args = parser.parse_args() |
|
|
|
|
|
synscapes_dir = os.path.abspath(args.synscapes_dir) |
|
|
output_dir = os.path.abspath(args.output_dir) |
|
|
os.makedirs(output_dir, exist_ok=True) |
|
|
|
|
|
|
|
|
rgb_dir = os.path.join(synscapes_dir, "img", "rgb") |
|
|
depth_dir = os.path.join(synscapes_dir, "img", "depth") |
|
|
class_dir = os.path.join(synscapes_dir, "img", "class") |
|
|
meta_dir = os.path.join(synscapes_dir, "meta") |
|
|
|
|
|
|
|
|
out_rgb_dir = os.path.join(output_dir, "rgb") |
|
|
out_depth_dir = os.path.join(output_dir, "depth") |
|
|
out_mask_dir = os.path.join(output_dir, "sky_mask") |
|
|
out_cam_dir = os.path.join(output_dir, "cam") |
|
|
for d in [out_rgb_dir, out_depth_dir, out_mask_dir, out_cam_dir]: |
|
|
os.makedirs(d, exist_ok=True) |
|
|
|
|
|
|
|
|
basenames = sorted( |
|
|
[ |
|
|
os.path.splitext(fname)[0] |
|
|
for fname in os.listdir(depth_dir) |
|
|
if fname.endswith(".exr") |
|
|
] |
|
|
) |
|
|
|
|
|
|
|
|
from concurrent.futures import ProcessPoolExecutor, as_completed |
|
|
|
|
|
num_workers = max(1, os.cpu_count() // 2) |
|
|
|
|
|
with ProcessPoolExecutor(max_workers=num_workers) as executor: |
|
|
future_to_basename = { |
|
|
executor.submit( |
|
|
process_basename, |
|
|
bname, |
|
|
rgb_dir, |
|
|
depth_dir, |
|
|
class_dir, |
|
|
meta_dir, |
|
|
out_rgb_dir, |
|
|
out_depth_dir, |
|
|
out_mask_dir, |
|
|
out_cam_dir, |
|
|
args.sky_id, |
|
|
): bname |
|
|
for bname in basenames |
|
|
} |
|
|
|
|
|
for future in tqdm( |
|
|
as_completed(future_to_basename), |
|
|
total=len(future_to_basename), |
|
|
desc="Processing Synscapes", |
|
|
): |
|
|
basename = future_to_basename[future] |
|
|
error = future.result() |
|
|
if error: |
|
|
print(error) |
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
main() |
|
|
|