├── cell_seq └── cell0000.png ├── README.md └── dlrse.py /cell_seq/cell0000.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/leonidk/drlse/HEAD/cell_seq/cell0000.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Requirements 2 | * Python 2.7 3 | * Scikit Image 0.11.x (for CHT and basic image processing (gaussian filter)) 4 | * Matplotlib (for I/O) 5 | * Numpy (for numerical applications) 6 | * Pillow (Python Imaging Library) (for saving) 7 | 8 | # Development Environment 9 | For my own use, I developed/tested on Windows, with the latest Anaconda Python distribution as of Dec 2, 2015. For some reason, there an issue with their version of matplotlib and I ran "conda update matplotlib" to update to the latest matplotlib and the error was resolved. 10 | 11 | # How to Run 12 | To run the example code, change into the directory of interest and run the dlrse.py script. 13 | 14 | For example 15 | $ cd cell_seq 16 | $ python ../dlrse.py 17 | will process all the cell images in the cell_seq directory. There should be both a real-time display of the processing and output images saved to the /out/ folder. 18 | -------------------------------------------------------------------------------- /dlrse.py: -------------------------------------------------------------------------------- 1 | from pylab import * 2 | from skimage import filters, io, color, morphology,exposure 3 | from skimage.transform import hough_circle 4 | from skimage.feature import peak_local_max, canny 5 | from skimage.draw import circle_perimeter, circle 6 | import scipy.ndimage as ndi 7 | from time import sleep 8 | import os, sys 9 | from PIL import Image 10 | 11 | def div(nx,ny): 12 | _,nxx = np.gradient(nx) 13 | nyy,_ = np.gradient(ny) 14 | return nxx + nyy 15 | 16 | def delta(x, sigma): 17 | f = (0.5/sigma)*(1.0+np.cos(pi*x/sigma)) 18 | b = (x<=sigma) & (x>=-sigma) 19 | return f*b 20 | 21 | def vNBounds(phi): 22 | phi[0,:] = phi[1,:] 23 | phi[-1,:] = phi[-2,:] 24 | phi[:,0] = phi[:,1] 25 | phi[:,-1] = phi[:,-2] 26 | 27 | def distReg_p1(phi,curv): 28 | return ndi.filters.laplace(phi)-curv 29 | 30 | def distReg_p2(phi,dx,dy,mag): 31 | #dy, dx = np.gradient(phi) 32 | #mag = np.sqrt(dx**2+dy**2) 33 | a = (mag >= 0.) & (mag <= 1.) 34 | b = (mag > 1.) 35 | ps = a*np.sin(2.0*np.pi*mag)/(2.0*np.pi) + b*(mag-1.0) 36 | dps=((ps != 0.)*ps + (ps == 0.) ) / ((mag != 0.)*mag + (mag == 0.)) 37 | return div(dps*dx - dx, dps*dy -dy) + ndi.filters.laplace(phi) 38 | 39 | 40 | def drlse_edge(phi, edge, lambdap,mu,alpha,epsilon,timestep,iter_inner): 41 | vy, vx = np.gradient(edge) 42 | for i2 in range(iter_inner): 43 | vNBounds(phi) #edges are duplicated for no flux in or out of image 44 | dy,dx = np.gradient(phi) 45 | mag = np.sqrt((dx**2)+(dy**2)) 46 | eps = 1e-6 47 | nx = dx/(mag+eps) 48 | ny = dy/(mag+eps) 49 | curv = div(nx,ny) 50 | 51 | #regTerm = distReg_p1(phi,curv) 52 | regTerm = distReg_p2(phi,dx,dy,mag) 53 | 54 | diracPhi = delta(phi,epsilon) 55 | #print nx.min(),nx.max(),curv.min(),curv.max(),regTerm.min(),regTerm.max(),diracPhi.min(),diracPhi.max() 56 | 57 | areaTerm = diracPhi * edge 58 | edgeTerm = diracPhi * (vx*nx+vy*ny) + diracPhi*edge*curv 59 | phi += timestep*(mu*regTerm + lambdap*edgeTerm + alpha*areaTerm) 60 | 61 | #params 62 | def dslre(img): 63 | timestep = 1.0 64 | mu = 0.2/timestep 65 | iter_basic = 1000 66 | iter_refine = 10 67 | lambdap = 5 68 | alpha = 1.5 # -3 69 | epsilon = 1.5 70 | sigma = 1.5 71 | 72 | smoothed = filters.gaussian_filter(img,sigma) 73 | dy,dx = np.gradient(smoothed) 74 | mag = (dx**2)+(dy**2) 75 | edge = 1.0/(1.0+mag) 76 | 77 | c0 = 2 78 | initialLSF = c0*np.ones(img.shape) 79 | initialLSF[10:50,10:50] = -c0 80 | 81 | #initialLSF[10:55,10:75] = -c0 82 | 83 | #initialLSF[25:35,20:25] -= c0 84 | #initialLSF[25:35,40:50] -= c0 85 | phi = initialLSF 86 | drlse_edge(phi,edge,lambdap,mu,alpha,epsilon,timestep,iter_basic) 87 | drlse_edge(phi,edge,lambdap,mu,0,epsilon,timestep,iter_refine) 88 | return phi 89 | if False: 90 | img = io.imread('../Cell_03.png') #twocells.bmp 91 | if len(img.shape) == 3: 92 | img = img[:,:,1] 93 | img = img.astype(np.float) 94 | phi = dslre(img) 95 | 96 | imshow(img) 97 | show() 98 | imshow(phi) 99 | show() 100 | seg, seg_n= ndi.label(phi < 0) 101 | print seg_n 102 | imshow(seg) 103 | show() 104 | else: 105 | timestep = 1.0 106 | mu = 0.2/timestep 107 | iter_basic = 1000 108 | iter_refine = 0 109 | lambdap = 5 110 | alpha = -0.8#-3 #1.5 # -3 111 | epsilon = 1.5 112 | sigma = 1.2 113 | c0 = 2 114 | elem = morphology.disk(3) #was 3 for savved data 115 | iml = None 116 | imgs = [] 117 | for idx,fn in enumerate(sorted(os.listdir('.'))): 118 | img = io.imread(fn) 119 | if len(img.shape) == 3: 120 | img = img[:,:,1] #(0.5*img[:,:,1] + 0.25*img[:,:,0] + 0.25*img[:,:,2]) 121 | img = img.astype(np.float) 122 | imgs.append(img) 123 | meanImg = np.mean( np.array(imgs), axis=0 ) 124 | stdImg = np.std( np.array(imgs),axis=0) 125 | tracked_size = [] 126 | for idx,fn in enumerate(sorted(os.listdir('.'))): 127 | img = io.imread(fn) 128 | orig_img = img.copy() 129 | if len(img.shape) == 3: 130 | img = img[:,:,1] 131 | #img = (0.5*img[:,:,1] + 0.25*img[:,:,0] + 0.25*img[:,:,2]) 132 | img = img.astype(np.float) 133 | 134 | #imr = (img-img.min())/(img.max()-img.min()) 135 | #img = 255*exposure.equalize_adapthist(imr, clip_limit=0.01) 136 | img = (img-0.5*meanImg)+0.5*meanImg.mean() 137 | if idx ==0:#True or idx == 0: 138 | initialLSF = c0*np.ones(img.shape) 139 | if False: 140 | initialLSF[10:50,10:50] = -c0 #cell 3 141 | #initialLSF[40:120,40:120] = -c0 #cell 8 142 | 143 | #initialLSF[10:-10,10:-10] = -c0 144 | else: 145 | edges = canny(img, sigma=3, low_threshold=10, high_threshold=50) 146 | #img = edges 147 | hough_radii = np.arange(20, 30, 3) 148 | hough_res = hough_circle(edges, hough_radii) 149 | 150 | centers = [] 151 | accums = [] 152 | radii = [] 153 | 154 | for radius, h in zip(hough_radii, hough_res): 155 | # For each radius, extract two circles 156 | num_peaks = 1 157 | peaks = peak_local_max(h, num_peaks=num_peaks) 158 | centers.extend(peaks) 159 | accums.extend(h[peaks[:, 0], peaks[:, 1]]) 160 | radii.extend([radius] * num_peaks) 161 | for idx in np.argsort(accums)[::-1]: 162 | try: 163 | center_x, center_y = centers[idx] 164 | radius = radii[idx] 165 | cx, cy = circle(center_y, center_x, radius) 166 | initialLSF[cy, cx] = -c0 167 | except: 168 | pass 169 | #initialLSF = morphology.erosion(initialLSF,elem) 170 | initialLSF = morphology.dilation(initialLSF,elem) 171 | 172 | 173 | phi = initialLSF 174 | smoothed = filters.gaussian_filter(img,sigma) 175 | dy,dx = np.gradient(smoothed) 176 | mag = (dx**2)+(dy**2) 177 | edge = 1.0/(1.0+mag) 178 | 179 | drlse_edge(phi,edge,lambdap,mu,alpha,epsilon,timestep,iter_basic) 180 | drlse_edge(phi,edge,lambdap,mu,0,epsilon,timestep,iter_refine) 181 | 182 | if iml is None: 183 | iml = imshow(phi) 184 | else: 185 | iml.set_data(phi) 186 | #pause(0.01) 187 | draw() 188 | orig_img[:,:,0] = uint8(200*(phi < 0)) 189 | #orig_img[:,:,1] += uint8(255*(phi < 0)) 190 | #orig_img[:,:,2] += uint8(255*(phi < 0)) 191 | tracked_size.append(len(phi[phi < 0])) 192 | pili = Image.fromarray(orig_img) 193 | pili.save('../out/' + fn) 194 | print fn 195 | #imshow(phi) 196 | #show() 197 | #phi = morphology.erosion(phi,elem) 198 | #phi = morphology.dilation(phi,elem) 199 | 200 | phi[0,:] = c0 201 | phi[-1,:] = c0 202 | phi[:,0] = c0 203 | phi[:,-1] = c0 204 | 205 | hough_trim = True 206 | if hough_trim: 207 | initialLSF = c0*np.ones(img.shape) 208 | edges = canny(phi) 209 | #edges = canny(img, sigma=3, low_threshold=10, high_threshold=50) 210 | #img = edges 211 | hough_radii = np.arange(20, 30, 3) 212 | hough_res = hough_circle(edges, hough_radii) 213 | 214 | centers = [] 215 | accums = [] 216 | radii = [] 217 | 218 | for radius, h in zip(hough_radii, hough_res): 219 | # For each radius, extract two circles 220 | num_peaks = 1 221 | peaks = peak_local_max(h, num_peaks=num_peaks) 222 | centers.extend(peaks) 223 | accums.extend(h[peaks[:, 0], peaks[:, 1]]) 224 | radii.extend([radius] * num_peaks) 225 | for idx in np.argsort(accums)[::-1]: 226 | try: 227 | center_x, center_y = centers[idx] 228 | radius = radii[idx] 229 | cx, cy = circle(center_y, center_x, radius+3) 230 | initialLSF[cy, cx] = -c0 231 | except: 232 | pass 233 | phi = np.maximum(phi,initialLSF) 234 | 235 | plt.style.use('ggplot') 236 | plot(tracked_size) 237 | xlabel('Frame Number') 238 | ylabel('Number of Pixels') 239 | title('Consistency of tracked result') 240 | savefig('res.png') --------------------------------------------------------------------------------