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 = load_img(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 = [] # gridsize = 5 # stepsize = 50000 # n = (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) # stagepos_p = np.array(zip(x_grid.flatten(), y_grid.flatten())) for fn in other_fn: img, h = load_img(fn) img = imgscale(img, scale) xobs, yobs, _, _, _ = h["StagePosition"] print("Image:", fn) print(f"Stageposition: x={xobs:.0f} | y={yobs:.0f}") print() shift = cross_correlate(img_cent, img, upsample_factor=10, verbose=False) 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 one_cycle(tilt: float=5, sign=1) -> list: angle1 = -tilt*sign self.stageposition.a = angle1 img1 = self.getRawImage() angle2 = +tilt*sign self.stageposition.a = angle2 img2 = self.getRawImage() if sign < 1: img2, img1 = img1, img2 shift = cross_correlate(img1, img2, upsample_factor=10, verbose=verbose) return shift
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 = cross_correlate(img_cent, img, upsample_factor=10, verbose=False) 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 align_to(self, ref_img: "np.array", apply: bool= True, verbose: bool=True) -> list: """Align current view by comparing it against the given image using cross correlation. The stage is translated so that the object of interest (in the reference image) is at the center of the view. Parameters ---------- ref_img: np.array Reference image that the microscope will be aligned to apply: bool Toggle to translate the stage to center the image verbose: bool Be more verbose Returns ------- stage_shift : np.array[2] The stage shift vector determined from cross correlation """ from instamatic.processing.cross_correlate import cross_correlate current_x, current_y = self.stageposition.xy print(f"Current stage position: {current_x:.0f} {current_y:.0f}") stagematrix = self.get_stagematrix() mati = np.linalg.inv(stagematrix) img = self.getRawImage() pixel_shift = cross_correlate(ref_img, img, upsample_factor=10, verbose=verbose) stage_shift = np.dot(pixel_shift, mati) print(f"Shifting stage by dx={stage_shift[0]:.2f} dy={stage_shift[1]:.2f}") new_x = current_x - stage_shift[0] new_y = current_y + stage_shift[1] print(f"New stage position: {new_x:.0f} {new_y:.0f}") if apply: self.stageposition.set_xy_with_backlash_correction(x=new_x, y=new_y) return stage_shift
def center_z_height(ctrl, verbose=False): """Automated routine to find the z-height Koster, A. J., et al. "Automated microscopy for electron tomography." Ultramicroscopy 46.1-4 (1992): 207-227. http://www.msg.ucsf.edu/agard/Publications/52-Koster.pdf """ print("\033[k", "Finding eucentric height...", end="\r") if ctrl.mode != 'mag1': ctrl.mode = 'mag1' ctrl.brightness.value = 65535 ctrl.magnification.value = 2500 z0 = ctrl.stageposition.z ctrl.stageposition.set(a=-5) a0 = ctrl.stageposition.a z = [] d = [] ctrl.stageposition.z = z0 - 2000 ctrl.stageposition.z = z0 - 1000 ctrl.stageposition.z = z0 for i in range(0, 10): z1 = ctrl.stageposition.z ctrl.stageposition.set(a=a0) img0, h = ctrl.getImage(exposure=0.01, comment="z height finding") z.append(z0 + i * 1000) ctrl.stageposition.set(a=a0 + 10) img1, h = ctrl.getImage(exposure=0.01, comment="z height finding") shift = cross_correlate(img0, img1, upsample_factor=10, verbose=False) d1 = np.linalg.norm(shift) if shift[0] < 0: d1 = -d1 d.append(d1) if verbose: print(f"Step {i}: z = {z1}, d = {np.linalg.norm(shift)}") ctrl.stageposition.set(z=z1 + 1000) time.sleep(1) d_f = reject_outlier(d) z_f = [] for e in d_f: z_f.append(z[d.index(e)]) p = np.polyfit(z, d, 1) z_center = -p[1] / p[0] satisfied = input( f"Found eucentric height: {z_center}. Press ENTER to set the height, x to cancel setting." ) if satisfied == "x": ctrl.stageposition.set(a=a0, z=z0) if verbose: print("Did not find proper eucentric height...") else: if z_center > ctrl.stageposition.z: ctrl.stageposition.set(a=a0, z=z_center - 2000) ctrl.stageposition.set(a=a0, z=z_center) else: ctrl.stageposition.set(a=a0, z=z_center + 2000) ctrl.stageposition.set(a=a0, z=z_center) print( "\033[k", "Eucentric height set. Find the crystal again and start data collection!", end="\r")
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.stageposition.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.stageposition.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.getImage(exposure=exposure, binsize=binsize, out=outfile, comment="Center image (start)") stage_cent = ctrl.stageposition.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.stageposition.set(x=xtarget - stepsize, y=ytarget - stepsize) time.sleep(settle_delay) print("(minimize_backlash) Overshoot a bit in XY: ", ctrl.stageposition.xy) for dx in x_range: for dy in y_range: ctrl.stageposition.set(x=x_cent + dx, y=y_cent + dy) time.sleep(settle_delay) stage = ctrl.stageposition.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.getImage(exposure=exposure, binsize=binsize, out=outfile, comment=comment) img = imgscale(img, scale) shift = cross_correlate(img_cent, img, upsample_factor=10, verbose=False) 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.stageposition.set(y=ytarget - stepsize) time.sleep(settle_delay) print("(minimize_backlash) Overshoot a bit in Y: ", ctrl.stageposition.xy) print(" >> Reset to center") ctrl.stageposition.set(x=x_cent, y=y_cent) time.sleep(settle_delay) # ctrl.stageposition.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.getImage(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_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"] # x_cent=40943.0 # y_cent=-6258.4 xy_cent = np.array([x_cent, y_cent]) print("Center:", center_fn) print("Stageposition: x={:.0f} | y={:.0f}".format(*xy_cent)) print() shifts = [] stagepos = [] # stage = ((30943.5, -16255.5), # (30874.701171875, -11258.2998046875), # (31009.701171875, -6256.89990234375), # (30876.0, -1256.9000244140625), # (31011.0, 3744.400146484375), # (35943.5, -16256.900390625), # (35874.6015625, -11256.900390625), # (36011.0, -6256.89990234375), # (35874.6015625, -1256.9000244140625), # (36012.30078125, 3743.0), # (40943.40234375, -16252.7001953125), # (40943.40234375, -11256.900390625), # (40943.40234375, -6258.30029296875), # (40943.40234375, -1256.9000244140625), # (40943.40234375, 3744.400146484375), # (45943.40234375, -16255.5), # (45943.40234375, -11258.2998046875), # (45943.40234375, -6255.5), # (45943.40234375, -1259.7000732421875), # (45943.40234375, 3745.800048828125), # (50943.40234375, -16255.5), # (50943.40234375, -11258.2998046875), # (50943.40234375, -6256.89990234375), # (50943.40234375, -1256.9000244140625), # (50943.40234375, 3743.0)) for i, fn in enumerate(other_fn): img, h = read_image(fn) img = imgscale(img, scale) x_xobs, yobs, _, _, _ = h_cent["StagePosition"] # xobs, yobs = stage[i] print("Image:", fn) print(f"Stageposition: x={xobs:.0f} | y={yobs:.0f}") shift = cross_correlate(img_cent, img, upsample_factor=10, verbose=False) 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_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 = cross_correlate(img_cent, img, upsample_factor=10, verbose=False) 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.getImage(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.getImage(exposure=exposure, binsize=binsize, out=outfile, comment=comment, header_keys="BeamShift") img = imgscale(img, scale) shift = cross_correlate(img_cent, img, upsample_factor=10, verbose=False) 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
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 not ctrl.mode == "diff": print(" >> Switching to diffraction mode") ctrl.mode_diffraction() 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.getImage(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("Position: {}/{}: {}".format(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.getImage(exposure=exposure, binsize=binsize, out=outfile, comment=comment, header_keys=key) img = imgscale(img, scale) shift = cross_correlate(img_cent, img, upsample_factor=10, verbose=False) 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_Imageshift(ctrl, diff_defocus, stepsize, logger, key="IS1"): if key != 'S': inp = input(f"""Calibrate {key} ------------------- 1. Go to diffraction mode. 2. Focus the diffraction spots. 3. Center the beam with PLA. >> Press <ENTER> to start >> \n""") else: inp = input("""Calibrate stage vs camera ------------------ 1. Go to mag1. 2. Find area with particles. >> Press <ENTER> to start >> \n""") d = { "IS1": ctrl.imageshift1, "IS2": ctrl.imageshift2, "BS": ctrl.beamshift, "S": ctrl.stageposition } if diff_defocus != 0: diff_focus_proper = ctrl.difffocus.value diff_focus_defocused = diff_focus_proper + diff_defocus ctrl.difffocus.value = diff_focus_defocused deflector = d[key] if key != "S": x0, y0 = deflector.get() scaling = True else: x0 = deflector.x y0 = deflector.y scaling = False img_cent, h_cent = ctrl.getImage(exposure=0.01, comment="Beam in center of image") shifts = [] imgpos = [] stepsize = stepsize for i in tqdm(range(0, 5)): for j in range(0, 5): deflector.set(x=x0 + (i - 2) * stepsize, y=y0 + (j - 2) * stepsize) img, h = ctrl.getImage(exposure=0.01, comment="imageshifted image") shift = cross_correlate(img_cent, img, upsample_factor=10, verbose=False) imgshift = np.array(((i - 2) * stepsize, (j - 2) * stepsize)) imgpos.append(imgshift) shifts.append(shift) deflector.set(x=x0, y=y0) r, t = fit_affine_transformation(shifts, imgpos, scaling=scaling) result = fit_affine_transformation(shifts, imgpos, scaling=scaling, as_params=True) if diff_defocus != 0: ctrl.difffocus.value = diff_focus_proper print("ImageShift calibration done.") print("Transformation matrix: ", r) logger.debug(f"Transformation matrix: {r}") logger.debug(f"Parameters: angle: {result['angle']}") logger.debug(f"sx: {result['sx']}") logger.debug(f"sy: {result['sy']}") logger.debug(f"tx: {result['tx']}") logger.debug(f"ty: {result['ty']}") logger.debug(f"k1: {result['k1']}") logger.debug(f"k2: {result['k2']}") r_i = np.linalg.inv(r) imgpos_ = np.dot(imgpos, r_i) shifts = np.array(shifts) imgpos_ = np.array(imgpos_) c = [imgpos_, shifts] return r, 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.getImage(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.stageposition.set(x=x_cent+dx, y=y_cent+dy) print(ctrl.stageposition) outfile = f"calib_{i:04d}" if save_images else None comment = comment img, h = ctrl.getImage(exposure=exposure, binsize=binsize, out=outfile, comment=comment, header_keys="StagePosition") img = imgscale(img, scale) shift = cross_correlate(img_cent, img, upsample_factor=10, verbose=False) xobs, yobs, _, _, _ = h["StagePosition"] stagepos.append((xobs, yobs)) shifts.append(shift) i += 1 print(" >> Reset to center") ctrl.stageposition.set(x=x_cent, y=y_cent) ctrl.stageposition.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.getImage(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