Spaces:
Runtime error
Runtime error
| # Copyright (c) Open-CD. All rights reserved. | |
| import os.path as osp | |
| from typing import List, Optional, Union | |
| import mmcv | |
| import mmengine | |
| import numpy as np | |
| from mmcv.transforms import Compose | |
| from mmseg.utils import ConfigType | |
| from mmseg.apis import MMSegInferencer | |
| class OpenCDInferencer(MMSegInferencer): | |
| """Change Detection inferencer, provides inference and visualization | |
| interfaces. Note: MMEngine >= 0.5.0 is required. | |
| Args: | |
| classes (list, optional): Input classes for result rendering, as the | |
| prediction of segmentation model is a segment map with label | |
| indices, `classes` is a list which includes items responding to the | |
| label indices. If classes is not defined, visualizer will take | |
| `cityscapes` classes by default. Defaults to None. | |
| palette (list, optional): Input palette for result rendering, which is | |
| a list of color palette responding to the classes. If palette is | |
| not defined, visualizer will take `cityscapes` palette by default. | |
| Defaults to None. | |
| dataset_name (str, optional): `Dataset name or alias. | |
| visulizer will use the meta information of the dataset i.e. classes | |
| and palette, but the `classes` and `palette` have higher priority. | |
| Defaults to None. | |
| scope (str, optional): The scope of the model. Defaults to 'opencd'. | |
| """ # noqa | |
| def __init__(self, | |
| classes: Optional[Union[str, List]] = None, | |
| palette: Optional[Union[str, List]] = None, | |
| dataset_name: Optional[str] = None, | |
| scope: Optional[str] = 'opencd', | |
| **kwargs) -> None: | |
| super().__init__(scope=scope, **kwargs) | |
| classes = classes if classes else self.model.dataset_meta.classes | |
| palette = palette if palette else self.model.dataset_meta.palette | |
| self.visualizer.set_dataset_meta(classes, palette, dataset_name) | |
| def _inputs_to_list(self, inputs: Union[str, np.ndarray]) -> list: | |
| """Preprocess the inputs to a list. | |
| Preprocess inputs to a list according to its type: | |
| - list or tuple: return inputs | |
| - str: | |
| - Directory path: return all files in the directory | |
| - other cases: return a list containing the string. The string | |
| could be a path to file, a url or other types of string according | |
| to the task. | |
| Args: | |
| inputs (InputsType): Inputs for the inferencer. | |
| Returns: | |
| list: List of input for the :meth:`preprocess`. | |
| """ | |
| return list(inputs) | |
| def visualize(self, | |
| inputs: list, | |
| preds: List[dict], | |
| return_vis: bool = False, | |
| show: bool = False, | |
| wait_time: int = 0, | |
| img_out_dir: str = '', | |
| opacity: float = 1.0) -> List[np.ndarray]: | |
| """Visualize predictions. | |
| Args: | |
| inputs (list): Inputs preprocessed by :meth:`_inputs_to_list`. | |
| preds (Any): Predictions of the model. | |
| show (bool): Whether to display the image in a popup window. | |
| Defaults to False. | |
| wait_time (float): The interval of show (s). Defaults to 0. | |
| img_out_dir (str): Output directory of rendering prediction i.e. | |
| color segmentation mask. Defaults: '' | |
| opacity (int, float): The transparency of segmentation mask. | |
| Defaults to 0.8. | |
| Returns: | |
| List[np.ndarray]: Visualization results. | |
| """ | |
| if not show and img_out_dir == '' and not return_vis: | |
| return None | |
| if self.visualizer is None: | |
| raise ValueError('Visualization needs the "visualizer" term' | |
| 'defined in the config, but got None.') | |
| self.visualizer.alpha = opacity | |
| results = [] | |
| for single_inputs, pred in zip(inputs, preds): | |
| img_from_to = [] | |
| for single_input in single_inputs: | |
| if isinstance(single_input, str): | |
| img_bytes = mmengine.fileio.get(single_input) | |
| img = mmcv.imfrombytes(img_bytes) | |
| img = img[:, :, ::-1] | |
| img_name = osp.basename(single_input) | |
| elif isinstance(single_input, np.ndarray): | |
| img = single_input.copy() | |
| img_num = str(self.num_visualized_imgs).zfill(8) + '_vis' | |
| img_name = f'{img_num}.jpg' | |
| else: | |
| raise ValueError('Unsupported input type:' | |
| f'{type(single_input)}') | |
| img_shape = img.shape | |
| img_from_to.append(img) | |
| out_file = osp.join(img_out_dir, img_name) if img_out_dir != ''\ | |
| else None | |
| img_zero_board = np.zeros(img_shape) | |
| self.visualizer.add_datasample( | |
| img_name, | |
| img_zero_board, | |
| img_from_to, | |
| pred, | |
| show=show, | |
| wait_time=wait_time, | |
| draw_gt=False, | |
| draw_pred=True, | |
| out_file=out_file) | |
| if return_vis: | |
| results.append(self.visualizer.get_image()) | |
| self.num_visualized_imgs += 1 | |
| return results if return_vis else None | |
| def _init_pipeline(self, cfg: ConfigType) -> Compose: | |
| """Initialize the test pipeline. | |
| Return a pipeline to handle various input data, such as ``str``, | |
| ``np.ndarray``. It is an abstract method in BaseInferencer, and should | |
| be implemented in subclasses. | |
| The returned pipeline will be used to process a single data. | |
| It will be used in :meth:`preprocess` like this: | |
| .. code-block:: python | |
| def preprocess(self, inputs, batch_size, **kwargs): | |
| ... | |
| dataset = map(self.pipeline, dataset) | |
| ... | |
| """ | |
| pipeline_cfg = cfg.test_dataloader.dataset.pipeline | |
| # Loading annotations is also not applicable | |
| for transform in ('MultiImgLoadAnnotations', 'MultiImgLoadDepthAnnotation'): | |
| idx = self._get_transform_idx(pipeline_cfg, transform) | |
| if idx != -1: | |
| del pipeline_cfg[idx] | |
| load_img_idx = self._get_transform_idx(pipeline_cfg, | |
| 'MultiImgLoadImageFromFile') | |
| if load_img_idx == -1: | |
| raise ValueError( | |
| 'MultiImgLoadImageFromFile is not found in the test pipeline') | |
| pipeline_cfg[load_img_idx]['type'] = 'MultiImgLoadInferencerLoader' | |
| return Compose(pipeline_cfg) | |