def apply_frame_correction(method): """Do a smile correction for a single frame and return the result. Parameters ---------- method: int Either 0 for lookup table method or 1 for row interpolation method. """ control = toml.loads(P.example_scan_control_content) width = control[P.ctrl_scan_settings][P.ctrl_width] width_offset = control[P.ctrl_scan_settings][P.ctrl_width_offset] height = control[P.ctrl_scan_settings][P.ctrl_height] height_offset = control[P.ctrl_scan_settings][P.ctrl_height_offset] light_ds = F.load_frame(distortion_smile_tilt_path) light_ds = light_ds.isel({ P.dim_x: slice(width_offset, width_offset + width), P.dim_y: slice(height_offset, height_offset + height) }) sm, sl = make_shift_matrix() # Uncomment for debugging # frame_inspector.plot_frame(light_ds, sl, True, True) # sm.plot() # plt.show() light_frame = light_ds[P.naming_frame_data] corrected = sc.apply_shift_matrix(light_frame, shift_matrix=sm, method=method, target_is_cube=False) return corrected
def _show_a_frame(path, window_name=None): """General method to show various stuff. """ source = F.load_frame(path) frame = source[P.naming_frame_data] dim_count = len(frame.dims) if dim_count == 1: plt.plot(frame.data) else: frame_inspector.plot_frame(source, window_name=window_name) plt.show()
def make_shift_matrix(): """Make shift matrix and save it to disk.""" control = toml.loads(P.example_scan_control_content) width = control[P.ctrl_scan_settings][P.ctrl_width] width_offset = control[P.ctrl_scan_settings][P.ctrl_width_offset] height = control[P.ctrl_scan_settings][P.ctrl_height] height_offset = control[P.ctrl_scan_settings][P.ctrl_height_offset] positions = np.array( control[P.ctrl_spectral_lines][P.ctrl_positions]) - width_offset bandpass_width = control[P.ctrl_spectral_lines][P.ctrl_window_width] light_ds = F.load_frame(distortion_smile_tilt_path) light_ds = light_ds.isel({ P.dim_x: slice(width_offset, width_offset + width), P.dim_y: slice(height_offset, height_offset + height) }) light_frame = light_ds[P.naming_frame_data] bp = sc.construct_bandpass_filter(light_frame, positions, bandpass_width) sl_list = sc.construct_spectral_lines(light_frame, positions, bp) shift_matrix = sc.construct_shift_matrix(sl_list, light_frame[P.dim_x].size, light_frame[P.dim_y].size) # frame_inspector.plot_frame(light_frame, sl_list, True, True, False, 'testing') abs_path = os.path.abspath(shift_path) print(f"Saving shift matrix to {abs_path}...", end=' ') shift_matrix.to_netcdf(abs_path) print("done") # Uncomment for debugging # shift_matrix.plot.imshow() # plt.show() return shift_matrix, sl_list
def make_undistorted_and_dark_frame(): """Creates an example of undistorted frame and dark frame to examples directory. Created frame is "full sensor size" where the area illuminated by the slit is centered vertically. Use global variables 'row_noise_fac' and 'random_noise_fac' to control the level of added random noise. Frame data follows closely to the form that camazing uses in the frames it provides. Attributes are omitted though. """ print(f"Generating frame example to '{undistorted_frame_path}'...", end='') source = F.load_frame(example_spectrogram_path) height = slit_height width = source[P.naming_frame_data][P.dim_x].size source_data = source[P.naming_frame_data].data max_pixel_val = source_data.max() expanded_data = np.repeat(source_data, height) expanded_data = np.reshape(expanded_data, (width, height)) expanded_data = expanded_data.transpose() full_sensor = np.zeros((sensor_height, width)) fh2 = int(sensor_height / 2) sh2 = int(slit_height / 2) full_sensor[fh2 - sh2:fh2 + sh2, :] = expanded_data # Multiply each row with a random number rand_row = np.random.normal(1, row_noise_fac, size=(sensor_height, )) full_sensor = full_sensor * rand_row[:, None] # Add random noise rando = np.random.uniform(0, random_noise_fac * max_pixel_val, size=(sensor_height, width)) full_sensor = full_sensor + rando coords = { P.dim_x: (P.dim_x, np.arange(0, source[P.naming_frame_data][P.dim_x].size) + 0.5), P.dim_y: (P.dim_y, np.arange(0, sensor_height) + 0.5), "timestamp": dt.datetime.today().timestamp(), } dims = (P.dim_y, P.dim_x) frame = xr.DataArray( full_sensor, name=P.naming_frame_data, dims=dims, coords=coords, ) # frame_inspector.plot_frame(frame) F.save_frame(frame, undistorted_frame_path) print("done") print(f"Generating dark frame example to '{dark_frame_path}'...", end='') dark = frame.copy(deep=True) dark.data = rando dark_frame = xr.DataArray( dark, name=P.naming_frame_data, dims=dims, coords=coords, ) F.save_frame(dark_frame, dark_frame_path) print("done")
def make_stripe_cube(): """Generates a raw cube. The cube is as if black and white target illuminated with fluorescence light was scanned. The result is saved to example_scan directory along with generated dark and white frames (copied from frame_examples directory), which will later be needed to calculate reflectance images. Also shift matrix is copied from frame_examples. """ print(f"Generating stripe example raw cube.") control = toml.loads(P.example_scan_control_content) width = control[P.ctrl_scan_settings][P.ctrl_width] width_offset = control[P.ctrl_scan_settings][P.ctrl_width_offset] height = control[P.ctrl_scan_settings][P.ctrl_height] height_offset = control[P.ctrl_scan_settings][P.ctrl_height_offset] if not os.path.exists(distortion_smile_tilt_path + '.nc'): make_distorted_frame(['smile', 'tilt']) white_area = F.load_frame(distortion_smile_tilt_path) dark_area = white_area.copy(deep=True) F.save_frame( white_area[P.naming_frame_data], P.path_rel_scan + P.example_scan_name + '/' + P.ref_white_name) F.save_frame(dark_area[P.naming_frame_data], P.path_rel_scan + P.example_scan_name + '/' + P.ref_dark_name) shift = F.load_shit_matrix(shift_path) F.save_shift_matrix( shift, P.path_rel_scan + P.example_scan_name + '/' + P.shift_name) x_slice = slice(width_offset, width_offset + width) y_slice = slice(height_offset, height_offset + height) white_area = white_area.isel({P.dim_x: x_slice, P.dim_y: y_slice}) dark_area = dark_area.isel({P.dim_x: x_slice, P.dim_y: y_slice}) white_area[P.naming_frame_data].values = np.nan_to_num( white_area[P.naming_frame_data].values) white_area[P.dim_x] = np.arange(0, white_area[P.dim_x].size) + 0.5 white_area[P.dim_y] = np.arange(0, white_area[P.dim_y].size) + 0.5 dark_area[P.dim_x] = np.arange(0, white_area[P.dim_x].size) + 0.5 dark_area[P.dim_y] = np.arange(0, white_area[P.dim_y].size) + 0.5 area_shape = white_area[P.naming_frame_data].values.shape max_pixel_val = white_area[P.naming_frame_data].max().item() dark_area[P.naming_frame_data].values = np.random.uniform( 0, random_noise_fac * max_pixel_val, size=area_shape) frame_list = [] stripe_counter = 0 use_white = True for i in range(cube_depth): if stripe_counter > stripe_width - 1: use_white = not use_white stripe_counter = 0 rando = np.random.uniform(0, random_noise_fac * max_pixel_val, size=area_shape) if use_white: f = white_area.copy(deep=True) f[P. naming_frame_data].values = f[P.naming_frame_data].values + rando else: f = dark_area.copy(deep=True) f[P.naming_frame_data].values = rando f.coords[P.dim_scan] = i frame_list.append(f[P.naming_frame_data]) stripe_counter += 1 frames = xr.concat(frame_list, dim=P.dim_scan) cube = xr.Dataset(data_vars={ P.naming_cube_data: frames, }, ) F.save_cube( cube, P.path_rel_scan + '/' + P.example_scan_name + '/' + P.cube_raw_name) print(f"Generated stripe example raw cube.")
def make_distorted_frame(distortions, amount=None): """Creates an example of a frame suffering from spectral smile or tilt or both to examples directory. Adds metadata to the frame, which can be accessed through the dataset ds by 'ds.attributes'. Meta contains tilt and curvature of the spectral lines. """ print("Generating distorted frame") if not os.path.exists(undistorted_frame_path): make_undistorted_and_dark_frame() u_frame_ds = F.load_frame(undistorted_frame_path) u_frame = u_frame_ds[P.naming_frame_data] width = u_frame[P.dim_x].size height = u_frame[P.dim_y].size save_path = P.path_example_frames + 'distorted' meta = {} if 'smile' in distortions: if amount is None: curvature = default_curvature else: curvature = amount meta[key_curvature_generated] = curvature distortion_matrix = generate_distortion_matrix(width, height, curvature, method='smile') u_frame = interpolative_distortion(u_frame, distortion_matrix) save_path = save_path + '_smile' if 'tilt' in distortions: if amount is None: tilt = default_tilt else: tilt = amount meta[key_tilt_generated] = tilt distortion_matrix = generate_distortion_matrix(width, height, tilt, method='tilt') save_path = save_path + '_tilt' u_frame = interpolative_distortion(u_frame, distortion_matrix) ################ # Find spectral lines and add the mean values to metadata to verify correctness of # the calculated values. control = toml.loads(P.example_scan_control_content) width = control[P.ctrl_scan_settings][P.ctrl_width] width_offset = control[P.ctrl_scan_settings][P.ctrl_width_offset] height = control[P.ctrl_scan_settings][P.ctrl_height] height_offset = control[P.ctrl_scan_settings][P.ctrl_height_offset] positions = np.array( control[P.ctrl_spectral_lines][P.ctrl_positions]) - width_offset peak_width = control[P.ctrl_spectral_lines][P.ctrl_peak_width] bandpass_width = control[P.ctrl_spectral_lines][P.ctrl_window_width] crop_frame = u_frame.isel({ P.dim_x: slice(width_offset, width_offset + width), P.dim_y: slice(height_offset, height_offset + height) }) bp = sc.construct_bandpass_filter(crop_frame, positions, bandpass_width) sl_list = sc.construct_spectral_lines(crop_frame, positions, bp, peak_width=peak_width) meta[P.meta_key_sl_count] = len(sl_list) meta[P.meta_key_location] = [sl.location for sl in sl_list] meta[P.meta_key_tilt] = [sl.tilt for sl in sl_list] meta[P.meta_key_curvature] = [sl.curvature for sl in sl_list] meta[key_curvature_measured_mean] = np.mean( np.array([sl.curvature for sl in sl_list])) meta[key_tilt_measured_mean] = np.mean( np.array([sl.tilt_angle_degree_abs for sl in sl_list])) print(meta) ################ u_frame = u_frame.isel({ P.dim_x: slice(width_offset, width_offset + width), P.dim_y: slice(height_offset, height_offset + height) }) F.save_frame(u_frame, save_path, meta) print(f"Generated distorted frame to '{save_path}'")
def __init__(self, session_name:str): """Initializes new scanning session with given name. Creates a default directory (/scans/<session_name>) if it does not yet exist. If it exists, the existing files are loaded. Parameters ---------- session_name : str Name of the session either existing or a new one. """ self.session_name = session_name self.session_root = P.path_rel_scan + '/' + session_name + '/' self.camera_setting_path = self.session_root + P.fn_camera_settings self.scan_settings_path = os.path.abspath(self.session_root + P.fn_control) self.dark_path = os.path.abspath(self.session_root + P.ref_dark_name + '.nc') self.white_path = os.path.abspath(self.session_root + P.ref_white_name + '.nc') self.light_path = os.path.abspath(self.session_root + P.ref_light_name + '.nc') self.shift_path = os.path.abspath(self.session_root + P.shift_name + '.nc') self.cube_raw_path = os.path.abspath(self.session_root + P.cube_raw_name + '.nc') self.cube_rfl_path = os.path.abspath(self.session_root + P.cube_reflectance_name + '.nc') self.cube_desmiled_lut_path = os.path.abspath(self.session_root + P.cube_desmiled_lut + '.nc') self.cube_desmiled_intr_path = os.path.abspath(self.session_root + P.cube_desmiled_intr + '.nc') # CameraInterface object self._cami = None # Contents of the control file as a dictionary self.control = None # Dark reference frame self.dark = None # White reference frame self.white = None # Light reference frame self.light = None if self.session_exists(): print(f"Found existing session '{session_name}'.") logging.info(f"Searching for existing dark frame from '{self.dark_path}'") if os.path.exists(self.dark_path): print(f"Found existing dark frame. Loading into memory", end='...') self.dark = F.load_frame(self.dark_path) print("done") logging.info(f"Searching for existing white frame from '{self.white_path}'") if os.path.exists(self.white_path): print(f"Found existing white frame. Loading into memory", end='...') self.white = F.load_frame(self.white_path) print("done") logging.info(f"Searching for existing light frame from '{self.light_path}'") if os.path.exists(self.light_path): print(f"Found existing light frame. Loading into memory", end='...') self.light = F.load_frame(self.light_path) print("done") else: print(f"Creating new session '{session_name}'") F.create_directory(self.session_root) if not os.path.exists(self.scan_settings_path): self.generate_default_scan_control() else: self.load_control_file() print(f"Session initialized and ready to work.")