#%% 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')
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
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
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
#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()
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
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()