| import argparse |
| from pathlib import Path |
| from typing import List, Union |
|
|
| import numpy as np |
| from PIL import Image |
|
|
|
|
| def is_path(path) -> bool: |
| return isinstance(path, (str, Path)) |
|
|
|
|
| def load_image_pils(image_paths: Union[str, List[str], np.ndarray, List[np.ndarray]]) -> Union[List["Image"], bool]: |
| """Load images from paths and return as a list of PIL.Image |
| :return is_list: whether input is a list |
| """ |
| |
| if is_path(image_paths): |
| image_pil = Image.open(image_paths).convert("RGB") |
| return [image_pil], False |
| elif isinstance(image_paths, list) and is_path(image_paths[0]): |
| image_pils = [] |
| for image_path in image_paths: |
| image_pil = Image.open(image_path).convert("RGB") |
| image_pils.append(image_pil) |
| return image_pils, True |
| elif isinstance(image_paths, list) and image_paths[0].ndim == 3 or image_paths.ndim == 4: |
| image_pils = [] |
| for image in image_paths: |
| image_pil = Image.fromarray(image).convert("RGB") |
| image_pils.append(image_pil) |
| return image_pils, True |
| elif image_paths.ndim == 3: |
| image_pil = Image.fromarray(image_paths).convert("RGB") |
| return [image_pil], False |
| else: |
| raise ValueError(f"Wrong format of image_paths: {type(image_paths)}") |
|
|
|
|
| def load_image_arrays( |
| image_paths: Union[str, List[str], np.ndarray, List[np.ndarray]] |
| ) -> Union[List[np.ndarray], bool]: |
| """Load images and return as a list of [H, W, 3] np.ndarray |
| :return is_list: whether input is a list |
| """ |
| if is_path(image_paths) or isinstance(image_paths, list) and is_path(image_paths[0]): |
| image_pils, is_list = load_image_pils(image_paths) |
| return [np.asarray(image_pil) for image_pil in image_pils], is_list |
| elif isinstance(image_paths, list) and image_paths[0].ndim == 3 or image_paths.ndim == 4: |
| return list(image_paths), True |
| elif image_paths.ndim == 3: |
| return [image_paths], False |
| else: |
| raise ValueError(f"Wrong format of image_paths: {type(image_paths)}") |
|
|
|
|
| class DictAction(argparse.Action): |
| """ |
| argparse action to split an argument into KEY=VALUE form |
| on the first = and append to a dictionary. List options can |
| be passed as comma separated values, i.e 'KEY=V1,V2,V3', or with explicit |
| brackets, i.e. 'KEY=[V1,V2,V3]'. It also support nested brackets to build |
| list/tuple values. e.g. 'KEY=[(V1,V2),(V3,V4)]' |
| """ |
|
|
| @staticmethod |
| def _parse_int_float_bool(val): |
| try: |
| return int(val) |
| except ValueError: |
| pass |
| try: |
| return float(val) |
| except ValueError: |
| pass |
| if val.lower() in ["true", "false"]: |
| return True if val.lower() == "true" else False |
| return val |
|
|
| @staticmethod |
| def _parse_iterable(val): |
| """Parse iterable values in the string. |
| |
| All elements inside '()' or '[]' are treated as iterable values. |
| |
| Args: |
| val (str): Value string. |
| |
| Returns: |
| list | tuple: The expanded list or tuple from the string. |
| |
| Examples: |
| >>> DictAction._parse_iterable('1,2,3') |
| [1, 2, 3] |
| >>> DictAction._parse_iterable('[a, b, c]') |
| ['a', 'b', 'c'] |
| >>> DictAction._parse_iterable('[(1, 2, 3), [a, b], c]') |
| [(1, 2, 3), ['a', 'b], 'c'] |
| """ |
|
|
| def find_next_comma(string): |
| """Find the position of next comma in the string. |
| |
| If no ',' is found in the string, return the string length. All |
| chars inside '()' and '[]' are treated as one element and thus ',' |
| inside these brackets are ignored. |
| """ |
| assert (string.count("(") == string.count(")")) and ( |
| string.count("[") == string.count("]") |
| ), f"Imbalanced brackets exist in {string}" |
| end = len(string) |
| for idx, char in enumerate(string): |
| pre = string[:idx] |
| |
| if (char == ",") and (pre.count("(") == pre.count(")")) and (pre.count("[") == pre.count("]")): |
| end = idx |
| break |
| return end |
|
|
| |
| val = val.strip("'\"").replace(" ", "") |
| is_tuple = False |
| if val.startswith("(") and val.endswith(")"): |
| is_tuple = True |
| val = val[1:-1] |
| elif val.startswith("[") and val.endswith("]"): |
| val = val[1:-1] |
| elif "," not in val: |
| |
| return DictAction._parse_int_float_bool(val) |
|
|
| values = [] |
| while len(val) > 0: |
| comma_idx = find_next_comma(val) |
| element = DictAction._parse_iterable(val[:comma_idx]) |
| values.append(element) |
| val = val[comma_idx + 1 :] |
| if is_tuple: |
| values = tuple(values) |
| return values |
|
|
| def __call__(self, parser, namespace, values, option_string=None): |
| options = {} |
| for kv in values: |
| key, val = kv.split("=", maxsplit=1) |
| options[key] = self._parse_iterable(val) |
| setattr(namespace, self.dest, options) |
|
|