vkit.mechanism.distortion_policy.geometric.mls
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 Tuple, List 15 16import attrs 17from numpy.random import Generator as RandomGenerator 18 19from vkit.element import Point, PointList 20from vkit.mechanism import distortion 21from ..type import DistortionConfigGenerator, DistortionPolicyFactory 22from ..opt import sample_float, SampleFloatMode, generate_grid_size 23 24 25@attrs.define 26class SimilarityMlsConfigGeneratorConfig: 27 num_segments_min: int = 2 28 num_segments_max: int = 4 29 step_min: int = 10 30 radius_max_ratio_min: float = 0.025 31 radius_max_ratio_max: float = 0.125 32 grid_size_min: int = 15 33 grid_size_ratio: float = 0.01 34 35 36class SimilarityMlsConfigGenerator( 37 DistortionConfigGenerator[ 38 SimilarityMlsConfigGeneratorConfig, 39 distortion.SimilarityMlsConfig, 40 ] 41): # yapf: disable 42 43 @classmethod 44 def generate_coord(cls, length: int, step: int, rng: RandomGenerator): 45 end = length - 1 46 if end % step == 0: 47 steps = [step] * (end // step) 48 else: 49 steps = [step] * (end // step - 1) 50 steps.append(step + end % step) 51 assert sum(steps) == end 52 53 rng.shuffle(steps) 54 coord: List[int] = [0] 55 for step in steps: 56 pos = coord[-1] + step 57 coord.append(pos) 58 return coord 59 60 def __call__(self, shape: Tuple[int, int], rng: RandomGenerator): 61 # Generate control points. 62 short_side_length = min(shape) 63 num_segments = rng.integers(self.config.num_segments_min, self.config.num_segments_max + 1) 64 step = (short_side_length - 1) // num_segments 65 if step < self.config.step_min: 66 # Downgrade to corners if the gap is too small. 67 step = short_side_length - 1 68 69 height, width = shape 70 # NOTE: 71 # 1. Corners are always included. 72 # 2. Distance of any two points >= step. 73 coord_y = self.generate_coord(height, step, rng) 74 coord_x = self.generate_coord(width, step, rng) 75 src_handle_points = PointList() 76 for y in coord_y: 77 for x in coord_x: 78 src_handle_points.append(Point.create(y=y, x=x)) 79 80 # Generate deformed points. 81 assert self.config.radius_max_ratio_max < 0.5 82 radius_max_ratio = sample_float( 83 level=self.level, 84 value_min=self.config.radius_max_ratio_min, 85 value_max=self.config.radius_max_ratio_max, 86 prob_reciprocal=None, 87 rng=rng, 88 mode=SampleFloatMode.QUAD, 89 ) 90 radius = int(radius_max_ratio * step) 91 dst_handle_points = PointList() 92 for point in src_handle_points: 93 delta_y = rng.integers(-radius, radius + 1) 94 delta_x = rng.integers(-radius, radius + 1) 95 dst_handle_points.append(Point.create( 96 y=point.y + delta_y, 97 x=point.x + delta_x, 98 )) 99 100 # Generate grid size. 101 grid_size = generate_grid_size( 102 self.config.grid_size_min, 103 self.config.grid_size_ratio, 104 shape, 105 ) 106 107 return distortion.SimilarityMlsConfig( 108 src_handle_points=src_handle_points.to_point_tuple(), 109 dst_handle_points=dst_handle_points.to_point_tuple(), 110 grid_size=grid_size, 111 ) 112 113 114similarity_mls_policy_factory = DistortionPolicyFactory( 115 distortion.similarity_mls, 116 SimilarityMlsConfigGenerator, 117)
class
SimilarityMlsConfigGeneratorConfig:
27class SimilarityMlsConfigGeneratorConfig: 28 num_segments_min: int = 2 29 num_segments_max: int = 4 30 step_min: int = 10 31 radius_max_ratio_min: float = 0.025 32 radius_max_ratio_max: float = 0.125 33 grid_size_min: int = 15 34 grid_size_ratio: float = 0.01
SimilarityMlsConfigGeneratorConfig( num_segments_min: int = 2, num_segments_max: int = 4, step_min: int = 10, radius_max_ratio_min: float = 0.025, radius_max_ratio_max: float = 0.125, grid_size_min: int = 15, grid_size_ratio: float = 0.01)
2def __init__(self, num_segments_min=attr_dict['num_segments_min'].default, num_segments_max=attr_dict['num_segments_max'].default, step_min=attr_dict['step_min'].default, radius_max_ratio_min=attr_dict['radius_max_ratio_min'].default, radius_max_ratio_max=attr_dict['radius_max_ratio_max'].default, grid_size_min=attr_dict['grid_size_min'].default, grid_size_ratio=attr_dict['grid_size_ratio'].default): 3 self.num_segments_min = num_segments_min 4 self.num_segments_max = num_segments_max 5 self.step_min = step_min 6 self.radius_max_ratio_min = radius_max_ratio_min 7 self.radius_max_ratio_max = radius_max_ratio_max 8 self.grid_size_min = grid_size_min 9 self.grid_size_ratio = grid_size_ratio
Method generated by attrs for class SimilarityMlsConfigGeneratorConfig.
class
SimilarityMlsConfigGenerator(vkit.mechanism.distortion_policy.type.DistortionConfigGenerator[vkit.mechanism.distortion_policy.geometric.mls.SimilarityMlsConfigGeneratorConfig, vkit.mechanism.distortion.geometric.mls.SimilarityMlsConfig]):
37class SimilarityMlsConfigGenerator( 38 DistortionConfigGenerator[ 39 SimilarityMlsConfigGeneratorConfig, 40 distortion.SimilarityMlsConfig, 41 ] 42): # yapf: disable 43 44 @classmethod 45 def generate_coord(cls, length: int, step: int, rng: RandomGenerator): 46 end = length - 1 47 if end % step == 0: 48 steps = [step] * (end // step) 49 else: 50 steps = [step] * (end // step - 1) 51 steps.append(step + end % step) 52 assert sum(steps) == end 53 54 rng.shuffle(steps) 55 coord: List[int] = [0] 56 for step in steps: 57 pos = coord[-1] + step 58 coord.append(pos) 59 return coord 60 61 def __call__(self, shape: Tuple[int, int], rng: RandomGenerator): 62 # Generate control points. 63 short_side_length = min(shape) 64 num_segments = rng.integers(self.config.num_segments_min, self.config.num_segments_max + 1) 65 step = (short_side_length - 1) // num_segments 66 if step < self.config.step_min: 67 # Downgrade to corners if the gap is too small. 68 step = short_side_length - 1 69 70 height, width = shape 71 # NOTE: 72 # 1. Corners are always included. 73 # 2. Distance of any two points >= step. 74 coord_y = self.generate_coord(height, step, rng) 75 coord_x = self.generate_coord(width, step, rng) 76 src_handle_points = PointList() 77 for y in coord_y: 78 for x in coord_x: 79 src_handle_points.append(Point.create(y=y, x=x)) 80 81 # Generate deformed points. 82 assert self.config.radius_max_ratio_max < 0.5 83 radius_max_ratio = sample_float( 84 level=self.level, 85 value_min=self.config.radius_max_ratio_min, 86 value_max=self.config.radius_max_ratio_max, 87 prob_reciprocal=None, 88 rng=rng, 89 mode=SampleFloatMode.QUAD, 90 ) 91 radius = int(radius_max_ratio * step) 92 dst_handle_points = PointList() 93 for point in src_handle_points: 94 delta_y = rng.integers(-radius, radius + 1) 95 delta_x = rng.integers(-radius, radius + 1) 96 dst_handle_points.append(Point.create( 97 y=point.y + delta_y, 98 x=point.x + delta_x, 99 )) 100 101 # Generate grid size. 102 grid_size = generate_grid_size( 103 self.config.grid_size_min, 104 self.config.grid_size_ratio, 105 shape, 106 ) 107 108 return distortion.SimilarityMlsConfig( 109 src_handle_points=src_handle_points.to_point_tuple(), 110 dst_handle_points=dst_handle_points.to_point_tuple(), 111 grid_size=grid_size, 112 )
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
@classmethod
def
generate_coord(cls, length: int, step: int, rng: numpy.random._generator.Generator):
44 @classmethod 45 def generate_coord(cls, length: int, step: int, rng: RandomGenerator): 46 end = length - 1 47 if end % step == 0: 48 steps = [step] * (end // step) 49 else: 50 steps = [step] * (end // step - 1) 51 steps.append(step + end % step) 52 assert sum(steps) == end 53 54 rng.shuffle(steps) 55 coord: List[int] = [0] 56 for step in steps: 57 pos = coord[-1] + step 58 coord.append(pos) 59 return coord