import os import argparse import kwcoco import numpy as np from tqdm import tqdm from geowatch.tasks.rutgers_material_seg_v2.matseg.utils.utils_misc import create_gif from geowatch.tasks.rutgers_material_seg_v2.matseg.utils.utils_dataset import colorize_material_mask def normalize_rgb(image, gamma=0.6): """Convert a raw image to beautiful RGB color. Args: image (np.ndarray): A uint16 tensor of shape (H, W, 3). gamma (float, optional): The factor to adjust color values. Defaults to 0.6. Returns: np.ndarray: The uint8 tensor of shape (H, W, 3). """ # Normalize from uint16 to float32. image = np.clip(image / 2**16, 0, 1) # Adjust color balance. image *= 2**4 image = np.clip(image**gamma, 0, 1) # Convert to uint8. image = (image * 255).astype('uint8') return image def rgbize_features(features): """_summary_ Args: features (_type_): A Returns: np.ndarray: _description_ """ if features.shape[-1] == 1: feat_img = np.repeat(features, 3, axis=-1) else: feat_img = features[..., :3] feat_img = np.nan_to_num(feat_img) max_value = np.quantile(feat_img, 0.95, axis=(0, 1, 2)) min_value = np.quantile(feat_img, 0.05, axis=(0, 1, 2)) feat_img = (feat_img - min_value) / (max_value - min_value) # Convert to uint8. feat_img = (feat_img * 255).astype('uint8') return feat_img def visualize_material_features(): parser = argparse.ArgumentParser() parser.add_argument('kwcoco_fpath', type=str, help='Path to kwcoco file') parser.add_argument('save_dir', type=str, help='Path to save images.') args = parser.parse_args() # Check if save directory exists. os.makedirs(args.save_dir, exist_ok=True) # Load kwcoco file. dset = kwcoco.CocoDataset.coerce(args.kwcoco_fpath) # For each video load material and RGB frames, visualize with GIF. video_ids = list(dset.videos()) for video_id in tqdm(video_ids, desc='Video'): # Get all image ids for video. video_image_ids = dset.index.vidid_to_gids[video_id] mat_rgb_imgs, metadata_strings = [], [] region_name = None for image_id in tqdm(video_image_ids, desc='Image', leave=False): coco_image = dset.coco_image(image_id) # Get region name. if region_name is None: region_name = coco_image.video['name'] # TODO: Check if the materials are empty for this image. # missing_material_instance = False # for asset in coco_image['assets']: # if not .has('materials'): # missing_material_images += 1 # continue # Load and normalize RGB image. rgb_image = coco_image.delay('red|green|blue', space='video', resolution='10GSD').finalize() rgb_image = normalize_rgb(rgb_image) # Load and colorize material image. materials = coco_image.delay('materials', space='video', resolution='10GSD').finalize() materials = np.argmax(materials, axis=-1) rgb_mats = colorize_material_mask(materials) # Load and colorize feature image. mat_feats = coco_image.delay('mat_feats', space='video', resolution='10GSD').finalize() mat_feat_img = rgbize_features(mat_feats) # Combine images and append to list. mat_rgb_imgs.append(np.concatenate([rgb_image, rgb_mats, mat_feat_img], axis=1)) # Get image metadata in string format. ## Get date of image taken. img_name = str(coco_image.primary_image_filepath()).split('/')[-1] datetime_str = img_name.split('_')[1] year = datetime_str[:4] month = datetime_str[4:6] day = datetime_str[6:8] ## Get sensor type. try: sensor_type = coco_image.primary_asset()['sensor_coarse'] except KeyError: sensor_type = None if sensor_type is None: metadata_string = f'{year}-{month}-{day} {image_id}' else: metadata_string = f'{year}-{month}-{day} {sensor_type} {image_id}' metadata_strings.append(metadata_string) # Generate GIF. save_path = f'{args.save_dir}/{region_name}.gif' create_gif(mat_rgb_imgs, save_path, image_text=metadata_strings) if __name__ == '__main__': visualize_material_features()