diff --git a/module/base/code_generator.py b/module/base/code_generator.py new file mode 100644 index 000000000..07a8d93b1 --- /dev/null +++ b/module/base/code_generator.py @@ -0,0 +1,168 @@ +import typing as t + + +class TabWrapper: + def __init__(self, generator, prefix='', suffix='', newline=True): + """ + Args: + generator (CodeGenerator): + """ + self.generator = generator + self.prefix = prefix + self.suffix = suffix + self.newline = newline + + self.nested = False + + def __enter__(self): + if not self.nested and self.prefix: + self.generator.add(self.prefix, newline=self.newline) + self.generator.tab_count += 1 + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.generator.tab_count -= 1 + if self.suffix: + self.generator.add(self.suffix) + + def __repr__(self): + return self.prefix + + def set_nested(self, suffix=''): + self.nested = True + self.suffix += suffix + + +class CodeGenerator: + def __init__(self): + self.tab_count = 0 + self.lines = [] + + def generate(self) -> t.Iterable[str]: + yield '' + + def add(self, line, comment=False, newline=True): + self.lines.append(self._line_with_tabs(line, comment=comment, newline=newline)) + + def print(self): + lines = ''.join(self.lines) + print(lines) + + def write(self, file: str = None): + lines = ''.join(self.lines) + with open(file, 'w', encoding='utf-8', newline='') as f: + f.write(lines) + + def _line_with_tabs(self, line, comment=False, newline=True): + if comment: + line = '# ' + line + out = ' ' * self.tab_count + line + if newline: + out += '\n' + return out + + def _repr(self, obj): + if isinstance(obj, str): + if '\n' in obj: + out = '"""\n' + with self.tab(): + for line in obj.strip().split('\n'): + line = line.strip() + out += self._line_with_tabs(line) + out += self._line_with_tabs('"""', newline=False) + return out + return repr(obj) + + def tab(self): + return TabWrapper(self) + + def Empty(self): + self.add('') + + def Import(self, text, empty=2): + for line in text.strip().split('\n'): + line = line.strip() + self.add(line) + for _ in range(empty): + self.Empty() + + def Value(self, key=None, value=None, type_=None, **kwargs): + if key is not None: + if type_ is not None: + self.add(f'{key}: {type_} = {self._repr(value)}') + else: + self.add(f'{key} = {self._repr(value)}') + for key, value in kwargs.items(): + self.Value(key, value) + + def Comment(self, text): + for line in text.strip().split('\n'): + line = line.strip() + self.add(line, comment=True) + + def List(self, key=None): + if key is not None: + return TabWrapper(self, prefix=str(key) + ' = [', suffix=']') + else: + return TabWrapper(self, prefix='[', suffix=']', newline=False) + + def ListItem(self, value): + if isinstance(value, TabWrapper): + value.set_nested(suffix=',') + self.add(f'{self._repr(value)}') + return value + else: + self.add(f'{self._repr(value)},') + + def Dict(self, key=None): + if key is not None: + return TabWrapper(self, prefix=str(key) + ' = {', suffix='}') + else: + return TabWrapper(self, prefix='{', suffix='}', newline=False) + + def DictItem(self, key=None, value=None): + if isinstance(value, TabWrapper): + value.set_nested(suffix=',') + if key is not None: + self.add(f'{self._repr(key)}: {self._repr(value)}') + return value + else: + if key is not None: + self.add(f'{self._repr(key)}: {self._repr(value)},') + + def Object(self, object_class, key=None): + if key is not None: + return TabWrapper(self, prefix=f'{key} = {object_class}(', suffix=')') + else: + return TabWrapper(self, prefix=f'{object_class}(', suffix=')', newline=False) + + def ObjectAttr(self, key=None, value=None): + if isinstance(value, TabWrapper): + value.set_nested(suffix=',') + if key is None: + self.add(f'{self._repr(value)}') + else: + self.add(f'{key}={self._repr(value)}') + return value + else: + if key is None: + self.add(f'{self._repr(value)},') + else: + self.add(f'{key}={self._repr(value)},') + + def Class(self, name, inherit=None): + if inherit is not None: + return TabWrapper(self, prefix=f'class {name}({inherit}):') + else: + return TabWrapper(self, prefix=f'class {name}:') + + def Def(self, name, args=''): + return TabWrapper(self, prefix=f'def {name}({args}):') + + +generator = CodeGenerator() +Import = generator.Import +Value = generator.Value +Comment = generator.Comment +Dict = generator.Dict +DictItem = generator.DictItem diff --git a/module/base/utils/grids.py b/module/base/utils/grids.py index 0c31465b0..69527c58a 100644 --- a/module/base/utils/grids.py +++ b/module/base/utils/grids.py @@ -176,9 +176,9 @@ class SelectedGrids: Returns: """ - if self: + try: return self.grids[0] - else: + except IndexError: return None def add(self, grids): diff --git a/module/base/utils/utils.py b/module/base/utils/utils.py index cf7fadd0c..6a3266884 100644 --- a/module/base/utils/utils.py +++ b/module/base/utils/utils.py @@ -194,6 +194,7 @@ def ensure_int(*args): def area_offset(area, offset): """ + Move an area. Args: area: (upper_left_x, upper_left_y, bottom_right_x, bottom_right_y). @@ -202,11 +203,14 @@ def area_offset(area, offset): Returns: tuple: (upper_left_x, upper_left_y, bottom_right_x, bottom_right_y). """ - return tuple(np.array(area) + np.append(offset, offset)) + upper_left_x, upper_left_y, bottom_right_x, bottom_right_y = area + x, y = offset + return upper_left_x + x, upper_left_y + y, bottom_right_x + x, bottom_right_y + y def area_pad(area, pad=10): """ + Inner offset an area. Args: area: (upper_left_x, upper_left_y, bottom_right_x, bottom_right_y). @@ -215,7 +219,8 @@ def area_pad(area, pad=10): Returns: tuple: (upper_left_x, upper_left_y, bottom_right_x, bottom_right_y). """ - return tuple(np.array(area) + np.array([pad, pad, -pad, -pad])) + upper_left_x, upper_left_y, bottom_right_x, bottom_right_y = area + return upper_left_x + pad, upper_left_y + pad, bottom_right_x - pad, bottom_right_y - pad def limit_in(x, lower, upper): @@ -526,7 +531,7 @@ def save_image(image, file): Image.fromarray(image).save(file) -def crop(image, area): +def crop(image, area, copy=True): """ Crop image like pillow, when using opencv / numpy. Provides a black background if cropping outside of image. @@ -534,6 +539,7 @@ def crop(image, area): Args: image (np.ndarray): area: + copy (bool): Returns: np.ndarray: @@ -542,9 +548,11 @@ def crop(image, area): h, w = image.shape[:2] border = np.maximum((0 - y1, y2 - h, 0 - x1, x2 - w), 0) x1, y1, x2, y2 = np.maximum((x1, y1, x2, y2), 0) - image = image[y1:y2, x1:x2].copy() + image = image[y1:y2, x1:x2] if sum(border) > 0: image = cv2.copyMakeBorder(image, *border, borderType=cv2.BORDER_CONSTANT, value=(0, 0, 0)) + if copy: + image = image.copy() return image @@ -656,7 +664,7 @@ def get_color(image, area): Returns: tuple: (r, g, b) """ - temp = crop(image, area) + temp = crop(image, area, copy=False) color = cv2.mean(temp) return color[:3] diff --git a/module/config/config_manual.py b/module/config/config_manual.py index e517d95d4..753d05fdb 100644 --- a/module/config/config_manual.py +++ b/module/config/config_manual.py @@ -16,6 +16,8 @@ class ManualConfig: module.assets """ ASSETS_FOLDER = './assets' + ASSETS_MODULE = './tasks' + ASSETS_RESOLUTION = (1280, 720) """ module.base