vkit.mechanism.distortion_policy.geometric.camera
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 15 16import attrs 17from numpy.random import Generator as RandomGenerator 18import numpy as np 19 20from vkit.mechanism import distortion 21from ..type import DistortionConfigGenerator, DistortionPolicyFactory 22from ..opt import sample_int, sample_float, generate_grid_size 23 24 25def sample_camera_model_config( 26 level: int, 27 level_1_max: int, 28 rotation_theta_max: int, 29 vec_z_max: float, 30 rng: RandomGenerator, 31): 32 rotation_theta = sample_int( 33 level=level, 34 value_min=1, 35 value_max=rotation_theta_max, 36 prob_negative=0.5, 37 rng=rng, 38 ) 39 40 theta_xy = rng.uniform(0, 2 * np.pi) 41 vec_x = np.cos(theta_xy) 42 vec_y = np.sin(theta_xy) 43 vec_z = 0.0 44 45 if level > level_1_max: 46 # NOTE: 47 # 1. rotation_unit_vec will be normalized to unit vector in 48 # CameraModel.prep_rotation_unit_vec. 49 # 2. If vec_z is 1.0, the camera model is equivalent to affine rotation. 50 vec_z = rng.uniform(0, vec_z_max) 51 vec_x = (1 - vec_z) * vec_x 52 vec_y = (1 - vec_z) * vec_y 53 54 return distortion.CameraModelConfig( 55 rotation_unit_vec=[vec_x, vec_y, vec_z], 56 rotation_theta=rotation_theta, 57 ) 58 59 60@attrs.define 61class CameraPlaneOnlyConfigGeneratorConfig: 62 level_1_max: int = 5 63 rotation_theta_max: int = 17 64 vec_z_max: float = 0.5 65 grid_size_min: int = 15 66 grid_size_ratio: float = 0.01 67 68 69class CameraPlaneOnlyConfigGenerator( 70 DistortionConfigGenerator[ 71 CameraPlaneOnlyConfigGeneratorConfig, 72 distortion.CameraPlaneOnlyConfig, 73 ] 74): # yapf: disable 75 76 def __call__(self, shape: Tuple[int, int], rng: RandomGenerator): 77 camera_model_config = sample_camera_model_config( 78 level=self.level, 79 level_1_max=self.config.level_1_max, 80 vec_z_max=self.config.vec_z_max, 81 rotation_theta_max=self.config.rotation_theta_max, 82 rng=rng, 83 ) 84 grid_size = generate_grid_size( 85 self.config.grid_size_min, 86 self.config.grid_size_ratio, 87 shape, 88 ) 89 return distortion.CameraPlaneOnlyConfig( 90 camera_model_config=camera_model_config, 91 grid_size=grid_size, 92 ) 93 94 95camera_plane_only_policy_factory = DistortionPolicyFactory( 96 distortion.camera_plane_only, 97 CameraPlaneOnlyConfigGenerator, 98) 99 100 101@attrs.define 102class CameraCubicCurveConfigGeneratorConfig: 103 curve_slope_range_min: float = 10.0 104 curve_slope_range_max: float = 90.0 105 curve_slope_max: float = 45 106 level_1_max: int = 5 107 rotation_theta_max: int = 17 108 vec_z_max: float = 0.5 109 grid_size_min: int = 15 110 grid_size_ratio: float = 0.01 111 112 113class CameraCubicCurveConfigGenerator( 114 DistortionConfigGenerator[ 115 CameraCubicCurveConfigGeneratorConfig, 116 distortion.CameraCubicCurveConfig, 117 ] 118): # yapf: disable 119 120 def __call__(self, shape: Tuple[int, int], rng: RandomGenerator): 121 curve_slope_range = sample_float( 122 level=self.level, 123 value_min=self.config.curve_slope_range_min, 124 value_max=self.config.curve_slope_range_max, 125 prob_reciprocal=None, 126 rng=rng, 127 ) 128 alpha_ratio = rng.uniform() 129 curve_alpha = curve_slope_range * alpha_ratio 130 curve_beta = curve_slope_range - curve_alpha 131 132 # Clip. 133 curve_alpha = min(self.config.curve_slope_max, curve_alpha) 134 curve_beta = min(self.config.curve_slope_max, curve_beta) 135 136 if rng.random() < 0.5: 137 curve_alpha *= -1 138 if rng.random() < 0.5: 139 curve_beta *= -1 140 141 curve_direction = rng.uniform(0, 180) 142 143 camera_model_config = sample_camera_model_config( 144 level=self.level, 145 level_1_max=self.config.level_1_max, 146 rotation_theta_max=self.config.rotation_theta_max, 147 vec_z_max=self.config.vec_z_max, 148 rng=rng, 149 ) 150 grid_size = generate_grid_size( 151 self.config.grid_size_min, 152 self.config.grid_size_ratio, 153 shape, 154 ) 155 return distortion.CameraCubicCurveConfig( 156 curve_alpha=curve_alpha, 157 curve_beta=curve_beta, 158 curve_direction=curve_direction, 159 curve_scale=1.0, 160 camera_model_config=camera_model_config, 161 grid_size=grid_size, 162 ) 163 164 165camera_cubic_curve_policy_factory = DistortionPolicyFactory( 166 distortion.camera_cubic_curve, 167 CameraCubicCurveConfigGenerator, 168) 169 170 171@attrs.define 172class CameraPlaneLineFoldConfigGeneratorConfig: 173 fold_alpha_min: float = 0.1 174 fold_alpha_max: float = 1.25 175 level_1_max: int = 5 176 rotation_theta_max: int = 17 177 vec_z_max: float = 0.5 178 grid_size_min: int = 15 179 grid_size_ratio: float = 0.01 180 181 182class CameraPlaneLineFoldConfigGenerator( 183 DistortionConfigGenerator[ 184 CameraPlaneLineFoldConfigGeneratorConfig, 185 distortion.CameraPlaneLineFoldConfig, 186 ] 187): # yapf: disable 188 189 def __call__(self, shape: Tuple[int, int], rng: RandomGenerator): 190 height, width = shape 191 fold_point = (rng.integers(0, width), rng.integers(0, height)) 192 193 fold_direction = rng.uniform(0, 180) 194 195 fold_perturb_vec_z = max(shape) / 4 196 if rng.random() < 0.5: 197 fold_perturb_vec_z *= -1.0 198 fold_perturb_vec = (0.0, 0.0, fold_perturb_vec_z) 199 200 fold_alpha = sample_float( 201 level=self.level, 202 value_min=self.config.fold_alpha_min, 203 value_max=self.config.fold_alpha_max, 204 prob_reciprocal=None, 205 rng=rng, 206 inverse_level=True, 207 ) 208 209 camera_model_config = sample_camera_model_config( 210 level=self.level, 211 level_1_max=self.config.level_1_max, 212 rotation_theta_max=self.config.rotation_theta_max, 213 vec_z_max=self.config.vec_z_max, 214 rng=rng, 215 ) 216 grid_size = generate_grid_size( 217 self.config.grid_size_min, 218 self.config.grid_size_ratio, 219 shape, 220 ) 221 return distortion.CameraPlaneLineFoldConfig( 222 fold_point=fold_point, 223 fold_direction=fold_direction, 224 fold_perturb_vec=fold_perturb_vec, 225 fold_alpha=fold_alpha, 226 camera_model_config=camera_model_config, 227 grid_size=grid_size, 228 ) 229 230 231camera_plane_line_fold_policy_factory = DistortionPolicyFactory( 232 distortion.camera_plane_line_fold, 233 CameraPlaneLineFoldConfigGenerator, 234) 235 236 237@attrs.define 238class CameraPlaneLineCurveConfigGeneratorConfig: 239 curve_alpha_min: float = 1.0 240 curve_alpha_max: float = 2.0 241 level_1_max: int = 5 242 rotation_theta_max: int = 17 243 vec_z_max: float = 0.5 244 grid_size_min: int = 15 245 grid_size_ratio: float = 0.01 246 247 248class CameraPlaneLineCurveConfigGenerator( 249 DistortionConfigGenerator[ 250 CameraPlaneLineCurveConfigGeneratorConfig, 251 distortion.CameraPlaneLineCurveConfig, 252 ] 253): # yapf: disable 254 255 def __call__(self, shape: Tuple[int, int], rng: RandomGenerator): 256 height, width = shape 257 curve_point = (rng.integers(0, width), rng.integers(0, height)) 258 259 curve_direction = rng.uniform(0, 180) 260 261 curve_perturb_vec_z = max(shape) / 4 262 if rng.random() < 0.5: 263 curve_perturb_vec_z *= -1.0 264 curve_perturb_vec = (0.0, 0.0, curve_perturb_vec_z) 265 266 curve_alpha = sample_float( 267 level=self.level, 268 value_min=self.config.curve_alpha_min, 269 value_max=self.config.curve_alpha_max, 270 prob_reciprocal=None, 271 rng=rng, 272 inverse_level=True, 273 ) 274 275 camera_model_config = sample_camera_model_config( 276 level=self.level, 277 level_1_max=self.config.level_1_max, 278 rotation_theta_max=self.config.rotation_theta_max, 279 vec_z_max=self.config.vec_z_max, 280 rng=rng, 281 ) 282 grid_size = generate_grid_size( 283 self.config.grid_size_min, 284 self.config.grid_size_ratio, 285 shape, 286 ) 287 return distortion.CameraPlaneLineCurveConfig( 288 curve_point=curve_point, 289 curve_direction=curve_direction, 290 curve_perturb_vec=curve_perturb_vec, 291 curve_alpha=curve_alpha, 292 camera_model_config=camera_model_config, 293 grid_size=grid_size, 294 ) 295 296 297camera_plane_line_curve_policy_factory = DistortionPolicyFactory( 298 distortion.camera_plane_line_curve, 299 CameraPlaneLineCurveConfigGenerator, 300)
26def sample_camera_model_config( 27 level: int, 28 level_1_max: int, 29 rotation_theta_max: int, 30 vec_z_max: float, 31 rng: RandomGenerator, 32): 33 rotation_theta = sample_int( 34 level=level, 35 value_min=1, 36 value_max=rotation_theta_max, 37 prob_negative=0.5, 38 rng=rng, 39 ) 40 41 theta_xy = rng.uniform(0, 2 * np.pi) 42 vec_x = np.cos(theta_xy) 43 vec_y = np.sin(theta_xy) 44 vec_z = 0.0 45 46 if level > level_1_max: 47 # NOTE: 48 # 1. rotation_unit_vec will be normalized to unit vector in 49 # CameraModel.prep_rotation_unit_vec. 50 # 2. If vec_z is 1.0, the camera model is equivalent to affine rotation. 51 vec_z = rng.uniform(0, vec_z_max) 52 vec_x = (1 - vec_z) * vec_x 53 vec_y = (1 - vec_z) * vec_y 54 55 return distortion.CameraModelConfig( 56 rotation_unit_vec=[vec_x, vec_y, vec_z], 57 rotation_theta=rotation_theta, 58 )
62class CameraPlaneOnlyConfigGeneratorConfig: 63 level_1_max: int = 5 64 rotation_theta_max: int = 17 65 vec_z_max: float = 0.5 66 grid_size_min: int = 15 67 grid_size_ratio: float = 0.01
2def __init__(self, level_1_max=attr_dict['level_1_max'].default, rotation_theta_max=attr_dict['rotation_theta_max'].default, vec_z_max=attr_dict['vec_z_max'].default, grid_size_min=attr_dict['grid_size_min'].default, grid_size_ratio=attr_dict['grid_size_ratio'].default): 3 self.level_1_max = level_1_max 4 self.rotation_theta_max = rotation_theta_max 5 self.vec_z_max = vec_z_max 6 self.grid_size_min = grid_size_min 7 self.grid_size_ratio = grid_size_ratio
Method generated by attrs for class CameraPlaneOnlyConfigGeneratorConfig.
70class CameraPlaneOnlyConfigGenerator( 71 DistortionConfigGenerator[ 72 CameraPlaneOnlyConfigGeneratorConfig, 73 distortion.CameraPlaneOnlyConfig, 74 ] 75): # yapf: disable 76 77 def __call__(self, shape: Tuple[int, int], rng: RandomGenerator): 78 camera_model_config = sample_camera_model_config( 79 level=self.level, 80 level_1_max=self.config.level_1_max, 81 vec_z_max=self.config.vec_z_max, 82 rotation_theta_max=self.config.rotation_theta_max, 83 rng=rng, 84 ) 85 grid_size = generate_grid_size( 86 self.config.grid_size_min, 87 self.config.grid_size_ratio, 88 shape, 89 ) 90 return distortion.CameraPlaneOnlyConfig( 91 camera_model_config=camera_model_config, 92 grid_size=grid_size, 93 )
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
103class CameraCubicCurveConfigGeneratorConfig: 104 curve_slope_range_min: float = 10.0 105 curve_slope_range_max: float = 90.0 106 curve_slope_max: float = 45 107 level_1_max: int = 5 108 rotation_theta_max: int = 17 109 vec_z_max: float = 0.5 110 grid_size_min: int = 15 111 grid_size_ratio: float = 0.01
2def __init__(self, curve_slope_range_min=attr_dict['curve_slope_range_min'].default, curve_slope_range_max=attr_dict['curve_slope_range_max'].default, curve_slope_max=attr_dict['curve_slope_max'].default, level_1_max=attr_dict['level_1_max'].default, rotation_theta_max=attr_dict['rotation_theta_max'].default, vec_z_max=attr_dict['vec_z_max'].default, grid_size_min=attr_dict['grid_size_min'].default, grid_size_ratio=attr_dict['grid_size_ratio'].default): 3 self.curve_slope_range_min = curve_slope_range_min 4 self.curve_slope_range_max = curve_slope_range_max 5 self.curve_slope_max = curve_slope_max 6 self.level_1_max = level_1_max 7 self.rotation_theta_max = rotation_theta_max 8 self.vec_z_max = vec_z_max 9 self.grid_size_min = grid_size_min 10 self.grid_size_ratio = grid_size_ratio
Method generated by attrs for class CameraCubicCurveConfigGeneratorConfig.
114class CameraCubicCurveConfigGenerator( 115 DistortionConfigGenerator[ 116 CameraCubicCurveConfigGeneratorConfig, 117 distortion.CameraCubicCurveConfig, 118 ] 119): # yapf: disable 120 121 def __call__(self, shape: Tuple[int, int], rng: RandomGenerator): 122 curve_slope_range = sample_float( 123 level=self.level, 124 value_min=self.config.curve_slope_range_min, 125 value_max=self.config.curve_slope_range_max, 126 prob_reciprocal=None, 127 rng=rng, 128 ) 129 alpha_ratio = rng.uniform() 130 curve_alpha = curve_slope_range * alpha_ratio 131 curve_beta = curve_slope_range - curve_alpha 132 133 # Clip. 134 curve_alpha = min(self.config.curve_slope_max, curve_alpha) 135 curve_beta = min(self.config.curve_slope_max, curve_beta) 136 137 if rng.random() < 0.5: 138 curve_alpha *= -1 139 if rng.random() < 0.5: 140 curve_beta *= -1 141 142 curve_direction = rng.uniform(0, 180) 143 144 camera_model_config = sample_camera_model_config( 145 level=self.level, 146 level_1_max=self.config.level_1_max, 147 rotation_theta_max=self.config.rotation_theta_max, 148 vec_z_max=self.config.vec_z_max, 149 rng=rng, 150 ) 151 grid_size = generate_grid_size( 152 self.config.grid_size_min, 153 self.config.grid_size_ratio, 154 shape, 155 ) 156 return distortion.CameraCubicCurveConfig( 157 curve_alpha=curve_alpha, 158 curve_beta=curve_beta, 159 curve_direction=curve_direction, 160 curve_scale=1.0, 161 camera_model_config=camera_model_config, 162 grid_size=grid_size, 163 )
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
173class CameraPlaneLineFoldConfigGeneratorConfig: 174 fold_alpha_min: float = 0.1 175 fold_alpha_max: float = 1.25 176 level_1_max: int = 5 177 rotation_theta_max: int = 17 178 vec_z_max: float = 0.5 179 grid_size_min: int = 15 180 grid_size_ratio: float = 0.01
2def __init__(self, fold_alpha_min=attr_dict['fold_alpha_min'].default, fold_alpha_max=attr_dict['fold_alpha_max'].default, level_1_max=attr_dict['level_1_max'].default, rotation_theta_max=attr_dict['rotation_theta_max'].default, vec_z_max=attr_dict['vec_z_max'].default, grid_size_min=attr_dict['grid_size_min'].default, grid_size_ratio=attr_dict['grid_size_ratio'].default): 3 self.fold_alpha_min = fold_alpha_min 4 self.fold_alpha_max = fold_alpha_max 5 self.level_1_max = level_1_max 6 self.rotation_theta_max = rotation_theta_max 7 self.vec_z_max = vec_z_max 8 self.grid_size_min = grid_size_min 9 self.grid_size_ratio = grid_size_ratio
Method generated by attrs for class CameraPlaneLineFoldConfigGeneratorConfig.
183class CameraPlaneLineFoldConfigGenerator( 184 DistortionConfigGenerator[ 185 CameraPlaneLineFoldConfigGeneratorConfig, 186 distortion.CameraPlaneLineFoldConfig, 187 ] 188): # yapf: disable 189 190 def __call__(self, shape: Tuple[int, int], rng: RandomGenerator): 191 height, width = shape 192 fold_point = (rng.integers(0, width), rng.integers(0, height)) 193 194 fold_direction = rng.uniform(0, 180) 195 196 fold_perturb_vec_z = max(shape) / 4 197 if rng.random() < 0.5: 198 fold_perturb_vec_z *= -1.0 199 fold_perturb_vec = (0.0, 0.0, fold_perturb_vec_z) 200 201 fold_alpha = sample_float( 202 level=self.level, 203 value_min=self.config.fold_alpha_min, 204 value_max=self.config.fold_alpha_max, 205 prob_reciprocal=None, 206 rng=rng, 207 inverse_level=True, 208 ) 209 210 camera_model_config = sample_camera_model_config( 211 level=self.level, 212 level_1_max=self.config.level_1_max, 213 rotation_theta_max=self.config.rotation_theta_max, 214 vec_z_max=self.config.vec_z_max, 215 rng=rng, 216 ) 217 grid_size = generate_grid_size( 218 self.config.grid_size_min, 219 self.config.grid_size_ratio, 220 shape, 221 ) 222 return distortion.CameraPlaneLineFoldConfig( 223 fold_point=fold_point, 224 fold_direction=fold_direction, 225 fold_perturb_vec=fold_perturb_vec, 226 fold_alpha=fold_alpha, 227 camera_model_config=camera_model_config, 228 grid_size=grid_size, 229 )
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
239class CameraPlaneLineCurveConfigGeneratorConfig: 240 curve_alpha_min: float = 1.0 241 curve_alpha_max: float = 2.0 242 level_1_max: int = 5 243 rotation_theta_max: int = 17 244 vec_z_max: float = 0.5 245 grid_size_min: int = 15 246 grid_size_ratio: float = 0.01
2def __init__(self, curve_alpha_min=attr_dict['curve_alpha_min'].default, curve_alpha_max=attr_dict['curve_alpha_max'].default, level_1_max=attr_dict['level_1_max'].default, rotation_theta_max=attr_dict['rotation_theta_max'].default, vec_z_max=attr_dict['vec_z_max'].default, grid_size_min=attr_dict['grid_size_min'].default, grid_size_ratio=attr_dict['grid_size_ratio'].default): 3 self.curve_alpha_min = curve_alpha_min 4 self.curve_alpha_max = curve_alpha_max 5 self.level_1_max = level_1_max 6 self.rotation_theta_max = rotation_theta_max 7 self.vec_z_max = vec_z_max 8 self.grid_size_min = grid_size_min 9 self.grid_size_ratio = grid_size_ratio
Method generated by attrs for class CameraPlaneLineCurveConfigGeneratorConfig.
249class CameraPlaneLineCurveConfigGenerator( 250 DistortionConfigGenerator[ 251 CameraPlaneLineCurveConfigGeneratorConfig, 252 distortion.CameraPlaneLineCurveConfig, 253 ] 254): # yapf: disable 255 256 def __call__(self, shape: Tuple[int, int], rng: RandomGenerator): 257 height, width = shape 258 curve_point = (rng.integers(0, width), rng.integers(0, height)) 259 260 curve_direction = rng.uniform(0, 180) 261 262 curve_perturb_vec_z = max(shape) / 4 263 if rng.random() < 0.5: 264 curve_perturb_vec_z *= -1.0 265 curve_perturb_vec = (0.0, 0.0, curve_perturb_vec_z) 266 267 curve_alpha = sample_float( 268 level=self.level, 269 value_min=self.config.curve_alpha_min, 270 value_max=self.config.curve_alpha_max, 271 prob_reciprocal=None, 272 rng=rng, 273 inverse_level=True, 274 ) 275 276 camera_model_config = sample_camera_model_config( 277 level=self.level, 278 level_1_max=self.config.level_1_max, 279 rotation_theta_max=self.config.rotation_theta_max, 280 vec_z_max=self.config.vec_z_max, 281 rng=rng, 282 ) 283 grid_size = generate_grid_size( 284 self.config.grid_size_min, 285 self.config.grid_size_ratio, 286 shape, 287 ) 288 return distortion.CameraPlaneLineCurveConfig( 289 curve_point=curve_point, 290 curve_direction=curve_direction, 291 curve_perturb_vec=curve_perturb_vec, 292 curve_alpha=curve_alpha, 293 camera_model_config=camera_model_config, 294 grid_size=grid_size, 295 )
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