#%% Determine Lethargus phases

l_pks_0 = [];
k = 0;
verbose = True;

for wid in range(nworms):
  r = exp.load(strain = strain, wid = wid, dtype = 'rotation')
  r_mean = average(r, nbins);
  
  # smooth roaming curve
  rf = sig.savgol_filter(r_mean, 51, 7)

  # find minima and mark
  pks = pd.find_peaks(rf, 0.5);
  l_pks_0.append(pks);
  
  if verbose: 
    if wid % 16 == 0:
      k += 1;
      fig = plt.figure(111+k); plt.clf();
      plt.subplot(4,4,1);
      i = 2;
    else:
      plt.subplot(4,4,i);
      i += 1;
    plt.plot(r_mean, '.')  
    plt.plot(rf, 'k')
    plt.title('worm %d' % wid);
    if len(pks) > 0:
#%% Determine Lethargus phases

l_pks_0 = [];
k = 0;
verbose = True;

for wid in range(nworms):
  r = exp.load(strain = strain, wid = wid, dtype = 'rotation')
  r_mean = average(r, nbins);
  
  # smooth roaming curve
  rf = sig.savgol_filter(r_mean, 51, 7)

  # find minima and mark
  pks = pd.find_peaks(rf, 0.5);
  l_pks_0.append(pks);
  
  if verbose: 
    if wid % 16 == 0:
      k += 1;
      fig = plt.figure(111+k); plt.clf();
      plt.subplot(4,4,1);
      i = 2;
    else:
      plt.subplot(4,4,i);
      i += 1;
    plt.plot(r_mean, '.')  
    plt.plot(rf, 'k')
    plt.title('worm %d' % wid);
    plt.scatter(pks[:,0], pks[:,1], s = 60, c = 'r')
예제 #3
0
plt.imshow(img, cmap = 'gray', interpolation = 'nearest')
plt.plot(x, y, 'b--')
plt.scatter(x, y, s = 1)
plt.show()

# curvature along the points
dx, dy = splev(us[:-1], cinterp, der = 1)
d2x, d2y = splev(us[:-1], cinterp, der = 2)
k = (dx * d2y - dy * d2x)/np.power(dx**2 + dy**2, 1.5);


# find tail and head via peak detection

from signalprocessing.peak_detection import find_peaks

peaks = find_peaks(np.abs(k), delta = 0.15);

imax = np.sort(np.asarray(peaks[np.argsort(peaks[:,1])[-2:],0], dtype = int))

print 'max k at %s' % str(imax)

plt.scatter(x[imax], y[imax], s=150, color='r')


plt.subplot(1,3,3)
plt.plot(np.abs(k))



# calcualte paths along both sides
예제 #4
0
def analyse_shape(img,
                  sigma=1,
                  threshold_level=0.95,
                  npts_contour=100,
                  npts_sides=21,
                  smooth=1.0,
                  verbose=False,
                  save=None):
    """Detect and ,measure shape features"""

    ### smooth image
    imgs = filters.gaussian_filter(np.asarray(img, float), sigma)

    ### get contours
    level = threshold_level * threshold_otsu(imgs)
    pts = detect_contour(imgs, level)

    if len(pts) == 0:
        return True, np.zeros((npts_sides, 2)), np.zeros(
            (npts_sides, 2)), np.zeros((npts_sides, 2))

    elif len(pts) > 2:
        #raise RuntimeWarning('found %d contours, expected 1 or 2!' % len(pts));
        #return np.zeros(2), np.zeros(2), np.zeros(2), 0, 0, np.zeros((2, npts_sides)), np.zeros((2, npts_sides)), np.zeros((2, npts_sides))
        pts, pts_inner = pts[0], pts[1]

    elif len(pts) == 1:
        pts, pts_inner = pts[0], None

    else:  #len(pts) == 2
        if pts[0].shape[0] < pts[1].shape[0]:
            i, o = 0, 1
        else:
            i, o = 1, 0

        if inside_polygon(pts[i], pts[o][0, :]):
            i, o = o, i

        pts, pts_inner = pts[o], pts[i]

    ### interpolate outer contour
    cinterp, u = splprep(pts.T, u=None, s=smooth, per=1)
    us = np.linspace(u.min(), u.max(), npts_contour)
    x, y = splev(us[:-1], cinterp, der=0)

    ### curvature along the points
    dx, dy = splev(us[:-1], cinterp, der=1)
    d2x, d2y = splev(us[:-1], cinterp, der=2)
    k = (dx * d2y - dy * d2x) / np.power(dx**2 + dy**2, 1.5)

    ### find tail and head via peak detection

    #pad k to detect peaks on both sides
    nextra = 20
    kk = -k
    # negative curvature peaks are heads/tails
    kk = np.hstack([kk, kk[:nextra]])
    peaks = find_peaks(kk, delta=0.3)
    #print peaks.shape
    if peaks.shape[0] > 0:
        peaks = peaks[peaks[:, 0] < k.shape[0], :]

    #plt.figure(15); plt.clf();
    #plt.plot(kk);
    #plt.scatter(peaks[:,0], peaks[:,1], c = 'r');

    #if peaks.shape[0] < 2:
    #  peaks = find_peaks(np.abs(k), delta = 0.05);
    #print peaks.shape
    if peaks.shape[0] < 2:
        if peaks.shape[0] == 1:
            # best guess is half way along the contour
            imax = np.sort(
                np.asarray(np.mod(
                    peaks[0, 0] + np.array([0, npts_contour / 2]),
                    npts_contour),
                           dtype=int))
        else:
            imax = np.array([0, 50])
    else:
        imax = np.sort(
            np.asarray(peaks[np.argsort(peaks[:, 1])[-2:], 0], dtype=int))

    #print imax

    # calcualte paths along both sides

    u1 = np.linspace(us[imax[0]], us[imax[1]], npts_sides)
    x1, y1 = splev(u1, cinterp, der=0)

    u2 = np.linspace(us[imax[0]], us[imax[1]] - 1, npts_sides)
    u2 = np.mod(u2, 1)
    x2, y2 = splev(u2, cinterp, der=0)

    # midline (simple)
    #xm = (x1 + x2) / 2; ym = (y1 + y2) / 2;
    xm, ym, nu = find_midline(x1, y1, x2, y2, offset=3)
    xym = np.vstack([xm, ym])
    xymintp, u = splprep(xym, u=None, s=1.0, per=0)

    # worm center
    xc, yc = splev([0.5], xymintp, der=0)
    xc = xc[0]
    yc = yc[0]

    if verbose:
        #print 'max k at %s' % str(imax)

        plt.figure(11)
        plt.clf()
        plt.subplot(2, 3, 1)
        plt.imshow(img, interpolation='nearest')
        plt.subplot(2, 3, 2)
        plt.imshow(imgs)
        plt.subplot(2, 3, 3)
        plt.imshow(img, cmap='gray')
        plt.contour(imgs, levels=[threshold_level * threshold_otsu(imgs)])
        #plt.imshow(img, cmap = 'gray', interpolation = 'nearest')
        #plt.scatter(pts[:,0], pts[:,1])
        #plt.plot(x, y, 'b--')

        #plot curvature
        plt.subplot(2, 3, 4)
        plt.plot(k)
        plt.scatter(imax, k[imax], c='r', s=100)
        if peaks.shape[0] > 0:
            plt.scatter(peaks[:, 0], -peaks[:, 1], c='m', s=40)

        # shape detection
        plt.subplot(2, 3, 5)
        plt.imshow(img, cmap='gray', interpolation='nearest')

        #plot lines and midline
        plt.plot(x1, y1, 'g', linewidth=4)
        plt.plot(x2, y2, 'y', linewidth=4)
        plt.plot(xm, ym, 'b')

        # plot segments
        for i in range(len(xm)):
            plt.plot([x1[i], x2[nu[i]]], [y1[i], y2[nu[i]]], 'm')

        #plot center
        plt.scatter(xc, yc, color='k')
        plt.scatter(x[imax], y[imax], s=150, color='r')

        #plot width profile
        plt.subplot(2, 3, 6)

        w = np.zeros(len(xm))
        for i in range(len(xm)):
            w[i] = np.linalg.norm([x2[nu[i]] - x1[i], y2[nu[i]] - y1[i]])
        plt.plot(w)

        if isinstance(save, basestring):
            fig = plt.figure(11)
            fig.savefig(save)

    ### measure features

    # points
    #pos_head = np.array([x1[0], y1[0]])
    #pos_tail = np.array([x1[-1], y1[-1]])
    #pos_center = np.array([xc, yc]);

    # head tail distance:
    #dist_head_tail = np.linalg.norm(pos_head-pos_tail)
    #dist_head_center = np.linalg.norm(pos_head-pos_center)
    #dist_tail_center = np.linalg.norm(pos_tail-pos_center)

    #average curvature
    #dcx, dcy = splev(u, xymintp, der = 1)
    #d2cx, d2cy = splev(u, xymintp, der = 2)
    #ck = (dcx * d2cy - dcy * d2cx)/np.power(dcx**2 + dcy**2, 1.5);
    #curvature_mean = np.mean(ck);
    #curvature_variation = np.sum(np.abs(ck))

    #cruves
    line_center = xym.T
    line_left = np.vstack([x1, y1]).T
    line_right = np.vstack([x2, y2]).T

    curled = pts_inner is None

    return curled, line_center, line_left, line_right
예제 #5
0
ncontour = 100
smooth = 1.0
cinterp, u = splprep(pts.T, u = None, s = smooth, per = 1) 
us = np.linspace(u.min(), u.max(), ncontour)
x, y = splev(us[:-1], cinterp, der = 0)

dx, dy = splev(us[:-1], cinterp, der = 1)
d2x, d2y = splev(us[:-1], cinterp, der = 2)
k = (dx * d2y - dy * d2x)/np.power(dx**2 + dy**2, 1.5);

from signalprocessing.peak_detection import find_peaks
nextra = 20;
delta = 0.3
kk = -k;
kk = np.hstack([kk[-nextra:], kk, kk[:nextra]]);
peaks = find_peaks(kk, delta = delta);

if peaks.shape[0] > 0:
  peaks[:,0] -= nextra;
  peaks = peaks[peaks[:,0] < k.shape[0],:];
  peaks = peaks[peaks[:,0] >= 0,:];

imax = np.sort(np.asarray(peaks[np.argsort(peaks[:,1])[-2:],0], dtype = int))

fig = plt.figure(4); plt.clf();
plt.plot(k, 'k')
plt.scatter(imax, k[imax], c = 'gray', s= 400);
plt.scatter(peaks[:,0], -peaks[:,1], c = 'red', s= 100);
fig.savefig('pipeline_curvature_peak.png', facecolor = 'white')

### side lines
예제 #6
0
            #mnpos = x[i]

        if lookformax:
            if this < mx - delta:
                maxid.append(mxpos)
                maxvalue.append(mx)
                mn = this
                #mnpos = x[i]
                lookformax = False
        else:
            if this > mn + delta:
                #mintab.append((mnpos, mn))
                mx = this
                mxpos = x[i]
                lookformax = True

    return np.asarray(maxid, dtype=int), np.asarray(maxvalue, dtype=v.dtype)


if __name__ == "__main__":
    import matplotlib.pyplot as plt
    import signalprocessing.peak_detection as pd
    reload(pd)
    series = [0, 0, 0, 2, 0, 0, 0, -2, 0, 0, 0, 2, 0, 0, 0, -2, 0]
    i, v = pd.find_peaks(series, .3)

    plt.figure(1)
    plt.clf()
    plt.plot(series)
    plt.scatter(i, v, color='blue', s=50)
    plt.draw()
예제 #7
0
plt.subplot(1, 3, 2)
plt.imshow(img, cmap='gray', interpolation='nearest')
plt.plot(x, y, 'b--')
plt.scatter(x, y, s=1)
plt.show()

# curvature along the points
dx, dy = splev(us[:-1], cinterp, der=1)
d2x, d2y = splev(us[:-1], cinterp, der=2)
k = (dx * d2y - dy * d2x) / np.power(dx**2 + dy**2, 1.5)

# find tail and head via peak detection

from signalprocessing.peak_detection import find_peaks

peaks = find_peaks(np.abs(k), delta=0.15)

imax = np.sort(np.asarray(peaks[np.argsort(peaks[:, 1])[-2:], 0], dtype=int))

print 'max k at %s' % str(imax)

plt.scatter(x[imax], y[imax], s=150, color='r')

plt.subplot(1, 3, 3)
plt.plot(np.abs(k))

# calcualte paths along both sides

nsteps = 50

u1 = np.linspace(us[imax[0]], us[imax[1]], nsteps)
def analyse_shape(img, sigma = 1, threshold_level = 0.95, npts_contour = 100, npts_sides = 21, smooth = 1.0, verbose = False, save = None):
  """Detect and ,measure shape features"""
  
  ### smooth image
  imgs = filters.gaussian_filter(np.asarray(img, float), sigma);
   
  ### get contours
  level = threshold_level * threshold_otsu(imgs);
  pts = detect_contour(imgs, level);
  
  if len(pts) == 0 or len(pts) > 2:
    raise RuntimeError('found %d contours, expected 1 or 2!' % len(pts));
    #return np.zeros(2), np.zeros(2), np.zeros(2), 0, 0, np.zeros((2, npts_sides)), np.zeros((2, npts_sides)), np.zeros((2, npts_sides))
    
  if len(pts) == 1:
    pts, pts_inner = pts[0], None;
  
  else: #len(pts) == 2
    if pts[0].shape[0] < pts[1].shape[0]:
      i,o = 0,1;
    else:
      i,o = 1,0;
    
    if inside_polygon(pts[i], pts[o][0,:]):
      i,o = o,i;
    
    pts, pts_inner = pts[o], pts[i];
  
  ### interpolate outer contour
  cinterp, u = splprep(pts.T, u = None, s = smooth, per = 1) 
  us = np.linspace(u.min(), u.max(), npts_contour)
  x, y = splev(us[:-1], cinterp, der = 0)

  ### curvature along the points
  dx, dy = splev(us[:-1], cinterp, der = 1)
  d2x, d2y = splev(us[:-1], cinterp, der = 2)
  k = (dx * d2y - dy * d2x)/np.power(dx**2 + dy**2, 1.5);


  ### find tail and head via peak detection

  #pad k to detect peaks on both sides
  nextra = 20;
  kk = -k; # negative curvature peaks are heads/tails
  kk = np.hstack([kk,kk[:nextra]]);
  peaks = find_peaks(kk, delta = 0.3);
  peaks = peaks[peaks[:,0] < k.shape[0],:];
  
  #plt.figure(15); plt.clf();
  #plt.plot(kk);
  #plt.scatter(peaks[:,0], peaks[:,1], c = 'r');

  
  #if peaks.shape[0] < 2:
  #  peaks = find_peaks(np.abs(k), delta = 0.05);
  print peaks.shape  
  if peaks.shape[0] < 2:
    if peaks.shape[0] == 1:
      # best guess is half way along the contour
      imax = np.sort(np.asarray(np.mod(peaks[0,0] + np.array([0,npts_contour/2]), npts_contour), dtype = int));
    else:
      imax = np.array([0,50]);
  else:
    imax = np.sort(np.asarray(peaks[np.argsort(peaks[:,1])[-2:],0], dtype = int))
  
  print imax
  
  # calcualte paths along both sides
  
  u1 = np.linspace(us[imax[0]], us[imax[1]], npts_sides)
  x1, y1 =  splev(u1, cinterp, der = 0);
  
  u2 = np.linspace(us[imax[0]], us[imax[1]]-1, npts_sides);
  u2 = np.mod(u2,1);
  x2, y2 = splev(u2, cinterp, der = 0);
  
  # midline (simple)
  #xm = (x1 + x2) / 2; ym = (y1 + y2) / 2;
  xm,ym,nu = find_midline(x1,y1,x2,y2, offset = 3);
  xym = np.vstack([xm,ym]);
  xymintp, u = splprep(xym, u = None, s = 1.0, per = 0);
  
  # worm center
  xc, yc = splev([0.5], xymintp, der = 0)
  xc = xc[0]; yc = yc[0];

  if verbose:
    print 'max k at %s' % str(imax)
    
    plt.figure(11); plt.clf();
    plt.subplot(2,3,1)
    plt.imshow(img, interpolation ='nearest')
    plt.subplot(2,3,2)
    plt.imshow(imgs)
    plt.subplot(2,3,3)
    plt.imshow(img, cmap = 'gray')
    plt.contour(imgs, levels = [threshold_level * threshold_otsu(imgs)])
    #plt.imshow(img, cmap = 'gray', interpolation = 'nearest')
    #plt.scatter(pts[:,0], pts[:,1])
    #plt.plot(x, y, 'b--')


    #plot curvature
    plt.subplot(2,3,4)
    plt.plot(k)
    plt.scatter(imax, k[imax], c = 'r', s= 100);
    plt.scatter(peaks[:,0], -peaks[:,1], c = 'm', s= 40);

    
    # shape detection
    plt.subplot(2,3,5)
    plt.imshow(img, cmap = 'gray', interpolation = 'nearest')
    
    #plot lines and midline
    plt.plot(x1,y1, 'g', linewidth= 4)
    plt.plot(x2,y2, 'y', linewidth= 4)
    plt.plot(xm,ym,'b')

    # plot segments
    for i in range(len(xm)):
        plt.plot([x1[i], x2[nu[i]]], [y1[i], y2[nu[i]]], 'm')

    #plot center
    plt.scatter(xc, yc, color = 'k')
    plt.scatter(x[imax], y[imax], s=150, color='r')
    
    
    #plot width profile    
    plt.subplot(2,3,6)
    
    w = np.zeros(len(xm));
    for i in range(len(xm)):
      w[i] = np.linalg.norm([x2[nu[i]]-x1[i], y2[nu[i]]- y1[i]]);
    plt.plot(w);
    
    if isinstance(save, basestring):
      fig = plt.figure(11);
      fig.savefig(save);


  ### measure features
  
  # points
  pos_head = np.array([x1[0], y1[0]])
  pos_tail = np.array([x1[-1], y1[-1]])
  pos_center = np.array([xc, yc]);
  
  # head tail distance:
  #dist_head_tail = np.linalg.norm(pos_head-pos_tail)
  #dist_head_center = np.linalg.norm(pos_head-pos_center)
  #dist_tail_center = np.linalg.norm(pos_tail-pos_center)
  
  #average curvature
  dcx, dcy = splev(u, xymintp, der = 1)
  d2cx, d2cy = splev(u, xymintp, der = 2)
  ck = (dcx * d2cy - dcy * d2cx)/np.power(dcx**2 + dcy**2, 1.5);
  curvature_mean = np.mean(ck);
  curvature_variation = np.sum(np.abs(ck))
  
  #cruves
  line_center = xym.T;
  line_left = np.vstack([x1, y1]).T;
  line_right = np.vstack([x2, y2]).T;
  
  return pos_center, pos_head, pos_tail, curvature_mean, curvature_variation, line_center, line_left, line_right
def shape_from_image(image, sigma = 1, absolute_threshold = None, threshold_factor = 0.95, 
                     ncontour = 100, delta = 0.3, smooth_head_tail = 1.0, smooth_left_right = 1.0, smooth_center = 10,
                     npoints = 21, center_offset = 3, 
                     threshold_reduce = 0.9, contour_hint = None, size_hint = None, min_size = 20, 
                     delta_reduce = 0.5, head_tail_hint = None,
                     verbose = False, save = None):
  """Detect non self intersecting shapes of the the worm
  
  Arguments:
    image (array): the image to detect worm from
    sigma (float or None): width of Gaussian smoothing on image, if None use raw image
    absolute_threshold (float or None): if set use this as the threshold, if None the threshold is set via Otsu
    threshold_level (float): in case the threshold is determined by Otsu multiply by this factor
    ncontour (int): number of vertices in the contour
    delta (float): min height of peak in curvature to detect the head
    smooth (float): smoothing to use for the countour 
    nneighbours (int): number of neighbours to consider for midline detection
    npoints (int): number of vertices in the final center and side lines of the worm
    nsamples (int): number of vertices for center line detection
    verbose (bool): plot results
    save (str or None): save result plot to this file
  
  Returns:
    status (bool): 0 the shape was successfully extracted, otherwise id of what method was used or which failure
    arrays (npointsx2): center, left, right side lines of the worm
    
  Note:
    This is a fast way to detect the worm shape, fails for worms intersecting themselves
  """
  
  ### smooth image
  if sigma is not None:
    imgs = cv2.GaussianBlur(np.asarray(image, dtype = float), ksize = (sigma, sigma), sigmaX = 0);
  else:
    imgs = image;
   
  ### get contours
  if absolute_threshold is not None:
    level = absolute_threshold;
  else:
    level = threshold_factor * threshold_otsu(imgs);
  
  pts, hrchy = detect_contour(imgs, level, with_hierarchy = True);
  if verbose:
    print("Found %d countours!" % len(pts));
    plt.subplot(2,3,3)
    plt.imshow(imgs, cmap = 'gray')
    for p in pts:
      plt.plot(p[:,0], p[:,1], c = 'red');
    
    plt.contour(imgs, levels = [level])
    plt.title('contour dectection')       
  
  status = 0;   
  if len(pts) == 0:
    if threshold_reduce is not None:
      pts, hrchy = detect_contour(imgs, threshold_reduce * level, with_hierarchy = True);
      status += 10000; # indicate we reduced the threshold !
    
    if len(pts) == 0: # we cannot find the worm and give up...      
      return -1-status, np.zeros((npoints,2)), np.zeros((npoints,2), np.zeros((npoints,2)), np.zeros(npoints))

  
  if len(pts) == 1:
    pts = pts[0];
    status += 1; # one contour only
  
  else:   # length is  >= 2
    # remove all contours that are children of others

    outer = np.where( np.logical_not(np.any(hrchy, axis = 0)) )[0];
    areas = np.array([cv2.contourArea(pts[o]) for o in outer]);
    outer = outer[areas > 0];
    #print outer
    
    if len(outer) == 0: # we cannot find the worm and give up...      
      return -2-status, np.zeros((npoints,2)), np.zeros((npoints,2), np.zeros((npoints,2)), np.zeros(npoints))
    
    elif len(outer) == 1:
      pts = pts[outer[0]]; # only one outer contour (worm mostlikely curled)
      status += 2;
      status += 10; # indicate there is an inner contour
      
    else:
      # is there contour with similar centroid and size to previous one
      moments = [cv2.moments(pts[o]) for o in outer];
      centroids = np.array([[(m["m10"] / m["m00"]), (m["m01"] / m["m00"])] for m in moments]);
      
      if contour_hint is not None:
        dist = [cv2.matchShapes(pts[o], contour_hint, 2,0) for o in outer];
        imin = np.argmin(dist);
        pts = pts[outer[imin]]; 
        status += 3;
        
      elif size_hint is not None:
        dist = np.array([cv2.contourArea(pts[o]) for o in outer]);
        dist = np.abs(dist - size_hint);
        imin = np.argmin(dist);
        status += 4;
        pts = pts[outer[imin]]; 
      
      
      else:
        #take most central one
        dist = np.linalg.norm(centroids - np.array(image.shape)/2, axis = 1);
        area = np.array([cv2.contourArea(pts[o]) for o in outer]);
        
        iarea = np.where(area > min_size)[0];
        dmin = np.argmin(dist[iarea]);
        imin = iarea[dmin]
        
        status += 5;
        pts = pts[outer[imin]];
        
      #check if contour has children
      #if np.sum(hrchy[:,-1] == outer[imin]) > 0:
      if hrchy[outer[imin]].sum() > 0:
        status += 10;
        
  #print status, len(pts)
  
  ### interpolate outer contour
  nextra = min(len(pts)-1, 20); # pts[0]==pts[-1] !!
  #print pts[0], pts[-1]
  #ptsa = np.vstack([pts[-nextra:], pts, pts[:nextra]]);
  #cinterp, u = splprep(ptsa.T, u = None, s = smooth_head_tail, per = 0, k = 4) 
  #print pts
  cinterp, u = splprep(pts.T, u = None, s = smooth_head_tail, per = 1, k = 5) 
  #u0 = u[nextra]; u1 = u[-nextra-1];
  u0 = 0; u1 = 1;
  #print splev([0,1], cinterp, der = 2);
  #return
  
  us = np.linspace(u0, u1, ncontour+1)[:-1];
  x, y = splev(us, cinterp, der = 0)
  dx, dy = splev(us, cinterp, der = 1)
  d2x, d2y = splev(us, cinterp, der = 2)
  k = (dx * d2y - dy * d2x)/np.power(dx**2 + dy**2, 1.5);
  kk = np.hstack([k[-nextra:], k, k[:nextra]]);
  
  #plt.figure(5); plt.clf();
  #plt.plot(x,y);
  #plt.figure(19);
  
  peak_ids, peak_values = find_peaks(kk, delta = delta);
  
  if len(peak_ids) > 0:
    peak_ids -= nextra;
    peak_values = peak_values[peak_ids>= 0]; peak_ids = peak_ids[peak_ids>= 0];  
    peak_values = peak_values[peak_ids < ncontour]; peak_ids = peak_ids[peak_ids < ncontour]; 
  
  if len(peak_ids) < 2 and delta_reduce is not None:
    peak_ids, peak_values = find_peaks(kk, delta = delta * delta_reduce);
    status += 1000; # indicated we reduced peak strength

    if len(peak_ids) > 0:
      peak_ids -= nextra;
      peak_values = peak_values[peak_ids>= 0]; peak_ids = peak_ids[peak_ids>= 0];  
      peak_values = peak_values[peak_ids < ncontour]; peak_ids = peak_ids[peak_ids < ncontour]; 

  if verbose:
    print('Found %d peaks' % len(peak_ids));

  # find head and tail
  if len(peak_ids) >= 2:
    if head_tail_hint is not None:
      xy = np.array([x[peak_ids], y[peak_ids]]).T;
      dist_h = np.linalg.norm(xy - head_tail_hint[0], axis = 1);
      dist_t = np.linalg.norm(xy - head_tail_hint[1], axis = 1);
      
      i_h = np.argmin(dist_h);
      i_t = np.argmin(dist_t);      
      if i_h == i_t:
        dist_t[i_t] = np.inf;
        i_t = np.argmin(dist_t);        
      
      imax = [peak_ids[i_h], peak_ids[i_t]];   
      status += 100;
      
    else:
      # best guess are the two highest ones
      imax = np.sort(np.asarray(peak_ids[np.argsort(peak_values)[-2:]], dtype = int))
      status += 200;
  
  elif len(peak_ids) == 1:
    if head_tail_hint is not None:
      xy = np.array([x[peak_ids[0]], y[peak_ids[0]]]).T;
      dist_h = np.linalg.norm(xy - head_tail_hint[0], axis = 1);
      dist_t = np.linalg.norm(xy - head_tail_hint[1], axis = 1);
      
      #closest point on contour to previous missing head/tail:
      xy = np.array([x, y]).T;   
      if dist_h <= dist_t:
        dist = np.linalg.norm(xy - head_tail_hint[1], axis = 1);          
        i_h = peak_ids[0]; 
        i_t = np.argmin(dist);
        if i_h == i_t:
          dist[i_t] = np.inf;
          i_t = np.argmin(dist);        
        imax = [i_h, i_t];  
      else:
        dist = np.linalg.norm(xy - head_tail_hint[0], axis = 1);
        i_t = peak_ids[0]; 
        i_h = np.argmin(dist);
        if i_h == i_t:
          dist[i_h] = np.inf;
          i_h = np.argmin(dist);        
        imax = [i_h, i_t];  
      status += 300;
  
    else:
      # best guess is half way along the contour
      imax = np.sort(np.asarray(np.mod(peak_ids[0] + np.array([0,ncontour//2]), ncontour), dtype = int));
      status += 400
  
  else: #peaks.shape[0] == 0
    if head_tail_hint is not None:
      xy = np.array([x, y]).T;      
      dist_h = np.linalg.norm(xy - head_tail_hint[0], axis = 1);
      dist_t = np.linalg.norm(xy - head_tail_hint[1], axis = 1);
      i_h = np.argmin(dist_h);
      i_t = np.argmin(dist_t);
      if i_h == i_t:
        dist_t[i_t] = np.inf;
        i_t = np.argmin(dist_t);        
      imax = [i_h, i_t];  
      status += 500;
    else:
      imax = np.asarray(np.round([0, ncontour//2]), dtype = int);
      status += 600;
  #print imax, status
  
  
  ### calcualte sides and midline
  if smooth_left_right is not None and smooth_head_tail != smooth_left_right:
    #cinterp, u = splprep(ptsa.T, u = None, s = smooth_left_right, per = 0, k = 4) 
    cinterp, u = splprep(pts.T, u = None, s = smooth_left_right, per = 1, k = 5) 
    #u0 = u[nextra]; u1 = u[-nextra-1];
    #us = np.linspace(u0, u1, ncontour);
  
  
  du = u1-u0;
  if imax[0] > imax[1]:
    ul = np.linspace(us[imax[0]], us[imax[1]]+du, ncontour);
    ul[ul >= u1] -= du;
  else:
    ul = np.linspace(us[imax[0]], us[imax[1]], ncontour);
  x1, y1 =  splev(ul, cinterp, der = 0);
  left = np.vstack([x1,y1]).T;
  
  if imax[0] > imax[1]:
    ur = np.linspace(us[imax[1]], us[imax[0]], ncontour);
  else:
    ur = np.linspace(us[imax[0]], us[imax[1]]-du, ncontour);
    ur[ur < u0] += du;
  x2, y2 = splev(ur, cinterp, der = 0);
  right = np.vstack([x2,y2]).T;
  
  #print u0,u1,ul,ur
  #print left[[0,-1]];
  #print right[[0,-1]];
  #return
  # center and midline 
  center, width = center_from_sides_min_projection(left, right, npoints = npoints, nsamples = ncontour, with_width = True, smooth = smooth_center, center_offset = center_offset);
  
  ### plotting
  if verbose:
    #print 'max k at %s' % str(imax)
    #plt.figure(11); plt.clf();
    plt.subplot(2,3,1)
    plt.imshow(image, interpolation ='none')
    plt.title('raw image');
    plt.subplot(2,3,2)
    plt.imshow(imgs, interpolation ='none')
    plt.title('smoothed image');
    plt.subplot(2,3,3)
    plt.imshow(imgs, cmap = 'gray', interpolation ='none')
    plt.contour(imgs, levels = [level])
    plt.title('contour dectection')
    
    #plot curvature
    plt.subplot(2,3,4)
    plt.plot(k)
    plt.scatter(imax, k[imax], c = 'r', s= 100);
    if len(peak_ids) > 0:
      plt.scatter(peak_ids, peak_values, c = 'm', s= 40);
    plt.title('curvature')
    
    # shape detection
    plt.subplot(2,3,5)
    plt.imshow(image, cmap = 'gray', interpolation = 'none')
    
    left1, right1 = wgeo.shape_from_center_discrete(center, width);
    plt.plot(left1[:,0]  , left1[:,1]  , 'r', linewidth= 2)
    plt.plot(right1[:,0] , right1[:,1] , 'r', linewidth= 2)    
    
    
    plt.plot(left[:,0]  , left[:,1]  , 'g', linewidth= 1)
    plt.plot(right[:,0] , right[:,1] , 'y', linewidth= 1)
    plt.plot(center[:,0], center[:,1], 'b')
    
    if smooth_left_right is not None and smooth_head_tail != smooth_left_right:
      #  x, y = splev(us, cinterp, der = 0);
      plt.plot(x,y, 'm', linewidth = 1);
    
    
    # plot segments
    #for i in range(len(xm)):
    #    plt.plot([x1[i], x2[nu[i]]], [y1[i], y2[nu[i]]], 'm')
    #plot center
    n2 = (npoints-1)//2;
    plt.scatter(center[n2,0], center[n2,1], color = 'k', s = 150)
    #plt.scatter(x[imax], y[imax], s=150, color='r');
    plt.contour(imgs, levels = [level])
    plt.title('shape detection')
    
    #plot width profile    
    plt.subplot(2,3,6)
    plt.plot(width);
    plt.title('width')
    
    if isinstance(save, basestring):
      fig = plt.gcf();
      fig.savefig(save);
  
  ### measure features
  # points
  #pos_head = np.array([x1[0], y1[0]])
  #pos_tail = np.array([x1[-1], y1[-1]])
  #pos_center = np.array([xc, yc]);
  
  # head tail distance:
  #dist_head_tail = np.linalg.norm(pos_head-pos_tail)
  #dist_head_center = np.linalg.norm(pos_head-pos_center)
  #dist_tail_center = np.linalg.norm(pos_tail-pos_center)
  
  #average curvature
  #dcx, dcy = splev(u, xymintp, der = 1)
  #d2cx, d2cy = splev(u, xymintp, der = 2)
  #ck = (dcx * d2cy - dcy * d2cx)/np.power(dcx**2 + dcy**2, 1.5);
  #curvature_mean = np.mean(ck);
  #curvature_variation = np.sum(np.abs(ck))
  
  ### returns
  #success = pts_inner is None;
  return status, left, right, center, width
예제 #10
0
def shape_from_image(image,
                     sigma=1,
                     absolute_threshold=None,
                     threshold_factor=0.95,
                     ncontour=100,
                     delta=0.3,
                     smooth_head_tail=1.0,
                     smooth_left_right=1.0,
                     smooth_center=10,
                     npoints=21,
                     center_offset=3,
                     threshold_reduce=0.9,
                     contour_hint=None,
                     size_hint=None,
                     min_size=20,
                     delta_reduce=0.5,
                     head_tail_hint=None,
                     verbose=False,
                     save=None):
    """Detect non self intersecting shapes of the the worm
  
  Arguments:
    image (array): the image to detect worm from
    sigma (float or None): width of Gaussian smoothing on image, if None use raw image
    absolute_threshold (float or None): if set use this as the threshold, if None the threshold is set via Otsu
    threshold_level (float): in case the threshold is determined by Otsu multiply by this factor
    ncontour (int): number of vertices in the contour
    delta (float): min height of peak in curvature to detect the head
    smooth (float): smoothing to use for the countour 
    nneighbours (int): number of neighbours to consider for midline detection
    npoints (int): number of vertices in the final center and side lines of the worm
    nsamples (int): number of vertices for center line detection
    verbose (bool): plot results
    save (str or None): save result plot to this file
  
  Returns:
    status (bool): 0 the shape was successfully extracted, otherwise id of what method was used or which failure
    arrays (npointsx2): center, left, right side lines of the worm
    
  Note:
    This is a fast way to detect the worm shape, fails for worms intersecting themselves
  """

    ### smooth image
    if sigma is not None:
        imgs = cv2.GaussianBlur(np.asarray(image, dtype=float),
                                ksize=(sigma, sigma),
                                sigmaX=0)
    else:
        imgs = image

    ### get contours
    if absolute_threshold is not None:
        level = absolute_threshold
    else:
        level = threshold_factor * threshold_otsu(imgs)

    pts, hrchy = detect_contour(imgs, level, with_hierarchy=True)
    if verbose:
        print("Found %d countours!" % len(pts))
        plt.subplot(2, 3, 3)
        plt.imshow(imgs, cmap='gray')
        for p in pts:
            plt.plot(p[:, 0], p[:, 1], c='red')

        plt.contour(imgs, levels=[level])
        plt.title('contour dectection')

    status = 0
    if len(pts) == 0:
        if threshold_reduce is not None:
            pts, hrchy = detect_contour(imgs,
                                        threshold_reduce * level,
                                        with_hierarchy=True)
            status += 10000
            # indicate we reduced the threshold !

        if len(pts) == 0:  # we cannot find the worm and give up...
            return -1 - status, np.zeros((npoints, 2)), np.zeros(
                (npoints, 2), np.zeros((npoints, 2)), np.zeros(npoints))

    if len(pts) == 1:
        pts = pts[0]
        status += 1
        # one contour only

    else:  # length is  >= 2
        # remove all contours that are children of others

        outer = np.where(np.logical_not(np.any(hrchy, axis=0)))[0]
        areas = np.array([cv2.contourArea(pts[o]) for o in outer])
        outer = outer[areas > 0]
        #print outer

        if len(outer) == 0:  # we cannot find the worm and give up...
            return -2 - status, np.zeros((npoints, 2)), np.zeros(
                (npoints, 2), np.zeros((npoints, 2)), np.zeros(npoints))

        elif len(outer) == 1:
            pts = pts[outer[0]]
            # only one outer contour (worm mostlikely curled)
            status += 2
            status += 10
            # indicate there is an inner contour

        else:
            # is there contour with similar centroid and size to previous one
            moments = [cv2.moments(pts[o]) for o in outer]
            centroids = np.array([[(m["m10"] / m["m00"]),
                                   (m["m01"] / m["m00"])] for m in moments])

            if contour_hint is not None:
                dist = [
                    cv2.matchShapes(pts[o], contour_hint, 2, 0) for o in outer
                ]
                imin = np.argmin(dist)
                pts = pts[outer[imin]]
                status += 3

            elif size_hint is not None:
                dist = np.array([cv2.contourArea(pts[o]) for o in outer])
                dist = np.abs(dist - size_hint)
                imin = np.argmin(dist)
                status += 4
                pts = pts[outer[imin]]

            else:
                #take most central one
                dist = np.linalg.norm(centroids - np.array(image.shape) / 2,
                                      axis=1)
                area = np.array([cv2.contourArea(pts[o]) for o in outer])

                iarea = np.where(area > min_size)[0]
                dmin = np.argmin(dist[iarea])
                imin = iarea[dmin]

                status += 5
                pts = pts[outer[imin]]

            #check if contour has children
            #if np.sum(hrchy[:,-1] == outer[imin]) > 0:
            if hrchy[outer[imin]].sum() > 0:
                status += 10

    #print status, len(pts)

    ### interpolate outer contour
    nextra = min(len(pts) - 1, 20)
    # pts[0]==pts[-1] !!
    #print pts[0], pts[-1]
    #ptsa = np.vstack([pts[-nextra:], pts, pts[:nextra]]);
    #cinterp, u = splprep(ptsa.T, u = None, s = smooth_head_tail, per = 0, k = 4)
    #print pts
    cinterp, u = splprep(pts.T, u=None, s=smooth_head_tail, per=1, k=5)
    #u0 = u[nextra]; u1 = u[-nextra-1];
    u0 = 0
    u1 = 1
    #print splev([0,1], cinterp, der = 2);
    #return

    us = np.linspace(u0, u1, ncontour + 1)[:-1]
    x, y = splev(us, cinterp, der=0)
    dx, dy = splev(us, cinterp, der=1)
    d2x, d2y = splev(us, cinterp, der=2)
    k = (dx * d2y - dy * d2x) / np.power(dx**2 + dy**2, 1.5)
    kk = np.hstack([k[-nextra:], k, k[:nextra]])

    #plt.figure(5); plt.clf();
    #plt.plot(x,y);
    #plt.figure(19);

    peak_ids, peak_values = find_peaks(kk, delta=delta)

    if len(peak_ids) > 0:
        peak_ids -= nextra
        peak_values = peak_values[peak_ids >= 0]
        peak_ids = peak_ids[peak_ids >= 0]
        peak_values = peak_values[peak_ids < ncontour]
        peak_ids = peak_ids[peak_ids < ncontour]

    if len(peak_ids) < 2 and delta_reduce is not None:
        peak_ids, peak_values = find_peaks(kk, delta=delta * delta_reduce)
        status += 1000
        # indicated we reduced peak strength

        if len(peak_ids) > 0:
            peak_ids -= nextra
            peak_values = peak_values[peak_ids >= 0]
            peak_ids = peak_ids[peak_ids >= 0]
            peak_values = peak_values[peak_ids < ncontour]
            peak_ids = peak_ids[peak_ids < ncontour]

    if verbose:
        print('Found %d peaks' % len(peak_ids))

    # find head and tail
    if len(peak_ids) >= 2:
        if head_tail_hint is not None:
            xy = np.array([x[peak_ids], y[peak_ids]]).T
            dist_h = np.linalg.norm(xy - head_tail_hint[0], axis=1)
            dist_t = np.linalg.norm(xy - head_tail_hint[1], axis=1)

            i_h = np.argmin(dist_h)
            i_t = np.argmin(dist_t)
            if i_h == i_t:
                dist_t[i_t] = np.inf
                i_t = np.argmin(dist_t)

            imax = [peak_ids[i_h], peak_ids[i_t]]
            status += 100

        else:
            # best guess are the two highest ones
            imax = np.sort(
                np.asarray(peak_ids[np.argsort(peak_values)[-2:]], dtype=int))
            status += 200

    elif len(peak_ids) == 1:
        if head_tail_hint is not None:
            xy = np.array([x[peak_ids[0]], y[peak_ids[0]]]).T
            dist_h = np.linalg.norm(xy - head_tail_hint[0], axis=1)
            dist_t = np.linalg.norm(xy - head_tail_hint[1], axis=1)

            #closest point on contour to previous missing head/tail:
            xy = np.array([x, y]).T
            if dist_h <= dist_t:
                dist = np.linalg.norm(xy - head_tail_hint[1], axis=1)
                i_h = peak_ids[0]
                i_t = np.argmin(dist)
                if i_h == i_t:
                    dist[i_t] = np.inf
                    i_t = np.argmin(dist)
                imax = [i_h, i_t]
            else:
                dist = np.linalg.norm(xy - head_tail_hint[0], axis=1)
                i_t = peak_ids[0]
                i_h = np.argmin(dist)
                if i_h == i_t:
                    dist[i_h] = np.inf
                    i_h = np.argmin(dist)
                imax = [i_h, i_t]
            status += 300

        else:
            # best guess is half way along the contour
            imax = np.sort(
                np.asarray(np.mod(peak_ids[0] + np.array([0, ncontour // 2]),
                                  ncontour),
                           dtype=int))
            status += 400

    else:  #peaks.shape[0] == 0
        if head_tail_hint is not None:
            xy = np.array([x, y]).T
            dist_h = np.linalg.norm(xy - head_tail_hint[0], axis=1)
            dist_t = np.linalg.norm(xy - head_tail_hint[1], axis=1)
            i_h = np.argmin(dist_h)
            i_t = np.argmin(dist_t)
            if i_h == i_t:
                dist_t[i_t] = np.inf
                i_t = np.argmin(dist_t)
            imax = [i_h, i_t]
            status += 500
        else:
            imax = np.asarray(np.round([0, ncontour // 2]), dtype=int)
            status += 600
    #print imax, status

    ### calcualte sides and midline
    if smooth_left_right is not None and smooth_head_tail != smooth_left_right:
        #cinterp, u = splprep(ptsa.T, u = None, s = smooth_left_right, per = 0, k = 4)
        cinterp, u = splprep(pts.T, u=None, s=smooth_left_right, per=1, k=5)
        #u0 = u[nextra]; u1 = u[-nextra-1];
        #us = np.linspace(u0, u1, ncontour);

    du = u1 - u0
    if imax[0] > imax[1]:
        ul = np.linspace(us[imax[0]], us[imax[1]] + du, ncontour)
        ul[ul >= u1] -= du
    else:
        ul = np.linspace(us[imax[0]], us[imax[1]], ncontour)
    x1, y1 = splev(ul, cinterp, der=0)
    left = np.vstack([x1, y1]).T

    if imax[0] > imax[1]:
        ur = np.linspace(us[imax[1]], us[imax[0]], ncontour)
    else:
        ur = np.linspace(us[imax[0]], us[imax[1]] - du, ncontour)
        ur[ur < u0] += du
    x2, y2 = splev(ur, cinterp, der=0)
    right = np.vstack([x2, y2]).T

    #print u0,u1,ul,ur
    #print left[[0,-1]];
    #print right[[0,-1]];
    #return
    # center and midline
    center, width = center_from_sides_min_projection(
        left,
        right,
        npoints=npoints,
        nsamples=ncontour,
        with_width=True,
        smooth=smooth_center,
        center_offset=center_offset)

    ### plotting
    if verbose:
        #print 'max k at %s' % str(imax)
        #plt.figure(11); plt.clf();
        plt.subplot(2, 3, 1)
        plt.imshow(image, interpolation='none')
        plt.title('raw image')
        plt.subplot(2, 3, 2)
        plt.imshow(imgs, interpolation='none')
        plt.title('smoothed image')
        plt.subplot(2, 3, 3)
        plt.imshow(imgs, cmap='gray', interpolation='none')
        plt.contour(imgs, levels=[level])
        plt.title('contour dectection')

        #plot curvature
        plt.subplot(2, 3, 4)
        plt.plot(k)
        plt.scatter(imax, k[imax], c='r', s=100)
        if len(peak_ids) > 0:
            plt.scatter(peak_ids, peak_values, c='m', s=40)
        plt.title('curvature')

        # shape detection
        plt.subplot(2, 3, 5)
        plt.imshow(image, cmap='gray', interpolation='none')

        left1, right1 = wgeo.shape_from_center_discrete(center, width)
        plt.plot(left1[:, 0], left1[:, 1], 'r', linewidth=2)
        plt.plot(right1[:, 0], right1[:, 1], 'r', linewidth=2)

        plt.plot(left[:, 0], left[:, 1], 'g', linewidth=1)
        plt.plot(right[:, 0], right[:, 1], 'y', linewidth=1)
        plt.plot(center[:, 0], center[:, 1], 'b')

        if smooth_left_right is not None and smooth_head_tail != smooth_left_right:
            #  x, y = splev(us, cinterp, der = 0);
            plt.plot(x, y, 'm', linewidth=1)

        # plot segments
        #for i in range(len(xm)):
        #    plt.plot([x1[i], x2[nu[i]]], [y1[i], y2[nu[i]]], 'm')
        #plot center
        n2 = (npoints - 1) // 2
        plt.scatter(center[n2, 0], center[n2, 1], color='k', s=150)
        #plt.scatter(x[imax], y[imax], s=150, color='r');
        plt.contour(imgs, levels=[level])
        plt.title('shape detection')

        #plot width profile
        plt.subplot(2, 3, 6)
        plt.plot(width)
        plt.title('width')

        if isinstance(save, basestring):
            fig = plt.gcf()
            fig.savefig(save)

    ### measure features
    # points
    #pos_head = np.array([x1[0], y1[0]])
    #pos_tail = np.array([x1[-1], y1[-1]])
    #pos_center = np.array([xc, yc]);

    # head tail distance:
    #dist_head_tail = np.linalg.norm(pos_head-pos_tail)
    #dist_head_center = np.linalg.norm(pos_head-pos_center)
    #dist_tail_center = np.linalg.norm(pos_tail-pos_center)

    #average curvature
    #dcx, dcy = splev(u, xymintp, der = 1)
    #d2cx, d2cy = splev(u, xymintp, der = 2)
    #ck = (dcx * d2cy - dcy * d2cx)/np.power(dcx**2 + dcy**2, 1.5);
    #curvature_mean = np.mean(ck);
    #curvature_variation = np.sum(np.abs(ck))

    ### returns
    #success = pts_inner is None;
    return status, left, right, center, width
          mn = this
          #mnpos = x[i]
      
      if lookformax:
          if this < mx-delta:
              maxid.append(mxpos);
              maxvalue.append(mx);
              mn = this
              #mnpos = x[i]
              lookformax = False
      else:
          if this > mn+delta:
              #mintab.append((mnpos, mn))
              mx = this
              mxpos = x[i]
              lookformax = True


  return np.asarray(maxid, dtype = int), np.asarray(maxvalue, dtype = v.dtype);

if __name__=="__main__":
    import matplotlib.pyplot as plt
    import signalprocessing.peak_detection as pd;
    reload(pd);
    series = [0,0,0,2,0,0,0,-2,0,0,0,2,0,0,0,-2,0]
    i,v = pd.find_peaks(series,.3)
    
    plt.figure(1); plt.clf();
    plt.plot(series)
    plt.scatter(i, v, color='blue', s= 50)
    plt.draw()