Exemple #1
0
def animate_detection(imstack, fsets, fcsets, fosets=None, rc=0, side=15, verbose=False):

    from matplotlib.patches import Circle

    def advance(event):
        key = event.key
        if verbose:
            print 'pressed', key, 'next frame:',
        global f_display
        if key=='left':
            if f_display>=1:
                f_display -= 1
        elif key=='right':
            f_display += 1
        else:
            plt.close()
            f_display = -1
        if verbose:
            print f_display
            sys.stdout.flush()

    plt_text = np.vectorize(plt.text)

    def draw_circles(ax, centers, r, *args, **kwargs):
        patches = [Circle(cent, r, *args, **kwargs) for cent in centers]
        map(ax.add_patch, patches)
        ax.figure.canvas.draw()
        return patches

    if side==1:
        side = 15
    txtoff = max(rc, side, 10)

    fig = plt.figure(figsize=(12, 12))
    p = plt.imshow(imstack[0], cmap='gray')
    h, w = imstack[0].shape
    ax = p.axes
    global f_display
    f_display = repeat = f_old = 0
    lengths = map(len, [imstack, fsets, fcsets])
    f_max = min(lengths)
    assert f_max, 'Lengths imstack: {}, fsets: {}, fcsets: {}'.format(*lengths)
    while 0 <= f_display < f_max:
        if repeat > 5:
            if verbose:
                print 'stuck on frame', f_display
            break
        f_display %= f_max
        if f_display==f_old:
            repeat += 1
        else:
            repeat = 0
        f_old = f_display
        if verbose:
            print 'starting loop with f_display =', f_display
        xyo = helpy.consecutive_fields_view(fsets[f_display], 'xyo', False)
        xyc = helpy.consecutive_fields_view(fcsets[f_display], 'xy', False)
        x, y, o = xyo.T
        omask = np.isfinite(o)
        xo, yo, oo = xyo[omask].T

        p.set_data(imstack[f_display])
        remove = []
        if rc > 0:
            patches = draw_circles(ax, xyo[:, 1::-1], rc,
                                color='g', fill=False, zorder=.5)
            remove.extend(patches)
        q = plt.quiver(yo, xo, np.sin(oo), np.cos(oo), angles='xy',
                       units='xy', width=side/8, scale_units='xy', scale=1/side)
        ps = plt.scatter(y, x, c='r')#c=np.where(omask, 'r', 'b'))
        cs = plt.scatter(xyc[:,1], xyc[:,0], c='g', s=8)
        if fosets is not None:
            oc = helpy.quick_field_view(fosets[f_display], 'corner').reshape(-1, 2)
            ocs = plt.scatter(oc[:,1], oc[:,0], c='orange', s=8)
            remove.append(ocs)
        remove.extend([q, ps, cs])

        tstr = fsets[f_display]['t'].astype('S')
        txt = plt_text(y+txtoff, x+txtoff, tstr, color='r')
        remove.extend(txt)

        plt.xlim(0, w)
        plt.ylim(0, h)
        plt.title("frame {}\n{} orientations / {} particles detected".format(
                    f_display, np.count_nonzero(omask), len(o)))
        fig.canvas.draw()

        plt.waitforbuttonpress()
        fig.canvas.mpl_connect('key_press_event', advance)
        for rem in remove:
            rem.remove()
        if verbose:
            print 'ending frame', f_display
            sys.stdout.flush()
    if verbose:
        print 'loop broken'
Exemple #2
0
def get_angles(pdata,
               cdata,
               pfsets,
               cfsets,
               cftrees,
               nc,
               rc,
               drc=None,
               ang=None,
               dang=None,
               do_average=True,
               verbose=False):
    """find the orientations of particles given center and corner positions

    Parameters
    ----------
    pdata:      data array with 'x' and 'y' fields for particle centers
    cdata:      data array wity 'x' and 'y' fields for corners
        pdata and cdata arrays need not have the same length,
        but both must have 'f' field for the image frame)
    pfsets:     slices into pdata, by frame
    cfsets:     slices into cdata, by frame
    cftrees:    dict of KDTrees for corners, by frame
        the following arguments are passed to find_corner:
    nc:         number of corner dots
    rc:         expected distance between center and corner dot
    drc:        tolerance for rc, defaults to sqrt(rc)
    ang:        angular separation between corners (if nc > 1)
    dang:       tolerance for ang (if None, ang is ignored if nfound == nc, but
                is uses to choose best nc of nfound if nfound > nc)
    do_average: whether to average the nc corners to one value for return

    Returns
    -------
    odata:  structured array, same shape as pdata, with fields:
            'corner' for particle corner (with 'x' and 'y' sub-fields)
            'orient' for orientation of particles
            'cdisp' for the corner - center displacement
    """
    dt = [('corner', float, (nc, 2)), ('orient', float),
          ('cdisp', float, (nc, ))]
    if nc > 1 and not do_average:
        dt[1] += ((nc, ), )  # give the 'orient' field a shape of (nc,)
    odata = np.full(len(pdata), np.nan, dtype=dt)
    if ang > pi:
        ang = np.radians(ang)
        if dang:
            dang = np.radians(dang)
    odata_corner = odata['corner']
    odata_orient = odata['orient']
    odata_cdisp = odata['cdisp']
    full_ids = pdata['id']
    id_ok = full_ids[0] == 0 and np.all(np.diff(full_ids) == 1)
    print_freq = len(pfsets) // (100 if verbose > 1 else 5) + 1
    print 'seeking orientations'
    for f in pfsets:
        if verbose and not f % print_freq:
            print f,
        fpdata = pfsets[f]
        fcdata = cfsets[f]
        cftree = cftrees[f]
        positions = helpy.consecutive_fields_view(fpdata, 'xy')
        cpositions = helpy.consecutive_fields_view(fcdata, 'xy')
        fp_ids = helpy.quick_field_view(fpdata, 'id')
        for fp_id, posi in it.izip(fp_ids, positions):
            # TODO could probably be sped up by looping through the output of
            # ptree.query_ball_tree(ctree)
            corner, orient, disp = \
                find_corner(posi, cpositions, nc=nc, rc=rc, drc=drc, ang=ang,
                            dang=dang, tree=cftree, do_average=do_average)
            if orient is None:
                continue
            full_id = fp_id if id_ok else np.searchsorted(full_ids, fp_id)
            odata_corner[full_id] = corner
            odata_orient[full_id] = orient
            odata_cdisp[full_id] = disp

    if do_average or nc == 1:
        mask = np.isfinite(odata['orient'])
    elif nc > 1:
        mask = np.all(np.isfinite(odata['orient']), axis=1)

    return odata, mask
def get_angles_loop(pdata, cdata, pfsets, cfsets, cftrees, nc=3, rc=11, drc=0, do_average=True, verbose=False):
    """ get_angles(pdata, cdata, pfsets, cfsets, cftrees, nc=3, rc=11, drc=0, do_average=True)
        
        arguments:
            pdata   - data array with 'x' and 'y' fields for particle centers
            cdata   - data array wity 'x' and 'y' fields for corners
                (these arrays need not have the same length,
                    but both must have 'f' field for the image frame)
            pfsets  - slices into pdata, by frame
            cfsets  -    and for cdata
            cftrees - dict of KDTrees for corners, by frame
            nc      - number of corner dots
            rc      - distance between center and corner dot
            drc     - tolerance for rc
            do_average - whether to average the nc corners to one value for return
            
        returns:
            odata   - array with fields:
                'orient' for orientation of particles
                'corner' for particle corner (with 'x' and 'y' sub-fields)
            (odata has the same shape as data)
    """
    import helpy
    if do_average or nc == 1:
        dt = [('corner',float,(nc,2)),
              ('orient',float),
              ('cdisp',float,(nc,))]
    elif nc > 1:
        dt = [('corner',float,(nc,2,)),
              ('orient',float,(nc,)),
              ('cdisp',float,(nc,))]
    odata = np.full(len(pdata), np.nan, dtype=dt)
    odata_corner = odata['corner']
    odata_orient = odata['orient']
    odata_cdisp  = odata['cdisp']
    full_ids = pdata['id']
    id_ok = full_ids[0]==0 and np.all(np.diff(full_ids)==1)
    print_freq = len(pfsets)//(100 if verbose>1 else 5) + 1
    if verbose:
        print 'seeking orientations'
    for f in pfsets:
        if verbose and not f % print_freq:
            print f,
        fpdata = pfsets[f]
        fcdata = cfsets[f]
        tree = cftrees[f]
        positions = helpy.consecutive_fields_view(fpdata, 'xy')
        cpositions = helpy.consecutive_fields_view(fcdata, 'xy')
        frame_ids = helpy.quick_field_view(fpdata, 'id')
        for frame_id, posi in izip(frame_ids, positions):
            #TODO could probably be sped up by looping through the output of
            #     ptree.query_ball_tree(ctree)
            corner, orient, disp = \
                find_corner(posi, cpositions, tree=tree,
                            nc=nc, rc=rc, drc=drc, do_average=do_average)
            if orient is None: continue
            full_id = frame_id if id_ok else np.searchsorted(full_ids, frame_id)
            odata_corner[full_id] = corner
            odata_orient[full_id] = orient
            odata_cdisp[full_id] = disp

    if do_average or nc == 1:
        mask = np.isfinite(odata['orient'])
    elif nc > 1:
        mask = np.all(np.isfinite(odata['orient']), axis=1)

    return odata, mask
def get_angles(pdata, cdata, pfsets, cfsets, cftrees, nc, rc, drc=None,
               ang=None, dang=None, do_average=True, verbose=False):
    """find the orientations of particles given center and corner positions

    Parameters
    ----------
    pdata:      data array with 'x' and 'y' fields for particle centers
    cdata:      data array wity 'x' and 'y' fields for corners
        pdata and cdata arrays need not have the same length,
        but both must have 'f' field for the image frame)
    pfsets:     slices into pdata, by frame
    cfsets:     slices into cdata, by frame
    cftrees:    dict of KDTrees for corners, by frame
        the following arguments are passed to find_corner:
    nc:         number of corner dots
    rc:         expected distance between center and corner dot
    drc:        tolerance for rc, defaults to sqrt(rc)
    ang:        angular separation between corners (if nc > 1)
    dang:       tolerance for ang (if None, ang is ignored if nfound == nc, but
                is uses to choose best nc of nfound if nfound > nc)
    do_average: whether to average the nc corners to one value for return

    Returns
    -------
    odata:  structured array, same shape as pdata, with fields:
            'corner' for particle corner (with 'x' and 'y' sub-fields)
            'orient' for orientation of particles
            'cdisp' for the corner - center displacement
    """
    dt = [('corner', float, (nc, 2)),
          ('orient', float),
          ('cdisp', float, (nc,))]
    if nc > 1 and not do_average:
        dt[1] += ((nc,),)   # give the 'orient' field a shape of (nc,)
    odata = np.full(len(pdata), np.nan, dtype=dt)
    if ang > pi:
        ang = np.radians(ang)
        if dang:
            dang = np.radians(dang)
    odata_corner = odata['corner']
    odata_orient = odata['orient']
    odata_cdisp = odata['cdisp']
    full_ids = pdata['id']
    id_ok = full_ids[0] == 0 and np.all(np.diff(full_ids) == 1)
    print_freq = len(pfsets)//(100 if verbose > 1 else 5) + 1
    print 'seeking orientations'
    for f in pfsets:
        if verbose and not f % print_freq:
            print f,
        fpdata = pfsets[f]
        fcdata = cfsets[f]
        cftree = cftrees[f]
        positions = helpy.consecutive_fields_view(fpdata, 'xy')
        cpositions = helpy.consecutive_fields_view(fcdata, 'xy')
        fp_ids = helpy.quick_field_view(fpdata, 'id')
        for fp_id, posi in it.izip(fp_ids, positions):
            # TODO could probably be sped up by looping through the output of
            # ptree.query_ball_tree(ctree)
            corner, orient, disp = \
                find_corner(posi, cpositions, nc=nc, rc=rc, drc=drc, ang=ang,
                            dang=dang, tree=cftree, do_average=do_average)
            if orient is None:
                continue
            full_id = fp_id if id_ok else np.searchsorted(full_ids, fp_id)
            odata_corner[full_id] = corner
            odata_orient[full_id] = orient
            odata_cdisp[full_id] = disp

    if do_average or nc == 1:
        mask = np.isfinite(odata['orient'])
    elif nc > 1:
        mask = np.all(np.isfinite(odata['orient']), axis=1)

    return odata, mask