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

42 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 Simultaneously Fits and apply the following transformations to SPC2 to mnimize the int difference wrt SPC1: 

19 - Shift in x and y 

20 - Rigid rotation 

21 - Spectral dispersion 

22 """ 

23 

24 def __init__(self, array): 

25 """ 

26 :param array: numpy array with the image data [row, col] 

27 """ 

28 self.data = array # original image 

29 self.result = None # distorted image 

30 self.shear = None # shear factor 

31 self.coord_off = None # offset to add to the coordinates of the image 

32 self.out_roi = slice(None, None), slice(None, None) # output roi 

33 

34 def run(self, shear_factor, coord_off=(0, 0)): 

35 """ 

36 shear_factor: float 

37 """ 

38 self.shear = shear_factor 

39 self.coord_off = coord_off 

40 if self.shear == 0: 

41 self.result = self.data 

42 self.out_roi = slice(0, self.data.shape[0]), slice(0, self.data.shape[1]) 

43 else: 

44 self.result = self.transform_image() 

45 self.result = self.keep_valid_rectangular_roi() 

46 return self.result 

47 

48 def transform_image(self): 

49 transform = ShearDistortion.nl_shear 

50 transformed_img = warp( 

51 self.data, 

52 inverse_map=transform, 

53 map_args={"shear_factor": self.shear, "coord_off": self.coord_off}, 

54 mode="constant", 

55 cval=np.NAN, 

56 ) 

57 return transformed_img 

58 

59 def keep_valid_rectangular_roi(self): 

60 roi = [None, None] 

61 is_nan = np.isnan(self.result) 

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

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

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

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

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

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

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

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

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

71 

72 @staticmethod 

73 def nl_shear(coords, shear_factor, coord_off): 

74 x, y = coords.T 

75 y += shear_factor / 1e5 * (y + coord_off[0]) * (x + coord_off[1]) 

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