def calibrate_mag1_from_image_fn(center_fn, other_fn): """Calibrate pixel->stageposition coordinates from a set of images. center_fn: `str` Reference image at the center of the grid (with the clover in the middle) other_fn: `tuple` of `str` Set of images to cross correlate to the first reference image return: instance of Calibration class with conversion methods """ img_cent, h_cent = read_image(center_fn) # binsize = h_cent["ImageBinsize"] cam_dimensions = h_cent['ImageCameraDimensions'] bin_x, bin_y = cam_dimensions / np.array(img_cent.shape) assert bin_x == bin_y, 'Binsizes do not match {bin_x} != {bin_y}' binsize = int(bin_x) img_cent, scale = autoscale(img_cent, maxdim=512) x_cent, y_cent, _, _, _ = h_cent['StagePosition'] xy_cent = np.array([x_cent, y_cent]) print('Center:', center_fn) print('Stageposition: x={:.0f} | y={:.0f}'.format(*xy_cent)) print() shifts = [] stagepos = [] for i, fn in enumerate(other_fn): img, h = read_image(fn) img = imgscale(img, scale) x_xobs, yobs, _, _, _ = h_cent['StagePosition'] print('Image:', fn) print(f'Stageposition: x={xobs:.0f} | y={yobs:.0f}') shift, error, phasediff = phase_cross_correlation(img_cent, img, upsample_factor=10) print('Shift:', shift) print() stagepos.append((xobs, yobs)) shifts.append(shift) # correct for binsize, store as binsize=1 shifts = np.array(shifts) * binsize / scale stagepos = np.array(stagepos) - xy_cent c = CalibStage.from_data(shifts, stagepos, reference_position=xy_cent, camera_dimensions=cam_dimensions) c.plot() c.to_file() return c
def calibrate_stage_lowmag_from_image_fn(center_fn, other_fn): """Calibrate pixel->stageposition coordinates from a set of images. center_fn: `str` Reference image at the center of the grid (with the clover in the middle) other_fn: `tuple` of `str` Set of images to cross correlate to the first reference image return: instance of Calibration class with conversion methods """ img_cent, h_cent = read_image(center_fn) img_cent, scale = autoscale(img_cent, maxdim=512) x_cent, y_cent, _, _, _ = h_cent['StagePosition'] xy_cent = np.array([x_cent, y_cent]) print('Center:', center_fn) print('Stageposition: x={:.0f} | y={:.0f}'.format(*xy_cent)) print() binsize = h_cent['ImageBinsize'] shifts = [] stagepos = [] for fn in other_fn: img, h = read_image(fn) img = imgscale(img, scale) xobs, yobs, _, _, _ = h['StagePosition'] print('Image:', fn) print(f'Stageposition: x={xobs:.0f} | y={yobs:.0f}') print() shift, error, phasediff = phase_cross_correlation(img_cent, img, upsample_factor=10) stagepos.append((xobs, yobs)) shifts.append(shift) # correct for binsize, store as binsize=1 shifts = np.array(shifts) * binsize / scale stagepos = np.array(stagepos) - xy_cent c = CalibStage.from_data(shifts, stagepos, reference_position=xy_cent, header=h_cent) c.plot() return c
def calibrate_directbeam_from_file(center_fn, other_fn, key='DiffShift'): print() print('Center:', center_fn) img_cent, h_cent = load_img(center_fn) readout_cent = np.array(h_cent[key]) img_cent, scale = autoscale(img_cent, maxdim=512) binsize = h_cent['ImageBinsize'] print('{}: x={} | y={}'.format(key, *readout_cent)) shifts = [] readouts = [] for i, fn in enumerate(other_fn): print(fn) img, h = load_img(fn) img = imgscale(img, scale) readout = np.array(h[key]) print() print('Image:', fn) print('{}: dx={} | dy={}'.format(key, *readout)) shift, error, phasediff = phase_cross_correlation(img_cent, img, upsample_factor=10) readouts.append(readout) shifts.append(shift) # correct for binsize, store in binsize=1 shifts = np.array(shifts) * binsize / scale readouts = np.array(readouts) - np.array(readout_cent) c = CalibDirectBeam.from_data(shifts, readouts, key, header=h_cent, **refine_params[key]) c.plot(key) return c
def calibrate_stage_lowmag_live(ctrl, gridsize=5, stepsize=50000, save_images=False, **kwargs): """Calibrate pixel->stageposition coordinates live on the microscope. ctrl: instance of `TEMController` contains tem + cam interface gridsize: `int` Number of grid points to take, gridsize=5 results in 25 points stepsize: `float` Size of steps for stage position along x and y exposure: `float` exposure time binsize: `int` return: instance of Calibration class with conversion methods """ exposure = kwargs.get('exposure', ctrl.cam.default_exposure) binsize = kwargs.get('binsize', ctrl.cam.default_binsize) outfile = 'calib_start' if save_images else None # Accurate reading fo the center positions is needed so that we can come back to it, # because this will be our anchor point img_cent, h_cent = ctrl.get_image(exposure=exposure, binsize=binsize, out=outfile, comment='Center image (start)') x_cent, y_cent, _, _, _ = h_cent['StagePosition'] xy_cent = np.array([x_cent, y_cent]) img_cent, scale = autoscale(img_cent) stagepos = [] shifts = [] n = int((gridsize - 1) / 2) # number of points = n*(n+1) x_grid, y_grid = np.meshgrid( np.arange(-n, n + 1) * stepsize, np.arange(-n, n + 1) * stepsize) tot = gridsize * gridsize i = 0 for dx, dy in np.stack([x_grid, y_grid]).reshape(2, -1).T: print() print(f'Position {i+1}/{tot}: x: {x_cent+dx:.0f}, y: {y_cent+dy:.0f}') ctrl.stage.set(x=x_cent + dx, y=y_cent + dy) print(ctrl.stage) outfile = f'calib_{i:04d}' if save_images else None comment = comment img, h = ctrl.get_image(exposure=exposure, binsize=binsize, out=outfile, comment=comment, header_keys='StagePosition') img = imgscale(img, scale) shift, error, phasediff = phase_cross_correlation(img_cent, img, upsample_factor=10) xobs, yobs, _, _, _ = h['StagePosition'] stagepos.append((xobs, yobs)) shifts.append(shift) i += 1 print(' >> Reset to center') ctrl.stage.set(x=x_cent, y=y_cent) ctrl.stage.reset_xy() # correct for binsize, store as binsize=1 shifts = np.array(shifts) * binsize / scale stagepos = np.array(stagepos) - np.array((x_cent, y_cent)) m = gridsize**2 // 2 if gridsize % 2 and stagepos[m].max() > 50: print( f' >> Warning: Large difference between image {m}, and center image. These should be close for a good calibration.' ) print(' Difference:', stagepos[m]) print() if save_images: ctrl.get_image(exposure=exposure, binsize=binsize, out='calib_end', comment='Center image (end)') c = CalibStage.from_data(shifts, stagepos, reference_position=xy_cent, header=h_cent) # Calling c.plot with videostream crashes program if not hasattr(ctrl.cam, 'VideoLoop'): c.plot(key) return c
def calibrate_mag1_live(ctrl, gridsize=5, stepsize=5000, minimize_backlash=True, save_images=False, **kwargs): """Calibrate pixel->stageposition coordinates live on the microscope. ctrl: instance of `TEMController` contains tem + cam interface gridsize: `int` Number of grid points to take, gridsize=5 results in 25 points stepsize: `float` Size of steps for stage position along x and y minimize_backlash: bool, Attempt to minimize backlash by overshooting a bit Follows the routine from Oostergetel (1998): https://doi.org/10.1016/S0304-3991(98)00022-9 exposure: `float` Exposure time in seconds binsize: `int` return: instance of Calibration class with conversion methods """ work_drc = get_new_work_subdirectory(stem='calib_mag1') settle_delay = 1.0 # seconds # make sure the angle == 0.0 for _ in range(3): ctrl.stage.a = 0.0 time.sleep(settle_delay) exposure = kwargs.get('exposure', config.camera.default_exposure) binsize = kwargs.get('binsize', config.camera.default_binsize) if minimize_backlash: ctrl.stage.eliminate_backlash_xy(step=stepsize, settle_delay=settle_delay) outfile = work_drc / 'calib_start' if save_images else None # Accurate reading fo the center positions is needed so that we can come back to it, # because this will be our anchor point img_cent, h_cent = ctrl.get_image(exposure=exposure, binsize=binsize, out=outfile, comment='Center image (start)') stage_cent = ctrl.stage.get() cam_dimensions = h_cent['ImageCameraDimensions'] bin_x, bin_y = cam_dimensions / np.array(img_cent.shape) assert bin_x == bin_y, 'Binsizes do not match {bin_x} != {bin_y}' binsize = int(bin_x) x_cent = stage_cent.x y_cent = stage_cent.y xy_cent = np.array([x_cent, y_cent]) img_cent, scale = autoscale(img_cent) stagepos = [] shifts = [] n = int((gridsize - 1) / 2) # number of points = n*(n+1) x_grid, y_grid = np.meshgrid(np.arange(-n, n + 1) * stepsize, np.arange(-n, n + 1) * stepsize) tot = gridsize * gridsize i = 0 x_range = np.arange(-n, n + 1) * stepsize y_range = np.arange(-n, n + 1) * stepsize if minimize_backlash: xtarget = x_cent + x_range[0] ytarget = y_cent + y_range[0] ctrl.stage.set(x=xtarget - stepsize, y=ytarget - stepsize) time.sleep(settle_delay) print('(minimize_backlash) Overshoot a bit in XY: ', ctrl.stage.xy) for dx in x_range: for dy in y_range: ctrl.stage.set(x=x_cent + dx, y=y_cent + dy) time.sleep(settle_delay) stage = ctrl.stage.get() print() print(f'Position {I+1}/{tot}') print(stage) outfile = work_drc / f'calib_{i:04d}' if save_images else None comment = f'Calib image {i}: dx={dx} - dy={dy}' img, h = ctrl.get_image(exposure=exposure, binsize=binsize, out=outfile, comment=comment) img = imgscale(img, scale) shift, error, phasediff = phase_cross_correlation(img_cent, img, upsample_factor=10) xobs = stage.x yobs = stage.y stagepos.append((xobs, yobs)) shifts.append(shift) i += 1 if minimize_backlash: ytarget = y_cent + y_range[0] ctrl.stage.set(y=ytarget - stepsize) time.sleep(settle_delay) print('(minimize_backlash) Overshoot a bit in Y: ', ctrl.stage.xy) print(' >> Reset to center') ctrl.stage.set(x=x_cent, y=y_cent) time.sleep(settle_delay) # ctrl.stage.reset_xy() # correct for binsize, store as binsize=1 shifts = np.array(shifts) * binsize / scale stagepos = np.array(stagepos) - np.array((x_cent, y_cent)) m = gridsize**2 // 2 if gridsize % 2 and stagepos[m].max() > 50: print(f' >> Warning: Large difference between image {m}, and center image. These should be close for a good calibration.') print(' Difference:', stagepos[m]) print() if save_images: outfile = work_drc / 'calib_end' ctrl.get_image(exposure=exposure, binsize=binsize, out=outfile, comment='Center image (end)') c = CalibStage.from_data(shifts, stagepos, reference_position=xy_cent, camera_dimensions=cam_dimensions) c.plot() c.to_file(work_drc / 'calib.pickle') return c
def calibrate_directbeam_live(ctrl, key='DiffShift', gridsize=None, stepsize=None, save_images=False, outdir='.', **kwargs): """Calibrate pixel->beamshift coordinates live on the microscope. ctrl: instance of `TEMController` contains tem + cam interface key: `str` Name of property to calibrate gridsize: `int` or None Number of grid points to take, gridsize=5 results in 25 points stepsize: `float` or None Size of steps for property along x and y exposure: `float` or None exposure time binsize: `int` or None In case paramers are not defined, camera specific default parameters are return: instance of Calibration class with conversion methods """ if ctrl.mode != 'diff': print(' >> Switching to diffraction mode') ctrl.mode.set('diff') exposure = kwargs.get('exposure', ctrl.cam.default_exposure) binsize = kwargs.get('binsize', ctrl.cam.default_binsize) if not gridsize: gridsize = config.camera.calib_directbeam.get(key, {}).get( 'gridsize', 5) # dat syntax... if not stepsize: stepsize = config.camera.calib_directbeam.get(key, {}).get( 'stepsize', 750) # just to fit everything on 1 line =) attr = getattr(ctrl, key.lower()) outfile = os.path.join(outdir, f'calib_db_{key}_0000') if save_images else None img_cent, h_cent = ctrl.get_image(exposure=exposure, binsize=binsize, comment='Beam in center of image', out=outfile) x_cent, y_cent = readout_cent = np.array(h_cent[key]) img_cent, scale = autoscale(img_cent) print('{}: x={} | y={}'.format(key, *readout_cent)) shifts = [] readouts = [] n = int((gridsize - 1) / 2) # number of points = n*(n+1) x_grid, y_grid = np.meshgrid( np.arange(-n, n + 1) * stepsize, np.arange(-n, n + 1) * stepsize) tot = gridsize * gridsize for i, (dx, dy) in enumerate(np.stack([x_grid, y_grid]).reshape(2, -1).T): i += 1 attr.set(x=x_cent + dx, y=y_cent + dy) printer(f'Position: {i}/{tot}: {attr}') outfile = os.path.join( outdir, f'calib_db_{key}_{i:04d}') if save_images else None comment = f'Calib image {i}: dx={dx} - dy={dy}' img, h = ctrl.get_image(exposure=exposure, binsize=binsize, out=outfile, comment=comment, header_keys=key) img = imgscale(img, scale) shift, error, phasediff = phase_cross_correlation(img_cent, img, upsample_factor=10) readout = np.array(h[key]) readouts.append(readout) shifts.append(shift) print('') # print "\nReset to center" attr.set(*readout_cent) # correct for binsize, store in binsize=1 shifts = np.array(shifts) * binsize / scale readouts = np.array(readouts) - np.array(readout_cent) c = CalibDirectBeam.from_data(shifts, readouts, key, header=h_cent, **refine_params[key]) # Calling c.plot with videostream crashes program # if not hasattr(ctrl.cam, "VideoLoop"): # c.plot(key) return c
def calibrate_beamshift_from_image_fn(center_fn, other_fn): """Calibrate pixel->beamshift coordinates from a set of images. center_fn: `str` Reference image with the beam at the center of the image other_fn: `tuple` of `str` Set of images to cross correlate to the first reference image return: instance of Calibration class with conversion methods """ print() print('Center:', center_fn) img_cent, h_cent = load_img(center_fn) beamshift_cent = np.array(h_cent['BeamShift']) img_cent, scale = autoscale(img_cent, maxdim=512) binsize = h_cent['ImageBinsize'] holes = find_holes(img_cent, plot=False, verbose=False, max_eccentricity=0.8) pixel_cent = np.array(holes[0].centroid) * binsize / scale print('Beamshift: x={} | y={}'.format(*beamshift_cent)) print('Pixel: x={:.2f} | y={:.2f}'.format(*pixel_cent)) shifts = [] beampos = [] for fn in other_fn: img, h = load_img(fn) img = imgscale(img, scale) beamshift = np.array(h['BeamShift']) print() print('Image:', fn) print('Beamshift: x={} | y={}'.format(*beamshift)) shift, error, phasediff = phase_cross_correlation(img_cent, img, upsample_factor=10) beampos.append(beamshift) shifts.append(shift) # correct for binsize, store as binsize=1 shifts = np.array(shifts) * binsize / scale beampos = np.array(beampos) - beamshift_cent c = CalibBeamShift.from_data(shifts, beampos, reference_shift=beamshift_cent, reference_pixel=pixel_cent, header=h_cent) c.plot() return c
def calibrate_beamshift_live(ctrl, gridsize=None, stepsize=None, save_images=False, outdir='.', **kwargs): """Calibrate pixel->beamshift coordinates live on the microscope. ctrl: instance of `TEMController` contains tem + cam interface gridsize: `int` or None Number of grid points to take, gridsize=5 results in 25 points stepsize: `float` or None Size of steps for beamshift along x and y Defined at a magnification of 2500, scales stepsize down for other mags. exposure: `float` or None exposure time binsize: `int` or None In case paramers are not defined, camera specific default parameters are retrieved return: instance of Calibration class with conversion methods """ exposure = kwargs.get('exposure', ctrl.cam.default_exposure) binsize = kwargs.get('binsize', ctrl.cam.default_binsize) if not gridsize: gridsize = config.camera.calib_beamshift.get('gridsize', 5) if not stepsize: stepsize = config.camera.calib_beamshift.get('stepsize', 250) img_cent, h_cent = ctrl.get_image(exposure=exposure, binsize=binsize, comment='Beam in center of image') x_cent, y_cent = beamshift_cent = np.array(h_cent['BeamShift']) magnification = h_cent['Magnification'] stepsize = 2500.0 / magnification * stepsize print(f'Gridsize: {gridsize} | Stepsize: {stepsize:.2f}') img_cent, scale = autoscale(img_cent) outfile = os.path.join(outdir, 'calib_beamcenter') if save_images else None pixel_cent = find_beam_center(img_cent) * binsize / scale print('Beamshift: x={} | y={}'.format(*beamshift_cent)) print('Pixel: x={} | y={}'.format(*pixel_cent)) shifts = [] beampos = [] n = int((gridsize - 1) / 2) # number of points = n*(n+1) x_grid, y_grid = np.meshgrid( np.arange(-n, n + 1) * stepsize, np.arange(-n, n + 1) * stepsize) tot = gridsize * gridsize i = 0 for dx, dy in np.stack([x_grid, y_grid]).reshape(2, -1).T: ctrl.beamshift.set(x=x_cent + dx, y=y_cent + dy) printer('Position: {}/{}: {}'.format(i + 1, tot, ctrl.beamshift)) outfile = os.path.join( outdir, 'calib_beamshift_{i:04d}') if save_images else None comment = f'Calib image {i}: dx={dx} - dy={dy}' img, h = ctrl.get_image(exposure=exposure, binsize=binsize, out=outfile, comment=comment, header_keys='BeamShift') img = imgscale(img, scale) shift, error, phasediff = phase_cross_correlation(img_cent, img, upsample_factor=10) beamshift = np.array(h['BeamShift']) beampos.append(beamshift) shifts.append(shift) i += 1 print('') # print "\nReset to center" ctrl.beamshift.set(*beamshift_cent) # correct for binsize, store in binsize=1 shifts = np.array(shifts) * binsize / scale beampos = np.array(beampos) - np.array(beamshift_cent) c = CalibBeamShift.from_data(shifts, beampos, reference_shift=beamshift_cent, reference_pixel=pixel_cent, header=h_cent) # Calling c.plot with videostream crashes program # if not hasattr(ctrl.cam, "VideoLoop"): # c.plot() return c