|
| 1 | +""" |
| 2 | +Copyright (c) 2018-2022 Intel Corporation |
| 3 | +
|
| 4 | +Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | +you may not use this file except in compliance with the License. |
| 6 | +You may obtain a copy of the License at |
| 7 | +
|
| 8 | + http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | +
|
| 10 | +Unless required by applicable law or agreed to in writing, software |
| 11 | +distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | +See the License for the specific language governing permissions and |
| 14 | +limitations under the License. |
| 15 | +""" |
| 16 | + |
| 17 | +from copy import deepcopy |
| 18 | +from collections import namedtuple |
| 19 | +import warnings |
| 20 | +import cv2 |
| 21 | +try: |
| 22 | + from cv2.gapi.mx.pp import Resize, Crop, Padding |
| 23 | + _preprocessing_available = True |
| 24 | +except ImportError: |
| 25 | + Resize, Crop, Padding = None, None, None |
| 26 | + _preprocessing_available = False |
| 27 | +from ...utils import get_size_from_config, string_to_tuple |
| 28 | + |
| 29 | + |
| 30 | +def gapi_preprocess_available(): |
| 31 | + return _preprocessing_available |
| 32 | + |
| 33 | + |
| 34 | +PreprocessingOp = namedtuple('PreprocessingOp', ['name', 'value']) |
| 35 | + |
| 36 | + |
| 37 | +class GAPIPreprocessor: |
| 38 | + |
| 39 | + def __init__(self, config): |
| 40 | + self.SUPPORTED_PREPROCESSING_OPS = { |
| 41 | + 'resize': self.get_resize_op, |
| 42 | + 'crop': self.get_crop_op, |
| 43 | + 'padding': self.get_padding_op |
| 44 | + } |
| 45 | + if _preprocessing_available: |
| 46 | + self.RESIZE_INTERPOLATIONS = { |
| 47 | + 'LINEAR': cv2.gapi.mx.pp.Resize_Interpolation_BILINEAR, |
| 48 | + 'BILINEAR': cv2.gapi.mx.pp.Resize_Interpolation_BILINEAR, |
| 49 | + 'BICUBIC': cv2.gapi.mx.pp.Resize_Interpolation_BICUBIC, |
| 50 | + } |
| 51 | + self.RESIZE_ASPECT_RATIO = { |
| 52 | + 'greater': cv2.gapi.mx.pp.Resize_AspectRatioScale_GREATER, |
| 53 | + 'fit_to_window': cv2.gapi.mx.pp.Resize_AspectRatioScale_FIT_TO_WINDOW, |
| 54 | + 'height': cv2.gapi.mx.pp.Resize_AspectRatioScale_HEIGHT, |
| 55 | + 'width': cv2.gapi.mx.pp.Resize_AspectRatioScale_WIDTH, |
| 56 | + } |
| 57 | + self.PADDING_TYPE = { |
| 58 | + 'center': cv2.gapi.mx.pp.Padding_PadType_CENTER, |
| 59 | + 'right_bottom': cv2.gapi.mx.pp.Padding_PadType_RIGHT_BOTTOM, |
| 60 | + 'left_top': cv2.gapi.mx.pp.Padding_PadType_LEFT_TOP, |
| 61 | + } |
| 62 | + else: |
| 63 | + self.RESIZE_ASPECT_RATIO = {} |
| 64 | + self.RESIZE_INTERPOLATIONS = {} |
| 65 | + self.PADDING_TYPE = {} |
| 66 | + |
| 67 | + self.config = config or [] |
| 68 | + self.configure() |
| 69 | + |
| 70 | + def configure(self): |
| 71 | + steps = [] |
| 72 | + step_names = set() |
| 73 | + keep_preprocessing_config = deepcopy(self.config) |
| 74 | + for preprocessor in reversed(self.config): |
| 75 | + if preprocessor['type'] not in self.SUPPORTED_PREPROCESSING_OPS: |
| 76 | + break |
| 77 | + ie_ops = self.get_op(preprocessor) |
| 78 | + if not ie_ops: |
| 79 | + break |
| 80 | + if ie_ops.name in step_names: |
| 81 | + break |
| 82 | + step_names.add(ie_ops.name) |
| 83 | + steps.append(ie_ops) |
| 84 | + keep_preprocessing_config = keep_preprocessing_config[:-1] |
| 85 | + self.steps = steps |
| 86 | + self.keep_preprocessing_info = keep_preprocessing_config |
| 87 | + if not steps: |
| 88 | + warnings.warn('no preprocessing steps for transition to PreProcessInfo') |
| 89 | + |
| 90 | + def get_op(self, preprocessing_config): |
| 91 | + preprocessing_getter = self.SUPPORTED_PREPROCESSING_OPS[preprocessing_config['type']] |
| 92 | + return preprocessing_getter(preprocessing_config) |
| 93 | + |
| 94 | + def get_resize_op(self, config): |
| 95 | + aspect_ratio_cfg = config.get('aspect_ratio_scale') |
| 96 | + if aspect_ratio_cfg is not None and aspect_ratio_cfg not in self.RESIZE_ASPECT_RATIO: |
| 97 | + return None |
| 98 | + aspect_ratio = self.RESIZE_ASPECT_RATIO.get(aspect_ratio_cfg, cv2.gapi.mx.pp.Resize_AspectRatioScale_UNKNOWN) |
| 99 | + cfg_interpolation = config.get('interpolation', 'BILINEAR').upper() |
| 100 | + if cfg_interpolation not in self.RESIZE_INTERPOLATIONS: |
| 101 | + return None |
| 102 | + interpolation = self.RESIZE_INTERPOLATIONS[cfg_interpolation] |
| 103 | + height, width = get_size_from_config(config) |
| 104 | + return PreprocessingOp( |
| 105 | + 'resize_algorithm', Resize((width, height), interpolation=interpolation, aspect_ratio_scale=aspect_ratio) |
| 106 | + ) |
| 107 | + |
| 108 | + def has_resize(self): |
| 109 | + preprocessor_names = [step.name for step in self.steps] |
| 110 | + return 'resize_algorithm' in preprocessor_names |
| 111 | + |
| 112 | + @staticmethod |
| 113 | + def get_crop_op(config): |
| 114 | + if 'max_square' in config: |
| 115 | + return PreprocessingOp('crop', Crop(cv2.gapi.mx.pp.MaxSquare())) |
| 116 | + if 'central_fraction' in config: |
| 117 | + ratio = float(config['central_fraction']) |
| 118 | + return PreprocessingOp('crop', Crop(cv2.gapi.mx.pp.CentralFraction(ratio))) |
| 119 | + height, width = get_size_from_config(config) |
| 120 | + return PreprocessingOp('crop', Crop((width, height))) |
| 121 | + |
| 122 | + def get_padding_op(self, config): |
| 123 | + if 'numpy_pad_mode' in config and config['numpy_pad_mode'] != 'constant': |
| 124 | + return None |
| 125 | + height, width = get_size_from_config(config, allow_none=True) |
| 126 | + # gapi dos not support fully strided padding right now |
| 127 | + if height is None or width is None: |
| 128 | + return None |
| 129 | + pad_type = config.get('pad_type', 'center') |
| 130 | + if pad_type not in self.PADDING_TYPE: |
| 131 | + return None |
| 132 | + pad_t = self.PADDING_TYPE[pad_type] |
| 133 | + pad_val = config.get('pad_value', [0, 0, 0]) |
| 134 | + if isinstance(pad_val, str): |
| 135 | + pad_val = string_to_tuple(pad_val, int) |
| 136 | + if isinstance(pad_val, int): |
| 137 | + pad_val = [pad_val] * 3 |
| 138 | + if isinstance(pad_val, tuple): |
| 139 | + pad_val = list(pad_val) |
| 140 | + return PreprocessingOp('padding', Padding((width, height), pad_val, pad_type=pad_t)) |
0 commit comments