Example #1
0
def drift_to_beam(cam,
                  xmotor,
                  zmotor,
                  pixelsize,
                  tolerance=5,
                  max_iterations=100):
    """
    Moves the camera *cam* with motors *xmotor* and *zmotor* until the
    center of mass is nearer than *tolerance*-pixels to the center of the
    frame or *max_iterations* is reached.

    To convert pixelcoordinates to realworld-coordinates of the motors the
    *pixelsize* (scalar or 2-element array-like, e.g. [4*q.um, 5*q.um]) is
    needed.
    """
    def take_frame():
        cam.trigger()
        return gaussian_filter(cam.grab().astype(np.float32), 40.0)

    units = (u for u in pixelsize.units if pixelsize.units[u] > 0.0)
    units = q.parse_expression(' * '.join(units))
    ps = np.tile(pixelsize.magnitude, 2)[:2] * units

    img = take_frame()
    frm_center = (np.array(img.shape) - 1) / 2
    d = center_of_mass(img - img.min()) - frm_center

    iter_ = 0
    while ((d**2).sum() > tolerance**2) and (iter_ < max_iterations):
        fut_0 = zmotor.move(d[0] * ps[0])
        fut_1 = xmotor.move(d[1] * ps[1])
        wait([fut_0, fut_1])
        img = take_frame()
        if img.sum() == 0:
            LOG.debug("drift_to_beam: Frame is empty (sum == 0). " +
                      "Can't follow center of mass.")
            raise ProcessException("There is nothing to see! "
                                   "Can't follow the center of mass.")
        d = center_of_mass(img - img.min()) - frm_center
        iter_ += 1

    if iter_ < max_iterations:
        return True
    else:
        return False
Example #2
0
def drift_to_beam(cam, xmotor, zmotor, pixelsize, tolerance=5,
                  max_iterations=100):
    """
    drift_to_beam(cam, xmotor, zmotor, pixelsize, tolerance=5, max_iterations=100)

    Moves the camera *cam* with motors *xmotor* and *zmotor* until the
    center of mass is nearer than *tolerance*-pixels to the center of the
    frame or *max_iterations* is reached.

    To convert pixelcoordinates to realworld-coordinates of the motors the
    *pixelsize* (scalar or 2-element array-like, e.g. [4*q.um, 5*q.um]) is
    needed.
    """
    def take_frame():
        cam.trigger()
        return gaussian_filter(cam.grab().astype(np.float32), 40.0)

    units = (u for u in pixelsize.units if pixelsize.units[u] > 0.0)
    units = q.parse_expression(' * '.join(units))
    ps = np.tile(pixelsize.magnitude, 2)[:2] * units

    img = take_frame()
    frm_center = (np.array(img.shape)-1)/2
    d = center_of_mass(img-img.min()) - frm_center

    iter_ = 0
    while ((d**2).sum() > tolerance**2) and (iter_ < max_iterations):
        fut_0 = zmotor.move(d[0]*ps[0])
        fut_1 = xmotor.move(d[1]*ps[1])
        wait([fut_0, fut_1])
        img = take_frame()
        if img.sum() == 0:
            LOG.debug("drift_to_beam: Frame is empty (sum == 0). " +
                      "Can't follow center of mass.")
            raise ProcessException("There is nothing to see! "
                                   "Can't follow the center of mass.")
        d = center_of_mass(img-img.min()) - frm_center
        iter_ += 1

    if iter_ < max_iterations:
        return True
    else:
        return False
Example #3
0
def find_beam(cam, xmotor, zmotor, pixelsize, xborder, zborder,
              xstep=None, zstep=None, thres=1000):
    """
    find_beam(cam, xmotor, zmotor, pixelsize, xborder, zborder, xstep=None, zstep=None, thres=1000)

    Scans the area defined by xborder and zborder for the beam until
    beam_visible returns True.
    Startpoint is the current motor-position if this position is inside the
    defined area else it start from the center of that area.
    It searches in a spiral around the startpoint.

    *cam* is the camera-device, *xmotor* the motor-device horizontally aligned
    to the image and *zmotor* the motor-device vertically aligned to the image.
    *pixelsize* determines the realworld size of an image pixels (scalar or
    2-element array-like, e.g. [4*q.um, 5*q.um]). *xborder* and *zborder*
    define the search area. Each constructed with a start- and an end-value
    (e.g. [-1.2*q.mm, 5.5*q.mm]).

    Optional arguments *xstep* and *zstep* define the length of one movement
    in the specific direction. Defaults are calculated from cam_img.shape and
    *pixelsize*.
    Optional argument *thres* will be past to beam_visible().
    """

    def beam_visible(img, thres):
        """
        Simple grayvalue-threshold that defines the beam to be visible in *img*.
        """
        return (img >= thres).any()

    def check(rel_move):
        """Move to new position and check if the beam is visible."""
        fut_0 = zmotor.move(rel_move[0]*q.um)
        fut_1 = xmotor.move(rel_move[1]*q.um)
        wait([fut_0, fut_1])
        cam.trigger()
        img = gaussian_filter(cam.grab().astype(np.float32), 40.0)
        img_shape[0] = img.shape
        bv = beam_visible(img, thres)
        return bv

    def spiral_scan():
        """
        Generator for returning rel. movement to the next position of the
        scanpath.
        """

        def trydir(dr):
            """
            Check if position in direction *dr* is unchecked or outside the
            search-area.
            Result:   2 - ok; 1 - outside; 0 - inside but already used
            """
            tmp = sp_pos + dir2rpos[dr]
            inside = (tmp >= 0).all() and (tmp < sp_shape).all()
            unused = (not scanned_points[tmp[0], tmp[1]]) if inside else False
            return 1 if not inside else 2 if unused else 0

        def next_move(pos, dr, rel_move=True):
            """
            Moves relativ in the direction *dr* (or to position *dr* if
            rel_move==False) and marks new position as scanned.
            Clips movement at border of the scanarea if needed.
            """
            old = np.array(pos).copy()
            if rel_move:
                pos += dir2rpos[dr]
            else:
                pos[0], pos[1] = dr[0], dr[1]
            scanned_points[pos[0], pos[1]] = True
            if (old == 0).any() or (old == sp_shape-1).any() or \
                    (pos == 0).any() or (pos == sp_shape-1).any():
                new_pos = np.array([zpos, xpos]) + step * (pos-[nz0, nx0])
                clip = np.append((new_pos < [zborder[0], xborder[0]]),
                                 (new_pos > [zborder[1], xborder[1]]))
                new_pos[0] = zborder[1] if clip[2] else \
                    zborder[0] if clip[0] else new_pos[0]
                new_pos[1] = xborder[1] if clip[3] else \
                    xborder[0] if clip[1] else new_pos[1]
                old_pos = np.array([zmotor.position.to(q.um.units).magnitude,
                                    xmotor.position.to(q.um.units).magnitude])
                return new_pos - old_pos
            else:
                if rel_move:
                    return step * dir2rpos[dr]
                else:
                    return step * (pos - old)

        def decide_dir():
            """
            Picks a direction to go and updates direction of search-rotation.
            """
            dr = np.array(map(trydir, range(4))) == 2
            r = np.arange(4)[dr][0]
            w0 = sp_pos-[nz0, nx0]
            w1 = w0 + dir2rpos[r]
            w = np.arctan2(w1[0], w1[1]) - np.arctan2(w0[0], w0[1])
            search_rot[0] = int((w % (2*np.pi)) < np.pi)
            return r

        xpos = xmotor.position.to(q.um.units).magnitude
        zpos = zmotor.position.to(q.um.units).magnitude
        search_rot = [0]
        rdir2try = [[1, 0, 3], [3, 0, 1]]
        dir2rpos = [[1, 0], [0, 1], [-1, 0], [0, -1]]
        step = img_shape[0] * \
            np.array([x.to(q.um.units).magnitude for x in ps])
        step[0] = step[0] if zstep is None else zstep.to(q.um.units).magnitude
        step[1] = step[1] if xstep is None else xstep.to(q.um.units).magnitude
        nz0 = int((zpos-zborder[0])/step[0]) + \
            ((zpos-zborder[0]) % step[0] > step[0]/2.)
        nz1 = int((zborder[1]-zpos)/step[0]) + \
            ((zborder[1]-zpos) % step[0] > step[0]/2.)
        nx0 = int((xpos-xborder[0])/step[1]) + \
            ((xpos-xborder[0]) % step[1] > step[1]/2.)
        nx1 = int((xborder[1]-xpos)/step[1]) + \
            ((xborder[1]-xpos) % step[1] > step[1]/2.)
        sp_shape = np.array([nz0+nz1+1, nx0+nx1+1])
        scanned_points = np.zeros(sp_shape, np.bool_)
        sp_pos = np.array([nz0, nx0])
        scanned_points[sp_pos[0], sp_pos[1]] = True

        while not scanned_points.all():
            skip = False
            try:
                sdir = decide_dir()
                yield next_move(sp_pos, sdir)
            except IndexError:
                skip = True

            while (not scanned_points.all()) and (not skip):
                sr = search_rot[0]
                for rd in rdir2try[sr]:
                    rd = (sdir + rd) % 4
                    c = trydir(rd)
                    if c == 2:
                        break
                    elif c == 1:
                        search_rot[0] = (search_rot[0]+1) % 2
                if c == 2:
                    sdir = rd
                    yield next_move(sp_pos, sdir)
                    continue
                break

            if not scanned_points.all():
                ind = np.indices(sp_shape)
                mask = np.logical_not(scanned_points)
                ind = np.array([ind[0][mask], ind[1][mask]])
                dist = ((ind-np.array([nz0, nx0]).reshape(2, 1))**2).sum(0)
                sort_pos = ind[:, np.argsort(dist)]
                n_pos = sort_pos[:, 0]
                r = next_move(sp_pos, n_pos, False)
                yield r

    units = (u for u in pixelsize.units if pixelsize.units[u] > 0.0)
    units = q.parse_expression(' * '.join(units))
    ps = np.tile(pixelsize.magnitude, 2)[:2] * units
    xborder = np.array([xborder[0].to(q.um.units).magnitude,
                        xborder[1].to(q.um.units).magnitude])
    zborder = np.array([zborder[0].to(q.um.units).magnitude,
                        zborder[1].to(q.um.units).magnitude])

    # startpoint
    img_shape = [0]
    xpos = xmotor.position.to(q.um.units).magnitude
    zpos = zmotor.position.to(q.um.units).magnitude
    outside = (xpos < xborder[0]) or (xpos > xborder[1]) or \
        (zpos < zborder[0]) or (zpos > zborder[1])
    rmov = (zborder.mean() - zpos, xborder.mean() - xpos) if outside \
        else (0*zpos, 0*xpos)
    if check(rmov):
        return True

    # scan
    for rmov in spiral_scan():
        if check(rmov):
            return True

    return False
Example #4
0
def find_beam(cam,
              xmotor,
              zmotor,
              pixelsize,
              xborder,
              zborder,
              xstep=None,
              zstep=None,
              thres=1000):
    """
    Scans the area defined by xborder and zborder for the beam until
    beam_visible returns True.
    Startpoint is the current motor-position if this position is inside the
    defined area else it start from the center of that area.
    It searches in a spiral around the startpoint.

    *cam* is the camera-device, *xmotor* the motor-device horizontally aligned
    to the image and *zmotor* the motor-device vertically aligned to the image.
    *pixelsize* determines the realworld size of an image pixels (scalar or
    2-element array-like, e.g. [4*q.um, 5*q.um]). *xborder* and *zborder*
    define the search area. Each constructed with a start- and an end-value
    (e.g. [-1.2*q.mm, 5.5*q.mm]).

    Optional arguments *xstep* and *zstep* define the length of one movement
    in the specific direction. Defaults are calculated from cam_img.shape and
    *pixelsize*.
    Optional argument *thres* will be past to beam_visible().
    """
    def beam_visible(img, thres):
        """
        Simple grayvalue-threshold that defines the beam to be visible in *img*.
        """
        return (img >= thres).any()

    def check(rel_move):
        """Move to new position and check if the beam is visible."""
        fut_0 = zmotor.move(rel_move[0] * q.um)
        fut_1 = xmotor.move(rel_move[1] * q.um)
        wait([fut_0, fut_1])
        cam.trigger()
        img = gaussian_filter(cam.grab().astype(np.float32), 40.0)
        img_shape[0] = img.shape
        bv = beam_visible(img, thres)
        return bv

    def spiral_scan():
        """
        Generator for returning rel. movement to the next position of the
        scanpath.
        """
        def trydir(dr):
            """
            Check if position in direction *dr* is unchecked or outside the
            search-area.
            Result:   2 - ok; 1 - outside; 0 - inside but already used
            """
            tmp = sp_pos + dir2rpos[dr]
            inside = (tmp >= 0).all() and (tmp < sp_shape).all()
            unused = (not scanned_points[tmp[0], tmp[1]]) if inside else False
            return 1 if not inside else 2 if unused else 0

        def next_move(pos, dr, rel_move=True):
            """
            Moves relativ in the direction *dr* (or to position *dr* if
            rel_move==False) and marks new position as scanned.
            Clips movement at border of the scanarea if needed.
            """
            old = np.array(pos).copy()
            if rel_move:
                pos += dir2rpos[dr]
            else:
                pos[0], pos[1] = dr[0], dr[1]
            scanned_points[pos[0], pos[1]] = True
            if (old == 0).any() or (old == sp_shape-1).any() or \
                    (pos == 0).any() or (pos == sp_shape-1).any():
                new_pos = np.array([zpos, xpos]) + step * (pos - [nz0, nx0])
                clip = np.append((new_pos < [zborder[0], xborder[0]]),
                                 (new_pos > [zborder[1], xborder[1]]))
                new_pos[0] = zborder[1] if clip[2] else \
                    zborder[0] if clip[0] else new_pos[0]
                new_pos[1] = xborder[1] if clip[3] else \
                    xborder[0] if clip[1] else new_pos[1]
                old_pos = np.array([
                    zmotor.position.to(q.um.units).magnitude,
                    xmotor.position.to(q.um.units).magnitude
                ])
                return new_pos - old_pos
            else:
                if rel_move:
                    return step * dir2rpos[dr]
                else:
                    return step * (pos - old)

        def decide_dir():
            """
            Picks a direction to go and updates direction of search-rotation.
            """
            dr = np.array(map(trydir, range(4))) == 2
            r = np.arange(4)[dr][0]
            w0 = sp_pos - [nz0, nx0]
            w1 = w0 + dir2rpos[r]
            w = np.arctan2(w1[0], w1[1]) - np.arctan2(w0[0], w0[1])
            search_rot[0] = int((w % (2 * np.pi)) < np.pi)
            return r

        xpos = xmotor.position.to(q.um.units).magnitude
        zpos = zmotor.position.to(q.um.units).magnitude
        search_rot = [0]
        rdir2try = [[1, 0, 3], [3, 0, 1]]
        dir2rpos = [[1, 0], [0, 1], [-1, 0], [0, -1]]
        step = img_shape[0] * \
            np.array([x.to(q.um.units).magnitude for x in ps])
        step[0] = step[0] if zstep is None else zstep.to(q.um.units).magnitude
        step[1] = step[1] if xstep is None else xstep.to(q.um.units).magnitude
        nz0 = int((zpos-zborder[0])/step[0]) + \
            ((zpos-zborder[0]) % step[0] > step[0]/2.)
        nz1 = int((zborder[1]-zpos)/step[0]) + \
            ((zborder[1]-zpos) % step[0] > step[0]/2.)
        nx0 = int((xpos-xborder[0])/step[1]) + \
            ((xpos-xborder[0]) % step[1] > step[1]/2.)
        nx1 = int((xborder[1]-xpos)/step[1]) + \
            ((xborder[1]-xpos) % step[1] > step[1]/2.)
        sp_shape = np.array([nz0 + nz1 + 1, nx0 + nx1 + 1])
        scanned_points = np.zeros(sp_shape, np.bool_)
        sp_pos = np.array([nz0, nx0])
        scanned_points[sp_pos[0], sp_pos[1]] = True

        while not scanned_points.all():
            skip = False
            try:
                sdir = decide_dir()
                yield next_move(sp_pos, sdir)
            except IndexError:
                skip = True

            while (not scanned_points.all()) and (not skip):
                sr = search_rot[0]
                for rd in rdir2try[sr]:
                    rd = (sdir + rd) % 4
                    c = trydir(rd)
                    if c == 2:
                        break
                    elif c == 1:
                        search_rot[0] = (search_rot[0] + 1) % 2
                if c == 2:
                    sdir = rd
                    yield next_move(sp_pos, sdir)
                    continue
                break

            if not scanned_points.all():
                ind = np.indices(sp_shape)
                mask = np.logical_not(scanned_points)
                ind = np.array([ind[0][mask], ind[1][mask]])
                dist = ((ind - np.array([nz0, nx0]).reshape(2, 1))**2).sum(0)
                sort_pos = ind[:, np.argsort(dist)]
                n_pos = sort_pos[:, 0]
                r = next_move(sp_pos, n_pos, False)
                yield r

    units = (u for u in pixelsize.units if pixelsize.units[u] > 0.0)
    units = q.parse_expression(' * '.join(units))
    ps = np.tile(pixelsize.magnitude, 2)[:2] * units
    xborder = np.array([
        xborder[0].to(q.um.units).magnitude,
        xborder[1].to(q.um.units).magnitude
    ])
    zborder = np.array([
        zborder[0].to(q.um.units).magnitude,
        zborder[1].to(q.um.units).magnitude
    ])

    # startpoint
    img_shape = [0]
    xpos = xmotor.position.to(q.um.units).magnitude
    zpos = zmotor.position.to(q.um.units).magnitude
    outside = (xpos < xborder[0]) or (xpos > xborder[1]) or \
        (zpos < zborder[0]) or (zpos > zborder[1])
    rmov = (zborder.mean() - zpos, xborder.mean() - xpos) if outside \
        else (0*zpos, 0*xpos)
    if check(rmov):
        return True

    # scan
    for rmov in spiral_scan():
        if check(rmov):
            return True

    return False