예제 #1
0
def main(inputs):
    """
    Main function for accessing post-process functions.
    
    args:
        inputs: command line inputs
    
    """
    a = parseargs.main(sys.argv[1:])
    a.properties = os.path.abspath(a.properties)

    # Read in midline and parameterize it
    importdata_inputs = (a.properties, a.frame_range, a.version)
    nosedist, nosetail = importdata.main(*importdata_inputs)
    
    # Get full set of frames (without error frames removed)
    is_loop = readtxt(a.properties, "is_loop", a.frame_range, str)
    all_frames = is_loop.keys()
    
    if a.action == 'check':
        # Remove looped frames (if using Nick's midline)
        if a.version == 0:
            for k, v in is_loop.iteritems():
                if nosedist.has_key(k) and v == 'True':
                    del nosedist[k], nosetail[k]
        
        # Find frames with bad lengths and write to .txt file
        checklength_inputs = (nosedist, a.len_span, 
                              a.len_max_dev, a.len_max_val)
        bad_length = checklength.main(*checklength_inputs)
        writetxt(a.properties, "bad_length", bad_length, all_frames, "%r")
        
        # Remove bad length frames before continuing
        for k, v in bad_length.iteritems():
            if v:
                del nosedist[k], nosetail[k]
        
        # Find frames that should be flipped and write to .txt file
        flipheadtail_inputs = (nosedist, nosetail, 
                               a.flip_degree, a.flip_iters, a.flip_span, 
                               a.flip_min_dev, a.flip_max_dev)
        is_flipped = flipheadtail.main(*flipheadtail_inputs)
        writetxt(a.properties, "is_flipped", is_flipped, all_frames, "%s")
        
    elif a.action == 'spline':
        if a.output == "":
            a.output = os.path.join(os.path.dirname(a.properties), 'processed')
        os.path.isdir(a.output) or os.mkdir(a.output)
        
        if a.use_checks:
            # Read in all checks from file (just skip if missing files)
            old_frames = nosedist.keys()
            checks = dict.fromkeys(['is_loop', 'bad_length', 'is_flipped'])
            
            # Initialize all values to 'False'
            for k in checks.keys():
                try:
                    v = readtxt(a.properties, k, a.frame_range, str)
                except IOError:
                    v = dict.fromkeys(old_frames, 'False')
                checks[k] = v
            
            # Do not use is_loop for Marc's midline
            if a.version == 1:
                checks['is_loop'] = dict.fromkeys(old_frames, 'False')
            
            # Do not flip unless thus requested
            if not a.reorient:
                checks['is_flipped'] = dict.fromkeys(old_frames, 'False')
            
            for k in old_frames:
                try:
                    # Remove loops, bad lengths and unknown orientations
                    if (checks['is_loop'][k] == 'True' or 
                        checks['bad_length'][k] == 'True' or
                        checks['is_flipped'][k] == 'Indeterminate'):
                        del nosedist[k], nosetail[k]
                    # Flip frames with bad orientation
                    elif checks['is_flipped'][k] == 'True':
                        nosedist[k] = (max(nosedist[k]) - nosedist[k])[::-1]
                        nosetail[k] = nosetail[k][::-1]
                except KeyError:
                    # Also remove frames for which checks are unavailable
                    del nosedist[k], nosetail[k]
        
        # Spline the worm and write the .txt files to a new directory
        up_rate = 5
        splinefit_inputs = (nosedist, nosetail, up_rate*a.smoothing, 
                            up_rate*a.num_points, a.spacing, a.length)
        nosedist, nosetail, noseder = splinefit.main(*splinefit_inputs)
        
        # Calculate the length by integrating over the midline
        wormlength = {}
        for k, u in nosedist.iteritems():
            dx, dy = noseder[k]
            z = integrate.trapz(np.sqrt(dx ** 2 + dy ** 2), u)
            wormlength[k] = z
        
        # Reformat the splined midline before saving to file
        nosetail = {k : np.asarray(zip(*v))[::up_rate] 
                    for k, v in nosetail.iteritems()}
        
        writetxt(a.output, "wormlength", wormlength, all_frames, "%0.2f")
        writetxt(a.output, "nosetail", nosetail, all_frames, "%0.2f")
        
        # Create dictionary for saving to .mat file
        data_dict = {'nosetail' : nosetail, 'wormlength' : wormlength}
        
        if a.keep_sides:
            # Read information from side paths
            sideonepath = readtxt(a.properties, 'sideonepath', a.frame_range)
            sidetwopath = readtxt(a.properties, 'sidetwopath', a.frame_range)
            
            sidepath = dict.fromkeys(nosedist.keys())
            for k in sidepath.keys():
                v = sideonepath[k][:-1]
                v.extend(sidetwopath[k][::-1])
                if v[0] != v[-1]:
                    v.append(v[0])
                sidepath[k] = np.asarray(v)
            sidedist, sidepath = importdata.getnosedist(sidepath)
            
            splinefit_inputs = (sidedist, sidepath, a.smoothing, 
                                up_rate*2*a.num_points, up_rate*2*a.spacing, 
                                0., 1)
            sidedist, sidepath, sideder = splinefit.main(*splinefit_inputs)
            
            # Calculate the area by integrating around the perimeter
            wormarea = {}
            for k, u in sidedist.iteritems():
                x = sidepath[k][0]
                dy = sideder[k][1]
                z = np.abs(integrate.trapz(x * dy, u))
                wormarea[k] = z
            
            # Reformat the splined perimeter before saving to file
            sidepath = {k : np.asarray(zip(*v))[::up_rate] 
                        for k, v in sidepath.iteritems()}
            
            writetxt(a.output, "wormarea", wormarea, all_frames, "%0.2f")
            writetxt(a.output, "sidepath", sidepath, all_frames, "%0.2f")
            
            data_dict['wormarea'] = wormarea
            data_dict['sidepath'] = sidepath
        
        # Save to .mat file
        savemat(a.output + '.mat', data_dict)
    
    # Print error check on all files in the directory
    fs, ds = [], []
    for f in os.listdir(a.properties):
        if os.path.splitext(f)[1] == '.txt':
            fs.append(f)
            ds.append(a.properties)
    if a.action == 'spline':
        for f in os.listdir(a.output):
            if os.path.splitext(f)[1] == '.txt':
                fs.append(f)
                ds.append(a.output)
    
    w1 = max([len(f) for f in fs])
    if a.action == 'check':
        print 'Frames that passed checks:'
        for p, b in zip(['is_loop', 'bad_length', 'is_flipped'], 
                        [('False', ), ('False', ), ('True', 'False')]):
            try:
                imported = readtxt(a.properties, p, a.frame_range, str)
                n = len(imported)
                m = len([v for v in imported.values() if v in b])
                r1 = '%d/%d' % (m, n)
                r2 = '%0.2f%%' % (100 * float(m) / n) if n > 0 else ""
                print '{:{w1}} {:{w2}} {}'.format(p, r1, r2, w1=w1, w2=15)
            except:
                pass
    elif a.action == 'spline':
        print 'Frames without errors:'
        for f in os.listdir(a.output):
            p = os.path.splitext(f)[0]
            try:
                imported = readtxt(a.output, p, a.frame_range, str)
                n = len(imported)
                m = len([v for v in imported.values() if v != "-1"])
                r1 = '%d/%d' % (m, n)
                r2 = '%0.2f%%' % (100 * float(m) / n) if n > 0 else ""
                print '{:{w1}} {:{w2}} {}'.format(p, r1, r2, w1=w1, w2=15)
            except:
                pass
예제 #2
0
def main(inputs):
    """
    Main function for accessing post-process functions.
    
    args:
        inputs: command line inputs
    
    """
    a = parseargs.main(sys.argv[1:])
    a.properties = os.path.abspath(a.properties)

    # Read in midline and parameterize it
    importdata_inputs = (a.properties, a.frame_range, a.version)
    nosedist, nosetail = importdata.main(*importdata_inputs)

    # Get full set of frames (without error frames removed)
    is_loop = readtxt(a.properties, "is_loop", a.frame_range, str)
    all_frames = is_loop.keys()

    if a.action == 'check':
        # Remove looped frames (if using Nick's midline)
        if a.version == 0:
            for k, v in is_loop.iteritems():
                if nosedist.has_key(k) and v == 'True':
                    del nosedist[k], nosetail[k]

        # Find frames with bad lengths and write to .txt file
        checklength_inputs = (nosedist, a.len_span, a.len_max_dev,
                              a.len_max_val)
        bad_length = checklength.main(*checklength_inputs)
        writetxt(a.properties, "bad_length", bad_length, all_frames, "%r")

        # Remove bad length frames before continuing
        for k, v in bad_length.iteritems():
            if v:
                del nosedist[k], nosetail[k]

        # Find frames that should be flipped and write to .txt file
        flipheadtail_inputs = (nosedist, nosetail, a.flip_degree, a.flip_iters,
                               a.flip_span, a.flip_min_dev, a.flip_max_dev)
        is_flipped = flipheadtail.main(*flipheadtail_inputs)
        writetxt(a.properties, "is_flipped", is_flipped, all_frames, "%s")

    elif a.action == 'spline':
        if a.output == "":
            a.output = os.path.join(os.path.dirname(a.properties), 'processed')
        os.path.isdir(a.output) or os.mkdir(a.output)

        if a.use_checks:
            # Read in all checks from file (just skip if missing files)
            old_frames = nosedist.keys()
            checks = dict.fromkeys(['is_loop', 'bad_length', 'is_flipped'])

            # Initialize all values to 'False'
            for k in checks.keys():
                try:
                    v = readtxt(a.properties, k, a.frame_range, str)
                except IOError:
                    v = dict.fromkeys(old_frames, 'False')
                checks[k] = v

            # Do not use is_loop for Marc's midline
            if a.version == 1:
                checks['is_loop'] = dict.fromkeys(old_frames, 'False')

            # Do not flip unless thus requested
            if not a.reorient:
                checks['is_flipped'] = dict.fromkeys(old_frames, 'False')

            for k in old_frames:
                try:
                    # Remove loops, bad lengths and unknown orientations
                    if (checks['is_loop'][k] == 'True'
                            or checks['bad_length'][k] == 'True'
                            or checks['is_flipped'][k] == 'Indeterminate'):
                        del nosedist[k], nosetail[k]
                    # Flip frames with bad orientation
                    elif checks['is_flipped'][k] == 'True':
                        nosedist[k] = (max(nosedist[k]) - nosedist[k])[::-1]
                        nosetail[k] = nosetail[k][::-1]
                except KeyError:
                    # Also remove frames for which checks are unavailable
                    del nosedist[k], nosetail[k]

        # Spline the worm and write the .txt files to a new directory
        up_rate = 5
        splinefit_inputs = (nosedist, nosetail, up_rate * a.smoothing,
                            up_rate * a.num_points, a.spacing, a.length)
        nosedist, nosetail, noseder = splinefit.main(*splinefit_inputs)

        # Calculate the length by integrating over the midline
        wormlength = {}
        for k, u in nosedist.iteritems():
            dx, dy = noseder[k]
            z = integrate.trapz(np.sqrt(dx**2 + dy**2), u)
            wormlength[k] = z

        # Reformat the splined midline before saving to file
        nosetail = {
            k: np.asarray(zip(*v))[::up_rate]
            for k, v in nosetail.iteritems()
        }

        writetxt(a.output, "wormlength", wormlength, all_frames, "%0.2f")
        writetxt(a.output, "nosetail", nosetail, all_frames, "%0.2f")

        # Create dictionary for saving to .mat file
        data_dict = {'nosetail': nosetail, 'wormlength': wormlength}

        if a.keep_sides:
            # Read information from side paths
            sideonepath = readtxt(a.properties, 'sideonepath', a.frame_range)
            sidetwopath = readtxt(a.properties, 'sidetwopath', a.frame_range)

            sidepath = dict.fromkeys(nosedist.keys())
            for k in sidepath.keys():
                v = sideonepath[k][:-1]
                v.extend(sidetwopath[k][::-1])
                if v[0] != v[-1]:
                    v.append(v[0])
                sidepath[k] = np.asarray(v)
            sidedist, sidepath = importdata.getnosedist(sidepath)

            splinefit_inputs = (sidedist, sidepath, a.smoothing,
                                up_rate * 2 * a.num_points,
                                up_rate * 2 * a.spacing, 0., 1)
            sidedist, sidepath, sideder = splinefit.main(*splinefit_inputs)

            # Calculate the area by integrating around the perimeter
            wormarea = {}
            for k, u in sidedist.iteritems():
                x = sidepath[k][0]
                dy = sideder[k][1]
                z = np.abs(integrate.trapz(x * dy, u))
                wormarea[k] = z

            # Reformat the splined perimeter before saving to file
            sidepath = {
                k: np.asarray(zip(*v))[::up_rate]
                for k, v in sidepath.iteritems()
            }

            writetxt(a.output, "wormarea", wormarea, all_frames, "%0.2f")
            writetxt(a.output, "sidepath", sidepath, all_frames, "%0.2f")

            data_dict['wormarea'] = wormarea
            data_dict['sidepath'] = sidepath

        # Save to .mat file
        savemat(a.output + '.mat', data_dict)

    # Print error check on all files in the directory
    fs, ds = [], []
    for f in os.listdir(a.properties):
        if os.path.splitext(f)[1] == '.txt':
            fs.append(f)
            ds.append(a.properties)
    if a.action == 'spline':
        for f in os.listdir(a.output):
            if os.path.splitext(f)[1] == '.txt':
                fs.append(f)
                ds.append(a.output)

    w1 = max([len(f) for f in fs])
    if a.action == 'check':
        print 'Frames that passed checks:'
        for p, b in zip(['is_loop', 'bad_length', 'is_flipped'],
                        [('False', ), ('False', ), ('True', 'False')]):
            try:
                imported = readtxt(a.properties, p, a.frame_range, str)
                n = len(imported)
                m = len([v for v in imported.values() if v in b])
                r1 = '%d/%d' % (m, n)
                r2 = '%0.2f%%' % (100 * float(m) / n) if n > 0 else ""
                print '{:{w1}} {:{w2}} {}'.format(p, r1, r2, w1=w1, w2=15)
            except:
                pass
    elif a.action == 'spline':
        print 'Frames without errors:'
        for f in os.listdir(a.output):
            p = os.path.splitext(f)[0]
            try:
                imported = readtxt(a.output, p, a.frame_range, str)
                n = len(imported)
                m = len([v for v in imported.values() if v != "-1"])
                r1 = '%d/%d' % (m, n)
                r2 = '%0.2f%%' % (100 * float(m) / n) if n > 0 else ""
                print '{:{w1}} {:{w2}} {}'.format(p, r1, r2, w1=w1, w2=15)
            except:
                pass
예제 #3
0
def main(
    nosedist,
    nosetail,
    degree=DEGREE,
    num_iters=NUM_ITERS,
    span=SPAN,
    min_dev=MIN_DEV,
    max_dev=MAX_DEV,
    smoothing=SMOOTHING,
    num_points=NUM_POINTS,
):
    """
    Find frames where head/tail identification has failed by making a 
    polynomial representation of the worm and comparing the value of the 
    coefficients frame-by-frame to the average in a sliding window. If the size of the sliding window is set to just one frame however, do not fit to a polynomial but instead calculate the Euclidean distance between points along splined worms in consecutive frames, counting a flip if the norm between 'forward' and 'reverse' is smaller than between both 'forward'.
    
    args:
        nosedist (dict): dict of numpy arrays of distance from nose to tail
        
        nosetail (dict): dict of numpy arrays of coordinates along midline
    
    kwargs:
        degree (int): degree of polynomial fit
        
        num_iters (int): number of times to repeat the head/tail flip check
        
        span (int): number of points in final midline
        
        min_dev (float): spacing between points
        
        max_dev (float): dict of desired lengths of each midline
    
    returns:
        is_flipped (dict): dict of strings with values of 
        'False': no flip (value < min_dev)
        'True': yes flip (value > max_dev)
        'Indeterminate': could not determine (min_dev < value < max_dev)
    
    """

    if span > 1:
        # Make the polynomial fit in the forward and reverse directions
        coefs_for = makepolyfit(nosedist, nosetail, degree=degree)
        taildist = dict.fromkeys(nosedist.keys())
        for k, v in nosedist.iteritems():
            taildist[k] = (max(v) - v)[::-1]
        coefs_rev = makepolyfit(taildist, nosetail, degree=degree)

        # Check iteratively for frames that have been flipped (try to correct
        # for large neighborhoods where nose has been incorrectly identified)
        for i in range(num_iters):
            coefs_for, coefs_rev = checkflips(coefs_for, coefs_rev, span, min_dev, max_dev)[:2]
        is_flipped = checkflips(coefs_for, coefs_rev, span, min_dev, max_dev)[-1]
    else:
        # Create a splined worm with an even number of points for each frame
        nosetail = splinefit.main(nosedist, nosetail, smoothing, num_points)[1]

        # Just check by comparing the current worm to the flipped last worm
        frames = sorted(nosetail.keys())
        is_flipped = dict.fromkeys(frames, "False")

        x1, y1 = nosetail[frames[0]]
        for i in frames[1:]:
            x2, y2 = nosetail[i]

            # Calculate the Euclidean distance between corresponding points
            f = np.sum(np.sqrt((x1 - x2[::+1]) ** 2 + (y1 - y2[::+1]) ** 2))
            r = np.sum(np.sqrt((x1 - x2[::-1]) ** 2 + (y1 - y2[::-1]) ** 2))

            # Flip if the norm between current forward worm and previous
            # reverse worm is smaller than between both forward worms
            if f > r:
                is_flipped[i] = "True"
                x1, y1 = x2[::-1], y2[::-1]
            else:
                x1, y1 = x2[::+1], y2[::+1]

    return is_flipped