vkit.mechanism.distortion.geometric.grid_rendering.interface

  1# Copyright 2022 vkit-x Administrator. All Rights Reserved.
  2#
  3# This project (vkit-x/vkit) is dual-licensed under commercial and SSPL licenses.
  4#
  5# The commercial license gives you the full rights to create and distribute software
  6# on your own terms without any SSPL license obligations. For more information,
  7# please see the "LICENSE_COMMERCIAL.txt" file.
  8#
  9# This project is also available under Server Side Public License (SSPL).
 10# The SSPL licensing is ideal for use cases such as open source projects with
 11# SSPL distribution, student/academic purposes, hobby projects, internal research
 12# projects without external distribution, or other projects where all SSPL
 13# obligations can be met. For more information, please see the "LICENSE_SSPL.txt" file.
 14from typing import (
 15    Generic,
 16    Type,
 17    TypeVar,
 18    Tuple,
 19    Optional,
 20)
 21
 22import numpy as np
 23from numpy.random import Generator as RandomGenerator
 24
 25from vkit.element import (
 26    Image,
 27    Point,
 28    Mask,
 29    ScoreMap,
 30)
 31from ...interface import (
 32    DistortionConfig,
 33    DistortionState,
 34    Distortion,
 35)
 36from .type import ImageGrid
 37from .point_projector import PointProjector
 38from .grid_creator import create_dst_image_grid_and_shift_amounts_and_resize_ratios
 39from .grid_blender import (
 40    blend_src_to_dst_image,
 41    blend_src_to_dst_score_map,
 42    blend_src_to_dst_mask,
 43)
 44
 45_T_CONFIG = TypeVar('_T_CONFIG', bound=DistortionConfig)
 46
 47
 48class DistortionStateImageGridBased(DistortionState[_T_CONFIG]):
 49
 50    @property
 51    def shift_amount_y(self):
 52        return self._shift_amount_y
 53
 54    @shift_amount_y.setter
 55    def shift_amount_y(self, val: float):
 56        self._shift_amount_y = val
 57
 58    @property
 59    def shift_amount_x(self):
 60        return self._shift_amount_x
 61
 62    @shift_amount_x.setter
 63    def shift_amount_x(self, val: float):
 64        self._shift_amount_x = val
 65
 66    @property
 67    def resize_ratio_y(self):
 68        return self._resize_ratio_y
 69
 70    @resize_ratio_y.setter
 71    def resize_ratio_y(self, val: float):
 72        self._resize_ratio_y = val
 73
 74    @property
 75    def resize_ratio_x(self):
 76        return self._resize_ratio_x
 77
 78    @resize_ratio_x.setter
 79    def resize_ratio_x(self, val: float):
 80        self._resize_ratio_x = val
 81
 82    @property
 83    def src_image_grid(self):
 84        return self._src_image_grid
 85
 86    @src_image_grid.setter
 87    def src_image_grid(self, val: ImageGrid):
 88        self._src_image_grid = val
 89
 90    @property
 91    def dst_image_grid(self):
 92        return self._dst_image_grid
 93
 94    @dst_image_grid.setter
 95    def dst_image_grid(self, val: ImageGrid):
 96        self._dst_image_grid = val
 97
 98    def initialize_image_grid_based(
 99        self,
100        src_image_grid: ImageGrid,
101        point_projector: PointProjector,
102        resize_as_src: bool = False,
103    ):
104        self.src_image_grid = src_image_grid
105
106        (
107            self.dst_image_grid,
108            (self.shift_amount_y, self.shift_amount_x),
109            (self.resize_ratio_y, self.resize_ratio_x),
110        ) = create_dst_image_grid_and_shift_amounts_and_resize_ratios(
111            self.src_image_grid,
112            point_projector,
113            resize_as_src=resize_as_src,
114        )
115
116    def shift_and_resize_point(self, point: Point):
117        return Point.create(
118            y=(point.smooth_y - self.shift_amount_y) * self.resize_ratio_y,
119            x=(point.smooth_x - self.shift_amount_x) * self.resize_ratio_x,
120        )
121
122    @property
123    def result_shape(self):
124        return (self.dst_image_grid.image_height, self.dst_image_grid.image_width)
125
126
127_T_STATE = TypeVar('_T_STATE', bound=DistortionStateImageGridBased)
128
129
130class FuncImageGridBased(Generic[_T_CONFIG, _T_STATE]):
131
132    @classmethod
133    def func_image(
134        cls,
135        config: _T_CONFIG,
136        state: Optional[_T_STATE],
137        image: Image,
138        rng: Optional[RandomGenerator],
139    ):
140        assert state
141        return blend_src_to_dst_image(
142            image,
143            state.src_image_grid,
144            state.dst_image_grid,
145        )
146
147    @classmethod
148    def func_score_map(
149        cls,
150        config: _T_CONFIG,
151        state: Optional[_T_STATE],
152        score_map: ScoreMap,
153        rng: Optional[RandomGenerator],
154    ):
155        assert state
156        return blend_src_to_dst_score_map(
157            score_map,
158            state.src_image_grid,
159            state.dst_image_grid,
160        )
161
162    @classmethod
163    def func_mask(
164        cls,
165        config: _T_CONFIG,
166        state: Optional[_T_STATE],
167        mask: Mask,
168        rng: Optional[RandomGenerator],
169    ):
170        assert state
171        return blend_src_to_dst_mask(
172            mask,
173            state.src_image_grid,
174            state.dst_image_grid,
175        )
176
177    @classmethod
178    def func_active_mask(
179        cls,
180        config: _T_CONFIG,
181        state: Optional[_T_STATE],
182        shape: Tuple[int, int],
183        rng: Optional[RandomGenerator],
184    ):
185        assert state
186        border_polygon = state.dst_image_grid.generate_border_polygon()
187        active_mask = Mask.from_shape((
188            state.dst_image_grid.image_height,
189            state.dst_image_grid.image_width,
190        ))
191        border_polygon.fill_mask(active_mask)
192        return active_mask
193
194    @classmethod
195    def func_point(
196        cls,
197        config: _T_CONFIG,
198        state: Optional[_T_STATE],
199        shape: Tuple[int, int],
200        point: Point,
201        rng: Optional[RandomGenerator],
202    ):
203        assert state
204        src_image_grid = state.src_image_grid
205        dst_image_grid = state.dst_image_grid
206
207        assert src_image_grid.grid_size
208        polygon_row = point.y // src_image_grid.grid_size
209        polygon_col = point.x // src_image_grid.grid_size
210
211        trans_mat = src_image_grid.get_trans_mat(polygon_row, polygon_col, dst_image_grid)
212        dst_tx, dst_ty, dst_t = np.matmul(trans_mat, (point.smooth_x, point.smooth_y, 1.0))
213        return Point.create(
214            y=float(dst_ty / dst_t),
215            x=float(dst_tx / dst_t),
216        )
217
218
219class DistortionImageGridBased(Distortion[_T_CONFIG, _T_STATE]):
220
221    def __init__(
222        self,
223        config_cls: Type[_T_CONFIG],
224        state_cls: Type[_T_STATE],
225    ):
226        func_cls = FuncImageGridBased[_T_CONFIG, _T_STATE]
227        super().__init__(
228            config_cls=config_cls,
229            state_cls=state_cls,
230            func_image=func_cls.func_image,
231            func_mask=func_cls.func_mask,
232            func_score_map=func_cls.func_score_map,
233            func_active_mask=func_cls.func_active_mask,
234            func_point=func_cls.func_point,
235        )
class DistortionStateImageGridBased(vkit.mechanism.distortion.interface.DistortionState[~_T_CONFIG]):
 49class DistortionStateImageGridBased(DistortionState[_T_CONFIG]):
 50
 51    @property
 52    def shift_amount_y(self):
 53        return self._shift_amount_y
 54
 55    @shift_amount_y.setter
 56    def shift_amount_y(self, val: float):
 57        self._shift_amount_y = val
 58
 59    @property
 60    def shift_amount_x(self):
 61        return self._shift_amount_x
 62
 63    @shift_amount_x.setter
 64    def shift_amount_x(self, val: float):
 65        self._shift_amount_x = val
 66
 67    @property
 68    def resize_ratio_y(self):
 69        return self._resize_ratio_y
 70
 71    @resize_ratio_y.setter
 72    def resize_ratio_y(self, val: float):
 73        self._resize_ratio_y = val
 74
 75    @property
 76    def resize_ratio_x(self):
 77        return self._resize_ratio_x
 78
 79    @resize_ratio_x.setter
 80    def resize_ratio_x(self, val: float):
 81        self._resize_ratio_x = val
 82
 83    @property
 84    def src_image_grid(self):
 85        return self._src_image_grid
 86
 87    @src_image_grid.setter
 88    def src_image_grid(self, val: ImageGrid):
 89        self._src_image_grid = val
 90
 91    @property
 92    def dst_image_grid(self):
 93        return self._dst_image_grid
 94
 95    @dst_image_grid.setter
 96    def dst_image_grid(self, val: ImageGrid):
 97        self._dst_image_grid = val
 98
 99    def initialize_image_grid_based(
100        self,
101        src_image_grid: ImageGrid,
102        point_projector: PointProjector,
103        resize_as_src: bool = False,
104    ):
105        self.src_image_grid = src_image_grid
106
107        (
108            self.dst_image_grid,
109            (self.shift_amount_y, self.shift_amount_x),
110            (self.resize_ratio_y, self.resize_ratio_x),
111        ) = create_dst_image_grid_and_shift_amounts_and_resize_ratios(
112            self.src_image_grid,
113            point_projector,
114            resize_as_src=resize_as_src,
115        )
116
117    def shift_and_resize_point(self, point: Point):
118        return Point.create(
119            y=(point.smooth_y - self.shift_amount_y) * self.resize_ratio_y,
120            x=(point.smooth_x - self.shift_amount_x) * self.resize_ratio_x,
121        )
122
123    @property
124    def result_shape(self):
125        return (self.dst_image_grid.image_height, self.dst_image_grid.image_width)

Abstract base class for generic types.

A generic type is typically declared by inheriting from this class parameterized with one or more type variables. For example, a generic mapping type might be defined as::

class Mapping(Generic[KT, VT]): def __getitem__(self, key: KT) -> VT: ... # Etc.

This class can then be used as follows::

def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT: try: return mapping[key] except KeyError: return default

def initialize_image_grid_based( self, src_image_grid: vkit.mechanism.distortion.geometric.grid_rendering.type.ImageGrid, point_projector: vkit.mechanism.distortion.geometric.grid_rendering.point_projector.PointProjector, resize_as_src: bool = False):
 99    def initialize_image_grid_based(
100        self,
101        src_image_grid: ImageGrid,
102        point_projector: PointProjector,
103        resize_as_src: bool = False,
104    ):
105        self.src_image_grid = src_image_grid
106
107        (
108            self.dst_image_grid,
109            (self.shift_amount_y, self.shift_amount_x),
110            (self.resize_ratio_y, self.resize_ratio_x),
111        ) = create_dst_image_grid_and_shift_amounts_and_resize_ratios(
112            self.src_image_grid,
113            point_projector,
114            resize_as_src=resize_as_src,
115        )
def shift_and_resize_point(self, point: vkit.element.point.Point):
117    def shift_and_resize_point(self, point: Point):
118        return Point.create(
119            y=(point.smooth_y - self.shift_amount_y) * self.resize_ratio_y,
120            x=(point.smooth_x - self.shift_amount_x) * self.resize_ratio_x,
121        )
class FuncImageGridBased(typing.Generic[~_T_CONFIG, ~_T_STATE]):
131class FuncImageGridBased(Generic[_T_CONFIG, _T_STATE]):
132
133    @classmethod
134    def func_image(
135        cls,
136        config: _T_CONFIG,
137        state: Optional[_T_STATE],
138        image: Image,
139        rng: Optional[RandomGenerator],
140    ):
141        assert state
142        return blend_src_to_dst_image(
143            image,
144            state.src_image_grid,
145            state.dst_image_grid,
146        )
147
148    @classmethod
149    def func_score_map(
150        cls,
151        config: _T_CONFIG,
152        state: Optional[_T_STATE],
153        score_map: ScoreMap,
154        rng: Optional[RandomGenerator],
155    ):
156        assert state
157        return blend_src_to_dst_score_map(
158            score_map,
159            state.src_image_grid,
160            state.dst_image_grid,
161        )
162
163    @classmethod
164    def func_mask(
165        cls,
166        config: _T_CONFIG,
167        state: Optional[_T_STATE],
168        mask: Mask,
169        rng: Optional[RandomGenerator],
170    ):
171        assert state
172        return blend_src_to_dst_mask(
173            mask,
174            state.src_image_grid,
175            state.dst_image_grid,
176        )
177
178    @classmethod
179    def func_active_mask(
180        cls,
181        config: _T_CONFIG,
182        state: Optional[_T_STATE],
183        shape: Tuple[int, int],
184        rng: Optional[RandomGenerator],
185    ):
186        assert state
187        border_polygon = state.dst_image_grid.generate_border_polygon()
188        active_mask = Mask.from_shape((
189            state.dst_image_grid.image_height,
190            state.dst_image_grid.image_width,
191        ))
192        border_polygon.fill_mask(active_mask)
193        return active_mask
194
195    @classmethod
196    def func_point(
197        cls,
198        config: _T_CONFIG,
199        state: Optional[_T_STATE],
200        shape: Tuple[int, int],
201        point: Point,
202        rng: Optional[RandomGenerator],
203    ):
204        assert state
205        src_image_grid = state.src_image_grid
206        dst_image_grid = state.dst_image_grid
207
208        assert src_image_grid.grid_size
209        polygon_row = point.y // src_image_grid.grid_size
210        polygon_col = point.x // src_image_grid.grid_size
211
212        trans_mat = src_image_grid.get_trans_mat(polygon_row, polygon_col, dst_image_grid)
213        dst_tx, dst_ty, dst_t = np.matmul(trans_mat, (point.smooth_x, point.smooth_y, 1.0))
214        return Point.create(
215            y=float(dst_ty / dst_t),
216            x=float(dst_tx / dst_t),
217        )

Abstract base class for generic types.

A generic type is typically declared by inheriting from this class parameterized with one or more type variables. For example, a generic mapping type might be defined as::

class Mapping(Generic[KT, VT]): def __getitem__(self, key: KT) -> VT: ... # Etc.

This class can then be used as follows::

def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT: try: return mapping[key] except KeyError: return default

FuncImageGridBased()
@classmethod
def func_image( cls, config: ~_T_CONFIG, state: Union[~_T_STATE, NoneType], image: vkit.element.image.Image, rng: Union[numpy.random._generator.Generator, NoneType]):
133    @classmethod
134    def func_image(
135        cls,
136        config: _T_CONFIG,
137        state: Optional[_T_STATE],
138        image: Image,
139        rng: Optional[RandomGenerator],
140    ):
141        assert state
142        return blend_src_to_dst_image(
143            image,
144            state.src_image_grid,
145            state.dst_image_grid,
146        )
@classmethod
def func_score_map( cls, config: ~_T_CONFIG, state: Union[~_T_STATE, NoneType], score_map: vkit.element.score_map.ScoreMap, rng: Union[numpy.random._generator.Generator, NoneType]):
148    @classmethod
149    def func_score_map(
150        cls,
151        config: _T_CONFIG,
152        state: Optional[_T_STATE],
153        score_map: ScoreMap,
154        rng: Optional[RandomGenerator],
155    ):
156        assert state
157        return blend_src_to_dst_score_map(
158            score_map,
159            state.src_image_grid,
160            state.dst_image_grid,
161        )
@classmethod
def func_mask( cls, config: ~_T_CONFIG, state: Union[~_T_STATE, NoneType], mask: vkit.element.mask.Mask, rng: Union[numpy.random._generator.Generator, NoneType]):
163    @classmethod
164    def func_mask(
165        cls,
166        config: _T_CONFIG,
167        state: Optional[_T_STATE],
168        mask: Mask,
169        rng: Optional[RandomGenerator],
170    ):
171        assert state
172        return blend_src_to_dst_mask(
173            mask,
174            state.src_image_grid,
175            state.dst_image_grid,
176        )
@classmethod
def func_active_mask( cls, config: ~_T_CONFIG, state: Union[~_T_STATE, NoneType], shape: Tuple[int, int], rng: Union[numpy.random._generator.Generator, NoneType]):
178    @classmethod
179    def func_active_mask(
180        cls,
181        config: _T_CONFIG,
182        state: Optional[_T_STATE],
183        shape: Tuple[int, int],
184        rng: Optional[RandomGenerator],
185    ):
186        assert state
187        border_polygon = state.dst_image_grid.generate_border_polygon()
188        active_mask = Mask.from_shape((
189            state.dst_image_grid.image_height,
190            state.dst_image_grid.image_width,
191        ))
192        border_polygon.fill_mask(active_mask)
193        return active_mask
@classmethod
def func_point( cls, config: ~_T_CONFIG, state: Union[~_T_STATE, NoneType], shape: Tuple[int, int], point: vkit.element.point.Point, rng: Union[numpy.random._generator.Generator, NoneType]):
195    @classmethod
196    def func_point(
197        cls,
198        config: _T_CONFIG,
199        state: Optional[_T_STATE],
200        shape: Tuple[int, int],
201        point: Point,
202        rng: Optional[RandomGenerator],
203    ):
204        assert state
205        src_image_grid = state.src_image_grid
206        dst_image_grid = state.dst_image_grid
207
208        assert src_image_grid.grid_size
209        polygon_row = point.y // src_image_grid.grid_size
210        polygon_col = point.x // src_image_grid.grid_size
211
212        trans_mat = src_image_grid.get_trans_mat(polygon_row, polygon_col, dst_image_grid)
213        dst_tx, dst_ty, dst_t = np.matmul(trans_mat, (point.smooth_x, point.smooth_y, 1.0))
214        return Point.create(
215            y=float(dst_ty / dst_t),
216            x=float(dst_tx / dst_t),
217        )
class DistortionImageGridBased(vkit.mechanism.distortion.interface.Distortion[~_T_CONFIG, ~_T_STATE]):
220class DistortionImageGridBased(Distortion[_T_CONFIG, _T_STATE]):
221
222    def __init__(
223        self,
224        config_cls: Type[_T_CONFIG],
225        state_cls: Type[_T_STATE],
226    ):
227        func_cls = FuncImageGridBased[_T_CONFIG, _T_STATE]
228        super().__init__(
229            config_cls=config_cls,
230            state_cls=state_cls,
231            func_image=func_cls.func_image,
232            func_mask=func_cls.func_mask,
233            func_score_map=func_cls.func_score_map,
234            func_active_mask=func_cls.func_active_mask,
235            func_point=func_cls.func_point,
236        )

Abstract base class for generic types.

A generic type is typically declared by inheriting from this class parameterized with one or more type variables. For example, a generic mapping type might be defined as::

class Mapping(Generic[KT, VT]): def __getitem__(self, key: KT) -> VT: ... # Etc.

This class can then be used as follows::

def lookup_name(mapping: Mapping[KT, VT], key: KT, default: VT) -> VT: try: return mapping[key] except KeyError: return default

DistortionImageGridBased(config_cls: Type[~_T_CONFIG], state_cls: Type[~_T_STATE])
222    def __init__(
223        self,
224        config_cls: Type[_T_CONFIG],
225        state_cls: Type[_T_STATE],
226    ):
227        func_cls = FuncImageGridBased[_T_CONFIG, _T_STATE]
228        super().__init__(
229            config_cls=config_cls,
230            state_cls=state_cls,
231            func_image=func_cls.func_image,
232            func_mask=func_cls.func_mask,
233            func_score_map=func_cls.func_score_map,
234            func_active_mask=func_cls.func_active_mask,
235            func_point=func_cls.func_point,
236        )