Révision 1
bin/image2geometry/measure_sepals.py (revision 1) | ||
---|---|---|
1 |
#!/usr/bin/env python |
|
2 |
|
|
3 |
# Usage: |
|
4 |
# ------ |
|
5 |
# measure_sepals.py directory filetype |
|
6 |
# filetype = '.tif' or '.inr.gz' |
|
7 |
|
|
8 |
from sys import path, argv |
|
9 |
import os |
|
10 |
import numpy as np |
|
11 |
from multiprocessing import Pool |
|
12 |
nproc = 11 # number of processors |
|
13 |
|
|
14 |
indir=argv[1] |
|
15 |
filetype=argv[2] |
|
16 |
|
|
17 |
outdir=indir+'measures' |
|
18 |
|
|
19 |
os.system("mkdir "+outdir) |
|
20 |
|
|
21 |
def one_simulation(param): |
|
22 |
if filetype in param: |
|
23 |
filename=param |
|
24 |
os.system("measure_sepal.py "+filename+" "+outdir) |
|
25 |
return |
|
26 |
|
|
27 |
list_params=[indir+'/'+filename for filename in os.listdir(indir)] |
|
28 |
|
|
29 |
pool = Pool(processes=nproc) |
|
30 |
pool.map(one_simulation, list_params) |
|
31 |
pool.close() |
|
32 |
pool.join() |
|
33 |
|
|
0 | 34 |
bin/image2geometry/orient_sepals.sh (revision 1) | ||
---|---|---|
1 |
#! /bin/bash |
|
2 |
|
|
3 |
# Usage: |
|
4 |
# ------ |
|
5 |
# ./orient_sepals.sh directory filetype |
|
6 |
# filetype = '.tif' or '.inr.gz' |
|
7 |
|
|
8 |
|
|
9 |
indir=$1 |
|
10 |
filetype=$2 |
|
11 |
|
|
12 |
outdir=$indir'_oriented' |
|
13 |
|
|
14 |
|
|
15 |
cd $indir |
|
16 |
|
|
17 |
logfile='orient_sepals-'$indir'.log' |
|
18 |
date > $logfile |
|
19 |
echo '--------------------------' >> $logfile |
|
20 |
|
|
21 |
|
|
22 |
for file in *$filetype |
|
23 |
do |
|
24 |
echo '--------------------------' >> $logfile |
|
25 |
echo $file >> $logfile |
|
26 |
echo $file $outdir |
|
27 |
echo '--------------------------' >> $logfile |
|
28 |
orient_sepal.py $file $outdir |
|
29 |
echo '--------------------------' >> $logfile |
|
30 |
done |
|
31 |
|
|
32 |
|
|
33 |
oriented='oriented-sepals' |
|
34 |
mkdir $oriented |
|
35 |
scp */*_oriented.inr.gz $oriented |
|
36 |
|
|
37 |
cd .. |
|
0 | 38 |
bin/image2geometry/bib_sepals.py (revision 1) | ||
---|---|---|
1 |
import numpy as np |
|
2 |
import matplotlib.pyplot as plt |
|
3 |
import math |
|
4 |
from scipy import optimize |
|
5 |
|
|
6 |
from titk_tools.io import imread, imsave, SpatialImage |
|
7 |
|
|
8 |
def center_on_point(img, cm): |
|
9 |
''' |
|
10 |
Centers the image img on the point cm |
|
11 |
''' |
|
12 |
x = np.array(np.where(img > 0) ) |
|
13 |
xp=np.zeros_like(x) |
|
14 |
img1=np.zeros_like(img) |
|
15 |
s=img.shape |
|
16 |
center_img=np.array(s)/2 |
|
17 |
for i in [0, 1, 2]: |
|
18 |
xp[i]=x[i]+center_img[i]-cm[i] |
|
19 |
for i in range(0, len(x[0])): |
|
20 |
if ((xp[0][i]>=0) and (xp[0][i]<s[0]) and (xp[1][i]>=0) and (xp[1][i]<s[1]) and (xp[2][i]>=0) and (xp[2][i]<s[2])): |
|
21 |
img1[xp[0][i],xp[1][i],xp[2][i]]=img[x[0][i],x[1][i],x[2][i]] |
|
22 |
img1=SpatialImage(img1) |
|
23 |
img1.resolution=img.resolution |
|
24 |
return img1 |
|
25 |
|
|
26 |
|
|
27 |
def center_on_cm(img): |
|
28 |
''' |
|
29 |
Centers the image img on the point cm |
|
30 |
''' |
|
31 |
s=img.shape |
|
32 |
res=img.voxelsize |
|
33 |
x = np.array(np.where(img > 0) ) |
|
34 |
cm = np.array([np.mean(x[i]) for i in [0,1,2]]) |
|
35 |
xp=np.zeros_like(x) |
|
36 |
img1=np.zeros_like(img) |
|
37 |
center_img=np.array(s)/2 |
|
38 |
for i in [0, 1, 2]: |
|
39 |
xp[i]=x[i]+center_img[i]-cm[i] |
|
40 |
for i in range(0, len(x[0])): |
|
41 |
if ((xp[0][i]>=0) and (xp[0][i]<s[0]) and (xp[1][i]>=0) and (xp[1][i]<s[1]) and (xp[2][i]>=0) and (xp[2][i]<s[2])): |
|
42 |
img1[xp[0][i],xp[1][i],xp[2][i]]=img[x[0][i],x[1][i],x[2][i]] |
|
43 |
img1=SpatialImage(img1) |
|
44 |
img1.voxelsize=res |
|
45 |
return img1 |
|
46 |
|
|
47 |
|
|
48 |
def principal_directions(img, threshold=10): |
|
49 |
''' |
|
50 |
Returns the first two principal eigen vectors of an input image |
|
51 |
Fixed threshold of 10 for a 8 bit image |
|
52 |
It suppposes an isotropic sampling of the image. |
|
53 |
''' |
|
54 |
x,y,z = np.where(img > threshold) ## appropriate thresholding |
|
55 |
x = x - np.mean(x) |
|
56 |
y = y - np.mean(y) |
|
57 |
z = z - np.mean(z) |
|
58 |
coords = np.vstack([x,y,z]) |
|
59 |
cov = np.cov(coords) |
|
60 |
evals,evecs = np.linalg.eig(cov) |
|
61 |
sort_indices = np.argsort(evals)[::-1] |
|
62 |
return list(evecs[:,sort_indices][0:2]) |
|
63 |
|
|
64 |
def direct_frame(pv): |
|
65 |
''' |
|
66 |
Constructs a direct frame with first two unitvectors v0 and v1 |
|
67 |
''' |
|
68 |
return np.array([pv[0], pv[1], np.cross(pv[0], pv[1])]) |
|
69 |
|
|
70 |
|
|
71 |
def write_transformation(T, trsf_file): |
|
72 |
''' |
|
73 |
writes the affine transformation T (4x4 matrix) in |
|
74 |
a textfile read by blockmatching. |
|
75 |
''' |
|
76 |
f = open(trsf_file,'w') |
|
77 |
f.write("( "+"\n") |
|
78 |
f.write("08 "+"\n") |
|
79 |
for i in T: |
|
80 |
for j in i: |
|
81 |
f.write(" "+str(j)+" ") |
|
82 |
f.write("\n") |
|
83 |
f.write(") ") |
|
84 |
return |
|
85 |
|
|
86 |
|
|
87 |
|
|
88 |
def write_rigid(trsf_file, R, a): |
|
89 |
''' |
|
90 |
write a rigid transformation with rotation matrix R and translation a |
|
91 |
''' |
|
92 |
T = np.identity(4) |
|
93 |
T[0:3,0:3] = R |
|
94 |
T = np.transpose(T) |
|
95 |
T[0:3,3] = a |
|
96 |
write_transformation(T, trsf_file) |
|
97 |
return |
|
98 |
|
|
99 |
|
|
100 |
|
|
101 |
def write_superposing_transfo(pv_flo, pv_ref, img, trsf_file): |
|
102 |
''' |
|
103 |
- pv_flo and pv-ref are lists of the first two principal vectors of the floating and the reference images respectively |
|
104 |
- img is the floating image |
|
105 |
''' |
|
106 |
# compute the rotation matrix R |
|
107 |
pframe_ref = direct_frame(pv_ref) |
|
108 |
pframe_flo = direct_frame(pv_flo) |
|
109 |
F = np.transpose(pframe_ref) |
|
110 |
G = np.transpose(pframe_flo) |
|
111 |
R = np.matmul(G, np.linalg.inv(F)) |
|
112 |
# blockmatching rotates arround the origin, |
|
113 |
# so a rotation arround the middle of the image contains an additional translation t |
|
114 |
s = img.shape |
|
115 |
res = img.voxelsize |
|
116 |
com = np.array(res)*np.array(s)/2 |
|
117 |
i = np.identity(3) |
|
118 |
t = np.dot((i-R),np.array(com)) |
|
119 |
R = np.transpose(R) |
|
120 |
write_rigid(trsf_file, R, t) |
|
121 |
return |
|
122 |
|
|
123 |
|
|
124 |
def add_side_slices(Img, x0, x1, y0, y1, z0, z1): |
|
125 |
""" |
|
126 |
adds 0 value slices on different sides of the image |
|
127 |
""" |
|
128 |
s=Img.shape |
|
129 |
ss=(s[0]+x0+x1,s[1]+y0+y1,s[2]+z0+z1) |
|
130 |
Img_new = (SpatialImage(np.zeros(ss))).astype('uint8') |
|
131 |
Img_new[x0:ss[0]-x1,y0:ss[1]-y1,z0:ss[2]-z1]=Img |
|
132 |
Img_new.voxelsize = Img.voxelsize |
|
133 |
return Img_new |
|
134 |
|
|
135 |
|
|
136 |
def remove_side_slices(Img, x0, x1, y0, y1, z0, z1): |
|
137 |
""" |
|
138 |
removes slices on different sides of the image |
|
139 |
""" |
|
140 |
ss=Img.shape |
|
141 |
Img_new=Img[x0:ss[0]-x1,y0:ss[1]-y1,z0:ss[2]-z1] |
|
142 |
#Img_new.resolution = Img.resolution |
|
143 |
return Img_new |
|
144 |
|
|
145 |
|
|
146 |
def measure_hight(a): |
|
147 |
b= np.where(a) |
|
148 |
height = 0 |
|
149 |
if b[0].shape[0]>0 : |
|
150 |
height = b[0][-1] |
|
151 |
return height |
|
152 |
|
|
153 |
|
|
154 |
def measure_height(a): |
|
155 |
b= np.where(a) |
|
156 |
height = [0,0] |
|
157 |
if b[0].shape[0]>0 : |
|
158 |
height = [b[0].min(),b[0].max()] |
|
159 |
return height |
|
160 |
|
|
161 |
|
|
162 |
def extract_curve(x_section): |
|
163 |
sx = x_section.shape |
|
164 |
xx = np.zeros((sx[0],2)) |
|
165 |
for i in range(0,sx[0]): |
|
166 |
xx[i,0] = i |
|
167 |
xx[i,1] = measure_hight(x_section[i,:]) |
|
168 |
return xx |
|
169 |
|
|
170 |
|
|
171 |
def extract_curves(x_section): |
|
172 |
sx = x_section.shape |
|
173 |
xup = np.zeros((sx[0],2)) |
|
174 |
xdown = np.zeros((sx[0],2)) |
|
175 |
for i in range(0,sx[0]): |
|
176 |
xup[i,0] = i |
|
177 |
xdown[i,0] = i |
|
178 |
xup[i,1] = measure_height(x_section[i,:])[1] |
|
179 |
xdown[i,1] = measure_height(x_section[i,:])[0] |
|
180 |
return xup, xdown |
|
181 |
|
|
182 |
|
|
183 |
def write_curve(y, pixelsize, filename) : |
|
184 |
FILE = open(filename,"w") |
|
185 |
FILE.write('# '+str(pixelsize[0])+' '+str(pixelsize[1])+'\n') |
|
186 |
s = y.shape |
|
187 |
#FILE.write('# '+str(s[0])+'\n') |
|
188 |
for i in range(0,s[0]) : |
|
189 |
FILE.write(str(y[i,0])+' '+str(y[i,1])+'\n') |
|
190 |
FILE.close() |
|
191 |
return |
|
192 |
|
|
193 |
|
|
194 |
def struct_element_sphere(radius): |
|
195 |
s=int(2*radius+1) |
|
196 |
structure=np.zeros((s,s,s)) |
|
197 |
center = np.array([radius, radius, radius]) |
|
198 |
Nl=range(s) |
|
199 |
for i in Nl: |
|
200 |
for j in Nl: |
|
201 |
for k in Nl: |
|
202 |
p=np.array([i,j,k]) |
|
203 |
d=p-center |
|
204 |
dist=np.sqrt(sum(d*d)) |
|
205 |
if dist<=radius: |
|
206 |
structure[i,j,k]=1 |
|
207 |
return structure |
|
208 |
|
|
209 |
|
|
210 |
def create_artificial_sepal(AA, RR, resolution): |
|
211 |
# A = parameters of an ellipse, as projected on xy plane (2d array) |
|
212 |
# R = curvature radius in directions x and y (2d array) |
|
213 |
# (A and R are given in micrometers) |
|
214 |
# resolution = voxelsize of the output stack |
|
215 |
A = np.array([AA[i]/resolution[i] for i in [0,1]]) |
|
216 |
R = np.array([RR[i]/resolution[i] for i in [0,1]]) |
|
217 |
h = np.array([math.sqrt(R[i]**2-A[i]**2) for i in range(len(A))]) |
|
218 |
zmax=np.array([R[i]-math.sqrt(R[i]**2-A[i]**2) for i in [0,1]]) |
|
219 |
#zmax= int(math.sqrt(zmax[0]*zmax[1])) |
|
220 |
zmax=zmax.mean() |
|
221 |
#zmax = 5 |
|
222 |
print(zmax) |
|
223 |
marge = 0.2 |
|
224 |
# creating the stack and the surface |
|
225 |
s = (int(A[0]*2*(1+marge)), int(A[1]*2*(1+marge)), int(zmax*(1+2*marge))) |
|
226 |
cm = np.array(s)/2 |
|
227 |
x = np.array(range(0,s[0])) |
|
228 |
y = np.array(range(0,s[1])) |
|
229 |
xx = x - cm[0] |
|
230 |
yy = y - cm[1] |
|
231 |
#xgrid, ygrid = np.meshgrid(xx, yy, sparse=True) # make sparse output arrays |
|
232 |
#mask=(((xgrid**2)/float(A[0])**2+(ygrid**2)/float(A[1])**2)<1).astype('uint8') |
|
233 |
z = np.zeros((s[0],s[1])) |
|
234 |
stack= np.zeros(s).astype('uint8') |
|
235 |
for i in x: |
|
236 |
for j in range(0,s[1]): |
|
237 |
if xx[i]**2/float(A[0])**2+yy[j]**2/float(A[1])**2<=1 : |
|
238 |
zx = (math.sqrt(R[0]**2-xx[i]**2)-h[0])*(1-abs(yy[j])/A[1]) |
|
239 |
zy = (math.sqrt(R[1]**2-yy[j]**2)-h[1])*(1-abs(xx[i])/A[0]) |
|
240 |
z[i,j] = math.sqrt(zx*zy) |
|
241 |
#z[i,j] = (zx+zy)/2 |
|
242 |
#z[i,j] = 5 |
|
243 |
stack[i,j,int(zmax*marge+z[i,j])]=1 |
|
244 |
stack = SpatialImage(stack) |
|
245 |
stack.resolution = resolution |
|
246 |
return z, stack |
|
247 |
|
|
248 |
|
|
249 |
|
|
250 |
def create_artificial_sepal_ellipse(AA, H, resolution): |
|
251 |
''' |
|
252 |
# A = parameters of an ellipse, as projected on xy plane (2d array) |
|
253 |
# R = curvature radius in directions x and y (2d array) |
|
254 |
# (A and R are given in micrometers) |
|
255 |
# resolution = voxelsize of the output stack |
|
256 |
''' |
|
257 |
A = np.array([AA[i]/resolution[i] for i in [0,1]]) |
|
258 |
h = H/resolution[2] |
|
259 |
zmax=h |
|
260 |
marge = 0.2 |
|
261 |
# creating the stack and the surface |
|
262 |
s = (int(A[0]*2*(1+marge)), int(A[1]*2*(1+marge)), int(zmax*(1+5*marge))) |
|
263 |
cm = np.array(s)/2 |
|
264 |
x = np.array(range(0,s[0])) |
|
265 |
y = np.array(range(0,s[1])) |
|
266 |
xx = x - cm[0] |
|
267 |
yy = y - cm[1] |
|
268 |
#xgrid, ygrid = np.meshgrid(xx, yy, sparse=True) # make sparse output arrays |
|
269 |
#mask=(((xgrid**2)/float(A[0])**2+(ygrid**2)/float(A[1])**2)<1).astype('uint8') |
|
270 |
z = np.zeros((s[0],s[1])) |
|
271 |
#z = -h*((xgrid**2)/float(A[0])**2+(ygrid**2)/float(A[1])**2) |
|
272 |
stack= np.zeros(s).astype('uint8') |
|
273 |
for i in x: |
|
274 |
for j in y: |
|
275 |
if xx[i]**2/float(A[0])**2+yy[j]**2/float(A[1])**2<=1 : |
|
276 |
z[i,j] = -h*((xx[i]**2)/float(A[0])**2+(yy[j]**2)/float(A[1])**2-1) |
|
277 |
stack[i,j,int(zmax*4*marge+z[i,j])]=1 |
|
278 |
stack = SpatialImage(stack) |
|
279 |
stack.voxelsize = resolution |
|
280 |
return z, stack |
|
281 |
|
|
282 |
# ------------------------------------------------------------------- |
|
283 |
|
|
284 |
def read_curve(filename) : |
|
285 |
""" |
|
286 |
Reads the coordinates of the point-list defining a 2D curve. |
|
287 |
**Returns** |
|
288 |
y : 2-column array |
|
289 |
defines a curve as an ordered list of points, |
|
290 |
each row of the array represents a point on the curve and contains |
|
291 |
its 2D cartesian coordinates |
|
292 |
pixelsize : tuple (res0, res1) in micrometers |
|
293 |
""" |
|
294 |
x0 = [] |
|
295 |
pixelsize = (1.0,1.0) |
|
296 |
for line in file(filename): |
|
297 |
if line[0] == "#" : |
|
298 |
line = line.lstrip('# ') |
|
299 |
line = line.rstrip('\n') |
|
300 |
line_list = [float(x) for x in line.split(' ')] |
|
301 |
pixelsize = (line_list[0], line_list[1]) |
|
302 |
else : |
|
303 |
line = line.rstrip('\n') |
|
304 |
line_list = [float(x) for x in line.split(' ')] |
|
305 |
x0.append(line_list) |
|
306 |
y = np.array(x0) |
|
307 |
return y, pixelsize |
|
308 |
|
|
309 |
|
|
310 |
|
|
311 |
def distance(p1, p2): |
|
312 |
return np.sqrt((p1[0]-p2[0])**2+(p1[1]-p2[1])**2) |
|
313 |
|
|
314 |
def distance_to_line(p1, p2, p0): |
|
315 |
''' |
|
316 |
gives the distance of point p0 to the line defined by points p1 and p2 (in 2d) |
|
317 |
''' |
|
318 |
return abs((p2[1]-p1[1])*p0[0]-(p2[0]-p1[0])*p0[1]+p2[0]*p1[1]-p2[1]*p1[0])/distance(p1,p2) |
|
319 |
|
|
320 |
def curvature(p1,p2,p3): |
|
321 |
t1 = (p3[0]**2-p2[0]**2+p3[1]**2-p2[1]**2)/(2.0*(p3[1]-p2[1])) |
|
322 |
t2 = (p2[0]**2-p1[0]**2+p2[1]**2-p1[1]**2)/(2.0*(p2[1]-p1[1])) |
|
323 |
n1 = (p3[0]-p2[0])/(p3[1]-p2[1]) |
|
324 |
n2 = (p2[0]-p1[0])/(p2[1]-p1[1]) |
|
325 |
pcx = (t1-t2+p3[1]-p1[1])/(n1-n2) |
|
326 |
pc = [pcx, -n1*pcx+t1/2+p3[1]/2+p1[1]/2] |
|
327 |
R = distance(p1, pc) |
|
328 |
return 1.0/R, pc |
|
329 |
|
|
330 |
|
|
331 |
def curvature2(p1,p2,p3): |
|
332 |
# http://www.ambrsoft.com/TrigoCalc/Circle3D.htm |
|
333 |
A = p1[0]*(p2[1]-p3[1])-p1[1]*(p2[0]-p3[0])+p2[0]*p3[1]-p3[0]*p2[1] |
|
334 |
B = (p1[0]**2+p1[1]**2)*(p3[1]-p2[1])+(p2[0]**2+p2[1]**2)*(p1[1]-p3[1])+(p3[0]**2+p3[1]**2)*(p2[1]-p1[1]) |
|
335 |
C = (p1[0]**2+p1[1]**2)*(p3[0]-p2[0])+(p2[0]**2+p2[1]**2)*(p1[0]-p3[0])+(p3[0]**2+p3[1]**2)*(p2[0]-p1[0]) |
|
336 |
D = (p1[0]**2+p1[1]**2)*(p3[0]*p2[1]-p2[0]*p3[1])+(p2[0]**2+p2[1]**2)*(p1[0]*p3[1]-p3[0]*p1[1])+(p3[0]**2+p3[1]**2)*(p2[0]*p1[1]-p1[0]*p2[1]) |
|
337 |
x = -B/(2*A) |
|
338 |
y = C/(2*A) |
|
339 |
pc = [x, y] |
|
340 |
R = distance(p1, pc) |
|
341 |
return 1.0/R, pc |
|
342 |
|
|
343 |
|
|
344 |
def curve_perle(y, first, last, step): |
|
345 |
yy=[] |
|
346 |
for i in range(first, last, step): |
|
347 |
if y[i][1]>0: |
|
348 |
yy.append(y[i]) |
|
349 |
if i<last: |
|
350 |
yy.append(y[last]) |
|
351 |
return np.array(yy) |
|
352 |
|
|
353 |
|
|
354 |
|
|
355 |
def compute_curvature_radius(x,y): |
|
356 |
# coordinates of the barycenter |
|
357 |
x_m = np.mean(x) |
|
358 |
y_m = np.mean(y) |
|
359 |
def calc_R(c): |
|
360 |
""" calculate the distance of each 2D points from the center c=(xc, yc) """ |
|
361 |
return np.sqrt((x-c[0])**2 + (y-c[1])**2) |
|
362 |
# |
|
363 |
def calc_ecart(c): |
|
364 |
""" calculate the algebraic distance between the 2D points and the mean circle centered at c=(xc, yc) """ |
|
365 |
Ri = calc_R(c) |
|
366 |
return Ri - Ri.mean() |
|
367 |
# |
|
368 |
center_estimate = x_m, y_m |
|
369 |
center_2, ier = optimize.leastsq(calc_ecart, center_estimate) |
|
370 |
# |
|
371 |
xc_2, yc_2 = center_2 |
|
372 |
Ri_2 = calc_R(center_2) |
|
373 |
R_2 = Ri_2.mean() |
|
374 |
residu_2 = sum((Ri_2 - R_2)**2) |
|
375 |
pc=[xc_2, yc_2] |
|
376 |
return R_2, pc |
|
377 |
|
|
378 |
|
|
379 |
def analyze_curve1(name, y, pixelsize, outfilename, graph_name='graph.png'): |
|
380 |
# isotropic pixels |
|
381 |
y[:,0] = y[:,0]*pixelsize[0] |
|
382 |
y[:,1] = y[:,1]*pixelsize[1] |
|
383 |
maxv = [y[:,i].max() for i in [0,1]] |
|
384 |
# find first and last points on the curve |
|
385 |
step = 5 |
|
386 |
sep_indices = np.where(y[:,1])[0] |
|
387 |
first = sep_indices[0]#+step/2 |
|
388 |
last = sep_indices[-1]#-step/2 |
|
389 |
# compute flat length |
|
390 |
flatlength = distance(y[first],y[last]) |
|
391 |
print("flat length =", flatlength," um") |
|
392 |
# compute curved length and height (maximal distance to the base) |
|
393 |
yy = curve_perle(y, first, last, step) |
|
394 |
length = 0 |
|
395 |
height = 0 |
|
396 |
height_index = 0 |
|
397 |
p1 = yy[0] |
|
398 |
p2 = yy[-1] |
|
399 |
for i in range(0, len(yy)-1): |
|
400 |
length = length + distance(yy[i+1],yy[i]) |
|
401 |
d = distance_to_line(p1, p2, yy[i]) |
|
402 |
if d>height : |
|
403 |
height = d |
|
404 |
height_index = i |
|
405 |
print("length = ",length," um") |
|
406 |
print("height = ",height," um") |
|
407 |
middle_point = yy[int(len(yy)/2)] |
|
408 |
# compute curvature radius by fitting the sepal section to a circle |
|
409 |
yyy=y[first:last] |
|
410 |
R, pc = compute_curvature_radius(yyy[:,0],yyy[:,1]) |
|
411 |
print("R=",R," um") |
|
412 |
# cutting curve in pieces in order to estimate curvature radius on portions of the curve |
|
413 |
slength=len(yyy) |
|
414 |
y21=yyy[0:int(slength/2)] |
|
415 |
y22=yyy[int(slength/2):slength] |
|
416 |
y41=yyy[0:int(slength/4)] |
|
417 |
y423=yyy[int(slength/4):3*int(slength/4)] |
|
418 |
y44=yyy[3*int(slength/4):slength] |
|
419 |
# and computing the curvature radius for each portion |
|
420 |
R21, pc = compute_curvature_radius(y21[:,0],y21[:,1]) |
|
421 |
R22, pc = compute_curvature_radius(y22[:,0],y22[:,1]) |
|
422 |
R41, pc = compute_curvature_radius(y41[:,0],y41[:,1]) |
|
423 |
R423, pc = compute_curvature_radius(y423[:,0],y423[:,1]) |
|
424 |
R44, pc = compute_curvature_radius(y44[:,0],y44[:,1]) |
|
425 |
fig = plt.figure() |
|
426 |
plt.plot(yy[:,0], yy[:,1], 'bo') |
|
427 |
plt.plot(y[:,0], y[:,1], 'r') |
|
428 |
plt.plot(y[first][0], y[first][1], 'ro') |
|
429 |
plt.plot(middle_point[0], middle_point[1], 'ro') |
|
430 |
plt.plot(y[last][0], y[last][1], 'ro') |
|
431 |
plt.plot(yy[height_index][0], yy[height_index][1], 'go') |
|
432 |
plt.plot(pc[0], pc[1], 'bx') |
|
433 |
plt.gca().set_aspect('equal', adjustable='box') |
|
434 |
#plt.show() |
|
435 |
fig.savefig(graph_name) |
|
436 |
#plt.close() |
|
437 |
# write the data into a file |
|
438 |
FILE = open(outfilename,"a") |
|
439 |
FILE.write(name+';'+str(length)+';'+str(R)+';'+str(flatlength)+';'+str(height)+'\n') |
|
440 |
FILE.close() |
|
441 |
return length, flatlength, height, R, R21, R22, R41, R423, R44 |
|
442 |
|
|
443 |
def imsave2D(filename, matrix): |
|
444 |
fig = plt.figure() |
|
445 |
plt.gca().imshow(np.transpose(matrix), interpolation='none') |
|
446 |
fig.savefig(filename) |
|
447 |
return |
bin/image2geometry/inr2tif.ijm (revision 1) | ||
---|---|---|
1 |
////////////////////////////////////////////////////////////////////////////////// |
|
2 |
|
|
3 |
//The script will process all your .inr.gz files in the chosen folder. |
|
4 |
//The stacks will be saved in subfolders named as the treated lif files. |
|
5 |
|
|
6 |
print ("==========================="); |
|
7 |
print ("==== Macro inr2tif.ijm ===="); |
|
8 |
|
|
9 |
|
|
10 |
//Choose the directory containing your .inr.gz files// |
|
11 |
dir = getDirectory("Choose a directory") |
|
12 |
setBatchMode(true); |
|
13 |
list = getFileList(dir); |
|
14 |
|
|
15 |
print(dir); |
|
16 |
ShortNameDir=substring(dir,0,lastIndexOf(dir,"/")); |
|
17 |
print (ShortNameDir); |
|
18 |
dirout=ShortNameDir+"-tif/"; |
|
19 |
print("Creating output directory ",dirout); |
|
20 |
File.makeDirectory(dirout); |
|
21 |
|
|
22 |
for (FileInd=0; FileInd<list.length; FileInd++){ |
|
23 |
FileName = list[FileInd]; |
|
24 |
if(endsWith (FileName, ".inr.gz")){ |
|
25 |
print ("### Processing ",FileName," ###"); |
|
26 |
path = dir+FileName; |
|
27 |
ShortName=substring(FileName,0,indexOf(FileName,".inr.gz")); |
|
28 |
run("Bio-Formats Importer", "open=["+path+"] color_mode=Default view=Hyperstack stack_order=XYCZT use_virtual_stack open_all_series "); |
|
29 |
TiffName=ShortName+".tif"; |
|
30 |
saveAs("Tiff", dirout+TiffName); |
|
31 |
run("Close All"); |
|
32 |
print("Done with", FileName,"!"); |
|
33 |
} else { |
|
34 |
print("### ",FileName," Not an .inr.gz file ###"); |
|
35 |
}; |
|
36 |
}; |
|
37 |
print("Done with this folder!!!"); |
|
38 |
|
|
39 |
|
|
40 |
|
|
41 |
|
bin/image2geometry/orient_sepal.py (revision 1) | ||
---|---|---|
1 |
#!/usr/bin/env python |
|
2 |
|
|
3 |
''' |
|
4 |
Usage: |
|
5 |
orient_object.py filename output.txt |
|
6 |
|
|
7 |
- filename = path and name of the stack file containing the object (background=0) |
|
8 |
|
|
9 |
Output: |
|
10 |
the image with the object reoriented: |
|
11 |
- CM in the middle of the image |
|
12 |
- first principal axis along y |
|
13 |
- second principal axis along x |
|
14 |
|
|
15 |
''' |
|
16 |
|
|
17 |
from sys import argv |
|
18 |
import os |
|
19 |
import numpy as np |
|
20 |
from scipy.ndimage.morphology import binary_closing, binary_opening |
|
21 |
|
|
22 |
from titk_tools.io import imread, imsave, SpatialImage |
|
23 |
from titk_tools.rw.registration import isotropic_resampling_seg |
|
24 |
|
|
25 |
from bib_sepals import * |
|
26 |
|
|
27 |
|
|
28 |
|
|
29 |
print('============== orient_sepal.py =================') |
|
30 |
|
|
31 |
filename = argv[1] |
|
32 |
|
|
33 |
print(argv) |
|
34 |
|
|
35 |
imname = filename.split('/')[-1] |
|
36 |
imnameroot = imname.split('.')[0] |
|
37 |
|
|
38 |
outputdir = imnameroot+'_oriented/' |
|
39 |
os.system("mkdir -p "+outputdir) |
|
40 |
|
|
41 |
isodir = imnameroot+'_iso/' |
|
42 |
os.system("mkdir -p "+isodir) |
|
43 |
|
|
44 |
#outname = outputfile.split('/')[-1] |
|
45 |
#outroot = outname.split('.')[0] |
|
46 |
|
|
47 |
inrname = outputdir+imnameroot+'.inr.gz' |
|
48 |
outfilename = outputdir+imnameroot+'_oriented.inr.gz' |
|
49 |
isoname = isodir+imnameroot+'_iso.inr.gz' |
|
50 |
sname = isodir+imnameroot+'_iso_closed.inr.gz' |
|
51 |
|
|
52 |
# resample isotropically |
|
53 |
print("----------------------") |
|
54 |
print("isotropic resampling of : filename=", filename) |
|
55 |
print("----------------------") |
|
56 |
sepale=imread(filename) |
|
57 |
voxelsize = sepale.voxelsize |
|
58 |
print("voxelsize=",voxelsize) |
|
59 |
s = sepale.shape |
|
60 |
print("shape=",s) |
|
61 |
|
|
62 |
radius=int(voxelsize[2]/voxelsize[0]) |
|
63 |
isovs=(voxelsize[0]*voxelsize[1]*voxelsize[2])**(1.0/3) |
|
64 |
#isovs=voxelsize[0] |
|
65 |
print("new voxelsize=",isovs) |
|
66 |
|
|
67 |
sepale=SpatialImage(sepale>0, dtype='uint8', voxelsize=voxelsize, origin=[0, 0, 0]) |
|
68 |
imsave(inrname, sepale) |
|
69 |
isotropic_resampling_seg(inrname, isoname, isovs) |
|
70 |
|
|
71 |
sepale=imread(isoname) |
|
72 |
s = sepale.shape |
|
73 |
voxelsize = sepale.voxelsize |
|
74 |
print('new voxelsize read=', voxelsize) |
|
75 |
print('new shape', s) |
|
76 |
|
|
77 |
# alongate the target image so that a sepal originally along the diagonal fits into the target image |
|
78 |
print("----------------------") |
|
79 |
print("elongating field : filename=", filename) |
|
80 |
print("----------------------") |
|
81 |
s_addy=int((np.sqrt(s[0]*s[1]*2)-np.sqrt(s[0]*s[1]))/2) |
|
82 |
#s_addy=int(np.sqrt(s[0]*s[1])(1.-np.sqrt(2.))/2. * 1.05) |
|
83 |
s_addz=int(s[2]*0.20) |
|
84 |
sepale_long=add_side_slices(sepale, 0, 0, s_addy, s_addy, s_addz, s_addz) |
|
85 |
sepale=SpatialImage(sepale_long, dtype='uint8', voxelsize=voxelsize, origin=[0, 0, 0]) |
|
86 |
imsave(isoname, sepale) |
|
87 |
print('--------------------') |
|
88 |
|
|
89 |
# smooth it with opening |
|
90 |
sepale=imread(isoname) |
|
91 |
s = sepale.shape |
|
92 |
voxelsize = sepale.voxelsize |
|
93 |
struct_el=struct_element_sphere(radius) |
|
94 |
sepale = binary_closing(sepale, structure=struct_el, iterations=int(radius)) |
|
95 |
struct_el=struct_element_sphere(radius/2) |
|
96 |
sepale = binary_closing(sepale, structure=struct_el, iterations=int(radius/2)) |
|
97 |
sepale=SpatialImage(sepale*255, dtype='uint8', voxelsize=voxelsize, origin=[0, 0, 0]) |
|
98 |
imsave(sname, sepale) |
|
99 |
|
|
100 |
|
|
101 |
# put the center of mass in the center of the image |
|
102 |
sepale_centered=center_on_cm(sepale) |
|
103 |
voxelsize = sepale_centered.resolution |
|
104 |
sepale_centered_filename = outputdir+imnameroot+'_centered.inr.gz' |
|
105 |
imsave(sepale_centered_filename, sepale_centered) |
|
106 |
|
|
107 |
|
|
108 |
# compute principal directions |
|
109 |
pv_flo=principal_directions(sepale_centered) |
|
110 |
print(pv_flo) |
|
111 |
|
|
112 |
# sepals originally are oriented with top in more-or less "up" direction on the images |
|
113 |
# while the eigenvectors' orientation is arbitrary |
|
114 |
# --> do not change the original rough orientation |
|
115 |
|
|
116 |
# check logitudinal direction: |
|
117 |
if pv_flo[0][1]<0 : |
|
118 |
pv_flo[0] = -pv_flo[0] |
|
119 |
|
|
120 |
# check the transversal direction |
|
121 |
if pv_flo[1][0]<0 : |
|
122 |
pv_flo[1] = -pv_flo[1] |
|
123 |
|
|
124 |
print("New pv_flo",pv_flo) |
|
125 |
|
|
126 |
''' |
|
127 |
pv_ref = [np.array([0,-1,0]), |
|
128 |
np.array([-1,0,0])] |
|
129 |
|
|
130 |
''' |
|
131 |
pv_ref = [np.array([0,1,0]), |
|
132 |
np.array([1,0,0])] |
|
133 |
|
|
134 |
|
|
135 |
# compute superposing transformation |
|
136 |
trsf_file=outputdir+imnameroot+'_rigid.txt' |
|
137 |
write_superposing_transfo(pv_flo, pv_ref, sepale_centered, trsf_file) |
|
138 |
|
|
139 |
# apply transformation |
|
140 |
sepale_filename = outputdir+imnameroot+'_oriented.inr.gz' |
|
141 |
apply_transfo_on_seg1(trsf_file, sepale_centered_filename, sepale_filename) |
|
142 |
|
|
143 |
# smooth the transformed image |
|
144 |
sepale=imread(sepale_filename) |
|
145 |
sepale = binary_closing(sepale, structure=struct_el, iterations=radius) |
|
146 |
|
|
147 |
# and save the oriented sepal |
|
148 |
sepale=SpatialImage(sepale*255, dtype='uint8', voxelsize=voxelsize, origin=[0, 0, 0]) |
|
149 |
imsave(sepale_filename, sepale) |
|
150 |
|
|
0 | 151 |
bin/image2geometry/measure_sepal.py (revision 1) | ||
---|---|---|
1 |
#!/usr/bin/env python |
|
2 |
|
|
3 |
''' |
|
4 |
Usage: |
|
5 |
measure_sepal.py filename output.csv |
|
6 |
|
|
7 |
- filename = path and name of the stack file containing the object (background=0) |
|
8 |
the object is supposed already oriented as follows: |
|
9 |
- output = output directory |
|
10 |
--------------------------------------------------------------------------------- |
|
11 |
- CM in the middle of the image |
|
12 |
- first principal axis along y |
|
13 |
- second principal axis along x |
|
14 |
|
|
15 |
Output: |
|
16 |
|
|
17 |
measured data is written into the file output.csv |
|
18 |
flat projections are written in the output directory |
|
19 |
|
|
20 |
''' |
|
21 |
|
|
22 |
from sys import argv |
|
23 |
import os |
|
24 |
import numpy as np |
|
25 |
from scipy.ndimage.morphology import binary_closing, binary_opening |
|
26 |
|
|
27 |
from titk_tools.io import imread, imsave |
|
28 |
from bib_sepals import * |
|
29 |
|
|
30 |
|
|
31 |
print('============== measure_sepal.py =================') |
|
32 |
|
|
33 |
filename = argv[1] |
|
34 |
outdir = argv[2] |
|
35 |
outputfile=outdir+"/"+outdir+".csv" |
|
36 |
|
|
37 |
|
|
38 |
print(argv) |
|
39 |
|
|
40 |
imname = filename.split('/')[-1] |
|
41 |
imnameroot = imname.split('.')[0] |
|
42 |
|
|
43 |
outputdir = imnameroot+'_sections/' |
|
44 |
projected2Dimage=outdir+"/"+imnameroot+"2D.png" |
|
45 |
projected2Dimage_hight=outdir+"/hight_"+imnameroot+"2D.png" |
|
46 |
|
|
47 |
os.system("mkdir -p "+outputdir) |
|
48 |
|
|
49 |
outname = outputfile.split('/')[-1] |
|
50 |
outroot = outname.split('.')[0] |
|
51 |
|
|
52 |
print("----------------------") |
|
53 |
print("reading the file ", filename) |
|
54 |
print("----------------------") |
|
55 |
sepale=imread(filename) |
|
56 |
voxelsize = sepale.voxelsize |
|
57 |
print("voxelsize=",voxelsize) |
|
58 |
s = sepale.shape |
|
59 |
print("shape=",s) |
|
60 |
|
|
61 |
print("Projecting on 2D...") |
|
62 |
|
|
63 |
def project2D(im3): |
|
64 |
s2=(s[1],s[0]) |
|
65 |
im2=np.zeros(s2, dtype='uint8') |
|
66 |
for i in range(s[0]): |
|
67 |
im2[:,i]=np.array([max(im3[i,j,:]) for j in range(s[1])]) |
|
68 |
return im2 |
|
69 |
|
|
70 |
def project2D_hightmap(im3): |
|
71 |
s2=(s[1],s[0]) |
|
72 |
im2=np.zeros(s2, dtype='uint8') |
|
73 |
for i in range(s[0]): |
|
74 |
im2[:,i]=np.array([list(im3[i,j,:]).index(max(im3[i,j,:])) for j in range(s[1])]) |
|
75 |
return im2 |
|
76 |
|
|
77 |
|
|
78 |
sepale2D=project2D(sepale) |
|
79 |
imsave2D(projected2Dimage, sepale2D) |
|
80 |
|
|
81 |
''' |
|
82 |
sepale2D=project2D_hightmap(sepale) |
|
83 |
imsave2D(projected2Dimage_hight, sepale2D) |
|
84 |
''' |
|
85 |
|
|
86 |
print('Extracting principal section curves...') |
|
87 |
|
|
88 |
# longitudinal section |
|
89 |
x_section = sepale[int(s[0]/2), :, :] |
|
90 |
xup_filename = outputdir+imnameroot+'_section_xup.txt' |
|
91 |
xdown_filename = outputdir+imnameroot+'_section_xdown.txt' |
|
92 |
x_filename = outputdir+imnameroot+'_section_x.txt' |
|
93 |
x_pixelsize = (voxelsize[1],voxelsize[2]) |
|
94 |
xup, xdown = extract_curves(x_section) |
|
95 |
|
|
96 |
write_curve(xup, x_pixelsize, xup_filename) |
|
97 |
|
|
98 |
|
|
99 |
# transversal section |
|
100 |
y_section = sepale[:,int(s[1]/2), :] |
|
101 |
yup_filename = outputdir+imnameroot+'_section_yup.txt' |
|
102 |
ydown_filename = outputdir+imnameroot+'_section_ydown.txt' |
|
103 |
y_filename = outputdir+imnameroot+'_section_y.txt' |
|
104 |
y_pixelsize = (voxelsize[0],voxelsize[2]) |
|
105 |
yup, ydown = extract_curves(y_section) |
|
106 |
|
|
107 |
write_curve(yup, y_pixelsize, yup_filename) |
|
108 |
|
|
109 |
|
|
110 |
# |
|
111 |
# ---------------------------------------- |
|
112 |
print('Analyzing principal section curves...') |
|
113 |
|
|
114 |
if not(os.path.isfile(outputfile)): |
|
115 |
FILE = open(outputfile,"w") |
|
116 |
FILE.write('Sepal;CurvedLength;FlatLength;LHeight;LR;LR21;LR22;LR41;LR423;LR44;CurvedWidth;FlatWidth;THeight;TR;TR21;TR22;TR41;TR423;TR44\n') |
|
117 |
FILE.close() |
|
118 |
|
|
119 |
FILE = open(outputfile,"a") |
|
120 |
FILE.write(imnameroot+';') |
|
121 |
|
|
122 |
outfile=outroot+'_up_longitudinal.csv' |
|
123 |
graph_name= outputdir+imnameroot+'_up_longitudinal.png' |
|
124 |
length_x, flatlength_x, height_x, R, R21, R22, R41, R423, R44=analyze_curve1(imnameroot, xup, x_pixelsize, outfile, graph_name) |
|
125 |
|
|
126 |
FILE.write(str(length_x)+';'+str(flatlength_x)+';'+str(height_x)+';'+str(R)+';'+str(R21)+';'+str(R22)+';'+str(R41)+';'+str(R423)+';'+str(R44)+';') |
|
127 |
|
|
128 |
outfile=outroot+'_up_transversal.csv' |
|
129 |
graph_name= outputdir+imnameroot+'_up_transversal.png' |
|
130 |
length_y, flatlength_y, height_y, R, R21, R22, R41, R423, R44=analyze_curve1(imnameroot, yup, y_pixelsize, outfile, graph_name) |
|
131 |
|
|
132 |
FILE.write(str(length_y)+';'+str(flatlength_y)+';'+str(height_y)+';'+str(R)+';'+str(R21)+';'+str(R22)+';'+str(R41)+';'+str(R423)+';'+str(R44)+'\n') |
|
133 |
|
|
0 | 134 |
bin/image2geometry/lif2tif.ijm (revision 1) | ||
---|---|---|
1 |
////////////////////////////////////////////////////////////////////////////////// |
|
2 |
|
|
3 |
//The script will process all your .lif files in the chosen folder. |
|
4 |
//The stacks will be saved in subfolders named as the treated lif files. |
|
5 |
|
|
6 |
print ("===================================="); |
|
7 |
print ("======== Macro lif2tif.ijm ========="); |
|
8 |
print ("===================================="); |
|
9 |
|
|
10 |
//Choose the directory containing your .lif file// |
|
11 |
dir = getDirectory("Choose a directory") |
|
12 |
setBatchMode(true); |
|
13 |
list = getFileList(dir); |
|
14 |
|
|
15 |
//Find .lif experiment// |
|
16 |
for (FileInd=0; FileInd<list.length; FileInd++){ |
|
17 |
FileName = list[FileInd]; |
|
18 |
if(endsWith (FileName, "lif")){ |
|
19 |
print ("### Processing ",FileName," ###"); |
|
20 |
path = dir+FileName; |
|
21 |
ShortName=substring(FileName,0,indexOf(FileName,".lif")); |
|
22 |
print("Creating output directory ",ShortName); |
|
23 |
File.makeDirectory(dir+ShortName); |
|
24 |
//Open .lif// |
|
25 |
run("Bio-Formats Importer", "open=["+path+"] color_mode=Default view=Hyperstack stack_order=XYCZT use_virtual_stack open_all_series "); |
|
26 |
//Saving as .tif the content of the .lif files, in their destination folders// |
|
27 |
list = getList("image.titles"); |
|
28 |
//get the name of each image opened// |
|
29 |
ids=newArray(nImages); |
|
30 |
for (j=0; j<list.length; j++){ |
|
31 |
//print(list[j]); |
|
32 |
selectImage(j+1); |
|
33 |
ids[j]=getTitle; |
|
34 |
//Get experiment name (title of the .lif file)// |
|
35 |
experiment_name=substring(ids[j],0,indexOf(ids[j],".lif")); |
|
36 |
//Remove the name of the .lif file that is included in each image// |
|
37 |
short_name1 = substring(ids[j], indexOf(ids[j], "- "), lastIndexOf(ids[j], "")); |
|
38 |
short_name = replace(short_name1, "- ", ""); |
|
39 |
//If not a stack, save directly as .tif with a short name// |
|
40 |
if (nSlices==1){ |
|
41 |
print("Not a stack"); |
|
42 |
run("8-bit"); |
|
43 |
saveAs("Tiff", dir+File.separator+experiment_name+File.separator+short_name); |
|
44 |
print(short_name, ">>> Image saved as .tif"); |
|
45 |
//If a stack, reverse and save as .tif with a short name// |
|
46 |
} else { |
|
47 |
run("Reverse"); |
|
48 |
run("8-bit"); |
|
49 |
saveAs("Tiff", dir+File.separator+experiment_name+File.separator+short_name); |
|
50 |
print("----- ",short_name, " >>> Reversed and saved as .tif"); |
|
51 |
}; |
|
52 |
getPixelSize(unit, pw, ph, pd); |
|
53 |
print("Voxelsize="+pw+"x"+ph+"x"+pd+" "+unit+"^3"); |
|
54 |
print("nSlices="+nSlices); |
|
55 |
}; |
|
56 |
run("Close All"); |
|
57 |
print("Done with", FileName,"!"); |
|
58 |
} else { |
|
59 |
print("### ",FileName," Not a .lif file###"); |
|
60 |
}; |
|
61 |
}; |
|
62 |
print("Done with this folder!!!"); |
|
63 |
|
|
64 |
|
|
65 |
|
|
66 |
|
readme.txt (revision 1) | ||
---|---|---|
1 |
--------------------------------------------------------------------------- |
|
2 |
# "FLORIVAR" project |
|
3 |
(project ID : "florivar") |
|
4 |
--------------------------------------------------------------------------- |
|
5 |
Biophysics Team - RDP ENS Lyon |
|
6 |
|
|
7 |
Developers : |
|
8 |
-------------- |
|
9 |
Annamaria KISS, Corentin MOLLIER, Frenk Diego HARTASANCHEZ |
|
10 |
|
|
11 |
Download the repository / Rapatrier le dépot |
|
12 |
-------------------------------------------- |
|
13 |
cd "directory that will contain the project's directory" |
|
14 |
svn --username $USER checkout http://forge.cbp.ens-lyon.fr/svn/florivar |
|
15 |
|
|
16 |
Update (download changes from the repository) |
|
17 |
-------------------------------------------- |
|
18 |
cd florivar |
|
19 |
svn up |
|
20 |
|
|
21 |
Commit (upload your changes into the repository) |
|
22 |
----------------------------------------------- |
|
23 |
cd florivar |
|
24 |
svn commit |
|
25 |
|
|
26 |
Changing the file tree |
|
27 |
---------------------- |
|
28 |
if you want to add, delete or move individual files in the file-tree of the repository, you have to do that by svn |
|
29 |
... cd in the right subdirectory |
|
30 |
svn add toto |
|
31 |
svn mv toto titi |
|
32 |
svn rm titi |
|
33 |
... and then make a commit (!) |
|
34 |
|
|
35 |
Useful links |
|
36 |
------------- |
|
37 |
svn useful commands : http://wiki.greenstone.org/wiki/index.php/Useful_SVN_Commands |
|
38 |
formats in a wiki : https://forge.cbp.ens-lyon.fr/redmine/help/wiki_syntax.html |
|
39 |
|
Formats disponibles : Unified diff