예제 #1
0
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
예제 #3
0
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
예제 #5
0
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
예제 #6
0
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
예제 #7
0
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
예제 #8
0
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