Coverage for src/susi/reduc/spc_registration/spc_registration.py: 0%

53 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2025-06-13 14:15 +0000

1#!/usr/bin/env python3 

2# -*- coding: utf-8 -*- 

3""" 

4Provides registration of SP1 and SP2 cameras 

5 

6@author: iglesias 

7""" 

8 

9import numpy as np 

10import logging 

11from skimage.transform import warp 

12 

13log = logging.getLogger("SUSI") 

14 

15 

16class SPCRegistration: 

17 """ 

18 TODO: Test!! 

19 Simultaneously Fits and apply the following transformations to image2 to mnimize difference wrt image1: 

20 - estimateAffinePartial2D 

21 """ 

22 

23 def __init__(self): 

24 self.offset = None 

25 self.rot = None 

26 self.scale = None 

27 self.scale2 = None 

28 self.result = None 

29 self.out_roi = None 

30 

31 def transform(self, image, offset=(0, 0), rot=(0, 0), scale=((1, 0), (1, 0))): 

32 """ 

33 Image transform using the given parameters (see nl_transform). 

34 """ 

35 self.offset = offset 

36 self.rot = rot 

37 self.scale = scale 

38 

39 self.result = self.apply_trasnf(image) 

40 self.result = self.keep_valid_rectangular_roi() 

41 return self.result 

42 

43 def apply_trasnf(self, image): 

44 transform = SPCRegistration.nl_transform 

45 transformed_img = warp( 

46 image, 

47 inverse_map=transform, 

48 map_args={"offset": self.offset, "rot": self.rot, "scale": self.scale}, 

49 mode="constant", 

50 cval=np.NAN, 

51 ) 

52 return transformed_img 

53 

54 def keep_valid_rectangular_roi(self): 

55 roi = [None, None] 

56 is_nan = np.isnan(self.result) 

57 y = ~np.all(is_nan, axis=1) 

58 x = ~np.all(is_nan, axis=0) 

59 roi[0] = slice(np.min(np.where(y)), np.max(np.where(y))) 

60 roi[1] = slice(np.min(np.where(x)), np.max(np.where(x))) 

61 is_nan = is_nan[y, :][:, x] 

62 y = np.all(~is_nan, axis=1) 

63 roi[0] = slice(roi[0].start + np.min(np.where(y)), roi[0].start + np.max(np.where(y))) 

64 self.out_roi = roi[0], roi[1] 

65 return self.result[roi[0], roi[1]] 

66 

67 @staticmethod 

68 def nl_transform(coords, offset=(0, 0), rot=(0, 0), scale=((1, 0), (1, 0))): 

69 """ 

70 Non-linear transformation of the input coordinates using the given parameters. The transformation is 

71 the combination of (in this order): 

72 - offset: 2D translation 

73 - rot: 2D rotation 

74 - scale: 2D non-linear scaling. We use a 2nd order polynomial per dimension: 

75 x' = scale[0][0] * x + scale[0][1] * x**2 

76 """ 

77 x, y = coords.T 

78 # offset 

79 if offset != (0, 0): 

80 x = x + offset[0] 

81 y = y + offset[1] 

82 

83 # rotation 

84 if rot != (0, 0): 

85 x_rot = x * np.cos(rot[0]) - y * np.sin(rot[0]) 

86 y_rot = x * np.sin(rot[0]) + y * np.cos(rot[0]) 

87 else: 

88 x_rot = x 

89 y_rot = y 

90 

91 # scaling 

92 if scale != ((1, 0), (1, 0)): 

93 x_rot = x_rot * scale[0][0] + scale[0][1] * x_rot**2 

94 y_rot = y_rot * scale[1][0] + scale[1][1] * y_rot**2 

95 else: 

96 x_rot = x_rot 

97 y_rot = y_rot 

98 

99 return np.column_stack((x, y))