Statistiques
| Révision :

root / bin / image2geometry / bib_sepals.py @ 10

Historique | Voir | Annoter | Télécharger (16,8 ko)

1
import numpy as np
2
import matplotlib.pyplot as plt
3
import math
4
from scipy import optimize
5
from scipy.ndimage import binary_dilation
6

    
7
from titk_tools.io import imread, imsave, SpatialImage
8

    
9
def center_on_point(img, cm):
10
        '''
11
        Centers the image img on the point cm
12
        '''
13
        x = np.array(np.where(img > 0) )
14
        xp=np.zeros_like(x)
15
        img1=np.zeros_like(img)
16
        s=img.shape
17
        center_img=np.array(s)/2
18
        for i in [0, 1, 2]:
19
                xp[i]=x[i]+center_img[i]-cm[i]
20
        for i in range(0, len(x[0])):
21
                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])):
22
                        img1[xp[0][i],xp[1][i],xp[2][i]]=img[x[0][i],x[1][i],x[2][i]]
23
        img1=SpatialImage(img1)
24
        img1.resolution=img.resolution
25
        return img1
26

    
27

    
28
def center_on_cm(img, volumic=True):
29
        '''
30
        Centers the image img on the point cm
31
        '''
32
        s=img.shape
33
        res=img.voxelsize
34
        if volumic:
35
                obj=img
36
        else :
37
                obj=binary_dilation(img)-img
38
        x = np.array(np.where(obj > 0) )
39
        cm = np.array([np.mean(x[i]) for i in [0,1,2]])
40
        x = np.array(np.where(img > 0) )
41
        xp=np.zeros_like(x)
42
        img1=np.zeros_like(img)
43
        center_img=np.array(s)/2
44
        for i in [0, 1, 2]:
45
                xp[i]=x[i]+center_img[i]-cm[i]
46
        for i in range(0, len(x[0])):
47
                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])):
48
                        img1[xp[0][i],xp[1][i],xp[2][i]]=img[x[0][i],x[1][i],x[2][i]]
49
        img1=SpatialImage(img1)
50
        img1.voxelsize=res
51
        return img1
52

    
53

    
54
def principal_directions(img, threshold=10, volumic=True):        
55
        '''
56
        Returns the first two principal eigen vectors of an input image
57
        Fixed threshold of 10 for a 8 bit image
58
        It suppposes an isotropic sampling of the image.
59
        '''
60
        if volumic:
61
                obj=img
62
        else :
63
                obj=binary_dilation(img)-img
64
        x,y,z = np.where(obj*255 > threshold) ## appropriate thresholding 
65
        x = x - np.mean(x)
66
        y = y - np.mean(y)
67
        z = z - np.mean(z)
68
        coords = np.vstack([x,y,z])
69
        cov = np.cov(coords)
70
        evals,evecs = np.linalg.eig(cov)
71
        sort_indices = np.argsort(evals)[::-1]
72
        return list(evecs[:,sort_indices][0:2])
73

    
74
def direct_frame(pv):
75
        '''
76
        Constructs a direct frame with first two unitvectors v0 and v1
77
        '''
78
        return np.array([pv[0], pv[1], np.cross(pv[0], pv[1])])
79

    
80

    
81
def write_transformation(T, trsf_file):
82
        '''
83
        writes the affine transformation T (4x4 matrix) in
84
        a textfile read by blockmatching.
85
        '''
86
        f = open(trsf_file,'w')
87
        f.write("( "+"\n")
88
        f.write("08 "+"\n")
89
        for i in T:
90
                for j in i:
91
                        f.write("  "+str(j)+" ")
92
                f.write("\n")
93
        f.write(") ")
94
        return
95

    
96

    
97

    
98
def write_rigid(trsf_file, R, a):
99
        '''
100
        write a rigid transformation with rotation matrix R and translation a
101
        '''
102
        T = np.identity(4)
103
        T[0:3,0:3] = R
104
        T = np.transpose(T)
105
        T[0:3,3] = a
106
        #write_transformation(T, trsf_file)
107
        np.savetxt(trsf_file, T, delimiter=";")
108
        return
109

    
110

    
111

    
112
def write_superposing_transfo(pv_flo, pv_ref, img, trsf_file):
113
        '''
114
        - pv_flo and pv-ref are lists of the first two principal vectors of the floating and the reference images respectively
115
        - img is the floating image
116
        '''
117
        # compute the rotation matrix R
118
        pframe_ref = direct_frame(pv_ref)
119
        pframe_flo = direct_frame(pv_flo)
120
        F = np.transpose(pframe_ref)
121
        G = np.transpose(pframe_flo)
122
        R = np.matmul(G, np.linalg.inv(F))
123
        # blockmatching rotates arround the origin,
124
        # so a rotation arround the middle of the image contains an additional translation t
125
        s = img.shape
126
        res = img.voxelsize
127
        com = np.array(res)*np.array(s)/2
128
        i = np.identity(3)
129
        t = np.dot((i-R),np.array(com))
130
        R = np.transpose(R)
131
        write_rigid(trsf_file, R, t)
132
        return
133

    
134

    
135
def add_side_slices(Img, x0, x1, y0, y1, z0, z1):
136
        """
137
        adds 0 value slices on different sides of the image
138
        """
139
        s=Img.shape
140
        ss=(s[0]+x0+x1,s[1]+y0+y1,s[2]+z0+z1)
141
        Img_new = (SpatialImage(np.zeros(ss))).astype('uint8')
142
        Img_new[x0:ss[0]-x1,y0:ss[1]-y1,z0:ss[2]-z1]=Img
143
        Img_new.voxelsize = Img.voxelsize
144
        return Img_new
145

    
146

    
147
def remove_side_slices(Img, x0, x1, y0, y1, z0, z1):
148
        """
149
        removes slices on different sides of the image
150
        """
151
        ss=Img.shape
152
        Img_new=Img[x0:ss[0]-x1,y0:ss[1]-y1,z0:ss[2]-z1]
153
        #Img_new.resolution = Img.resolution
154
        return Img_new
155

    
156

    
157
def measure_hight(a):
158
        b= np.where(a)
159
        height = 0
160
        if b[0].shape[0]>0 :
161
                height = b[0][-1]
162
        return height
163

    
164

    
165
def measure_height(a):
166
        b= np.where(a)
167
        height = [0,0]
168
        if b[0].shape[0]>0 :
169
                height = [b[0].min(),b[0].max()]
170
        return height
171

    
172

    
173
def extract_curve(x_section):
174
        sx = x_section.shape
175
        xx = np.zeros((sx[0],2))
176
        for i in range(0,sx[0]):
177
                xx[i,0] = i
178
                xx[i,1] = measure_hight(x_section[i,:])
179
        return xx
180

    
181

    
182
def extract_curves(x_section):
183
        sx = x_section.shape
184
        xup = np.zeros((sx[0],2))
185
        xdown = np.zeros((sx[0],2))
186
        for i in range(0,sx[0]):
187
                xup[i,0] = i
188
                xdown[i,0] = i
189
                xup[i,1] = measure_height(x_section[i,:])[1]
190
                xdown[i,1] = measure_height(x_section[i,:])[0]
191
        return xup, xdown
192

    
193

    
194
def write_curve(y, pixelsize, filename) :
195
        FILE = open(filename,"w")
196
        FILE.write('# '+str(pixelsize[0])+' '+str(pixelsize[1])+'\n')
197
        s = y.shape
198
        #FILE.write('# '+str(s[0])+'\n')
199
        for i in range(0,s[0]) :
200
                FILE.write(str(y[i,0])+' '+str(y[i,1])+'\n')
201
        FILE.close()
202
        return
203

    
204

    
205
def struct_element_sphere(radius):
206
        s=int(2*radius+1)
207
        structure=np.zeros((s,s,s))
208
        center = np.array([radius, radius, radius])
209
        Nl=range(s)
210
        for i in Nl:
211
                for j in Nl:
212
                        for k in Nl:
213
                                p=np.array([i,j,k])
214
                                d=p-center
215
                                dist=np.sqrt(sum(d*d))
216
                                if dist<=radius:
217
                                        structure[i,j,k]=1
218
        return structure
219

    
220

    
221
def create_artificial_sepal(AA, RR, resolution):
222
        # A = parameters of an ellipse, as projected on xy plane (2d array)
223
        # R = curvature radius in directions x and y (2d array)
224
        # (A and R are given in micrometers)
225
        # resolution = voxelsize of the output stack
226
        A = np.array([AA[i]/resolution[i] for i in [0,1]])
227
        R = np.array([RR[i]/resolution[i] for i in [0,1]])
228
        h = np.array([math.sqrt(R[i]**2-A[i]**2) for i in range(len(A))])
229
        zmax=np.array([R[i]-math.sqrt(R[i]**2-A[i]**2) for i in [0,1]])
230
        #zmax= int(math.sqrt(zmax[0]*zmax[1]))
231
        zmax=zmax.mean()
232
        #zmax = 5
233
        print(zmax)
234
        marge = 0.2
235
        # creating the stack and the surface
236
        s = (int(A[0]*2*(1+marge)), int(A[1]*2*(1+marge)), int(zmax*(1+2*marge)))
237
        cm = np.array(s)/2
238
        x = np.array(range(0,s[0]))
239
        y = np.array(range(0,s[1]))
240
        xx = x - cm[0]
241
        yy = y - cm[1]
242
        #xgrid, ygrid = np.meshgrid(xx, yy, sparse=True)  # make sparse output arrays
243
        #mask=(((xgrid**2)/float(A[0])**2+(ygrid**2)/float(A[1])**2)<1).astype('uint8')
244
        z = np.zeros((s[0],s[1]))
245
        stack= np.zeros(s).astype('uint8')
246
        for i in x:
247
                for j in range(0,s[1]):
248
                        if xx[i]**2/float(A[0])**2+yy[j]**2/float(A[1])**2<=1 :
249
                                zx = (math.sqrt(R[0]**2-xx[i]**2)-h[0])*(1-abs(yy[j])/A[1])
250
                                zy = (math.sqrt(R[1]**2-yy[j]**2)-h[1])*(1-abs(xx[i])/A[0])
251
                                z[i,j] = math.sqrt(zx*zy)
252
                                #z[i,j] = (zx+zy)/2
253
                                #z[i,j] = 5
254
                                stack[i,j,int(zmax*marge+z[i,j])]=1
255
        stack = SpatialImage(stack)
256
        stack.resolution = resolution
257
        return z, stack
258

    
259

    
260

    
261
def create_artificial_sepal_ellipse(AA, H, resolution):
262
        '''
263
        # A = parameters of an ellipse, as projected on xy plane (2d array)
264
        # R = curvature radius in directions x and y (2d array)
265
        # (A and R are given in micrometers)
266
        # resolution = voxelsize of the output stack
267
        '''
268
        A = np.array([AA[i]/resolution[i] for i in [0,1]])
269
        h = H/resolution[2]
270
        zmax=h
271
        marge = 0.2
272
        # creating the stack and the surface
273
        s = (int(A[0]*2*(1+marge)), int(A[1]*2*(1+marge)), int(zmax*(1+5*marge)))
274
        cm = np.array(s)/2
275
        x = np.array(range(0,s[0]))
276
        y = np.array(range(0,s[1]))
277
        xx = x - cm[0]
278
        yy = y - cm[1]
279
        #xgrid, ygrid = np.meshgrid(xx, yy, sparse=True)  # make sparse output arrays
280
        #mask=(((xgrid**2)/float(A[0])**2+(ygrid**2)/float(A[1])**2)<1).astype('uint8')
281
        z = np.zeros((s[0],s[1]))
282
        #z = -h*((xgrid**2)/float(A[0])**2+(ygrid**2)/float(A[1])**2)
283
        stack= np.zeros(s).astype('uint8')
284
        for i in x:
285
                for j in y:
286
                        if xx[i]**2/float(A[0])**2+yy[j]**2/float(A[1])**2<=1 :
287
                                z[i,j] = -h*((xx[i]**2)/float(A[0])**2+(yy[j]**2)/float(A[1])**2-1)
288
                                stack[i,j,int(zmax*4*marge+z[i,j])]=1
289
        stack = SpatialImage(stack)
290
        stack.voxelsize = resolution
291
        return z, stack
292

    
293
# -------------------------------------------------------------------
294

    
295
def read_curve(filename) :
296
        """
297
        Reads the coordinates of the point-list defining a 2D curve.
298
        **Returns**
299
        y : 2-column array
300
                defines a curve as an ordered list of points, 
301
                each row of the array represents a point on the curve and contains
302
                its 2D cartesian coordinates
303
        pixelsize : tuple (res0, res1) in micrometers
304
        """        
305
        x0 = []
306
        pixelsize = (1.0,1.0)
307
        for line in file(filename):
308
                if line[0] == "#" :
309
                        line = line.lstrip('# ')
310
                        line = line.rstrip('\n')
311
                        line_list = [float(x) for x in line.split(' ')]
312
                        pixelsize = (line_list[0], line_list[1])
313
                else :
314
                        line = line.rstrip('\n')
315
                        line_list = [float(x) for x in line.split(' ')]
316
                        x0.append(line_list)
317
        y = np.array(x0)
318
        return y, pixelsize
319

    
320

    
321

    
322
def distance(p1, p2):
323
        return np.sqrt((p1[0]-p2[0])**2+(p1[1]-p2[1])**2)
324

    
325
def distance_to_line(p1, p2, p0):
326
        '''
327
        gives the distance of point p0 to the line defined by points p1 and p2 (in 2d)
328
        '''
329
        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)
330

    
331
def curvature(p1,p2,p3):
332
        t1 = (p3[0]**2-p2[0]**2+p3[1]**2-p2[1]**2)/(2.0*(p3[1]-p2[1]))
333
        t2 = (p2[0]**2-p1[0]**2+p2[1]**2-p1[1]**2)/(2.0*(p2[1]-p1[1]))
334
        n1 = (p3[0]-p2[0])/(p3[1]-p2[1])
335
        n2 = (p2[0]-p1[0])/(p2[1]-p1[1])
336
        pcx = (t1-t2+p3[1]-p1[1])/(n1-n2)
337
        pc = [pcx, -n1*pcx+t1/2+p3[1]/2+p1[1]/2]
338
        R = distance(p1, pc)
339
        return 1.0/R, pc
340

    
341

    
342
def curvature2(p1,p2,p3):
343
        # http://www.ambrsoft.com/TrigoCalc/Circle3D.htm
344
        A = p1[0]*(p2[1]-p3[1])-p1[1]*(p2[0]-p3[0])+p2[0]*p3[1]-p3[0]*p2[1]
345
        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])
346
        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])
347
        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])
348
        x = -B/(2*A)
349
        y = C/(2*A)
350
        pc = [x, y]
351
        R = distance(p1, pc)
352
        return 1.0/R, pc
353

    
354

    
355
def curve_perle(y, first, last, step):
356
        yy=[]
357
        for i in range(first, last, step):
358
                if y[i][1]>0:
359
                        yy.append(y[i])
360
        if i<last:
361
                yy.append(y[last])
362
        return np.array(yy)
363

    
364

    
365

    
366
def compute_curvature_radius(x,y):
367
        # coordinates of the barycenter
368
        x_m = np.mean(x)
369
        y_m = np.mean(y)
370
        def calc_R(c):
371
                """ calculate the distance of each 2D points from the center c=(xc, yc) """
372
                return np.sqrt((x-c[0])**2 + (y-c[1])**2)
373
        #
374
        def calc_ecart(c):
375
                """ calculate the algebraic distance between the 2D points and the mean circle centered at c=(xc, yc) """
376
                Ri = calc_R(c)
377
                return Ri - Ri.mean()
378
        #
379
        center_estimate = x_m, y_m
380
        center_2, ier = optimize.leastsq(calc_ecart, center_estimate)
381
        #
382
        xc_2, yc_2 = center_2
383
        Ri_2       = calc_R(center_2)
384
        R_2        = Ri_2.mean()
385
        residu_2   = sum((Ri_2 - R_2)**2)
386
        pc=[xc_2, yc_2]
387
        return R_2, pc
388

    
389

    
390
def analyze_curve1(name, y, pixelsize, outfilename, graph_name='graph.png'):
391
        # isotropic pixels
392
        y[:,0] = y[:,0]*pixelsize[0]
393
        y[:,1] = y[:,1]*pixelsize[1]
394
        maxv = [y[:,i].max() for i in [0,1]]
395
        # find first and last points on the curve
396
        step = 5
397
        sep_indices = np.where(y[:,1])[0]
398
        first = sep_indices[0]#+step/2
399
        last = sep_indices[-1]#-step/2
400
        # compute flat length
401
        flatlength = distance(y[first],y[last])
402
        print("flat length =", flatlength," um")
403
        # compute curved length and height (maximal distance to the base)
404
        yy = curve_perle(y, first, last, step)
405
        length = 0
406
        height = 0
407
        height_index = 0
408
        p1 = yy[0]
409
        p2 = yy[-1]
410
        for i in range(0, len(yy)-1):
411
                length = length + distance(yy[i+1],yy[i])
412
                d = distance_to_line(p1, p2, yy[i])
413
                if d>height :
414
                        height = d
415
                        height_index = i
416
        print("length = ",length," um")
417
        print("height = ",height," um")
418
        middle_point = yy[int(len(yy)/2)]
419
        # compute curvature radius by fitting the sepal section to a circle
420
        yyy=y[first:last]
421
        R, pc = compute_curvature_radius(yyy[:,0],yyy[:,1])
422
        print("R=",R," um")
423
        # cutting curve in pieces in order to estimate curvature radius on portions of the curve
424
        slength=len(yyy)
425
        y21=yyy[0:int(slength/2)]
426
        y22=yyy[int(slength/2):slength]
427
        y41=yyy[0:int(slength/4)]
428
        y423=yyy[int(slength/4):3*int(slength/4)]
429
        y44=yyy[3*int(slength/4):slength]
430
        # and computing the curvature radius for each portion
431
        R21, pc = compute_curvature_radius(y21[:,0],y21[:,1])
432
        R22, pc = compute_curvature_radius(y22[:,0],y22[:,1])
433
        R41, pc = compute_curvature_radius(y41[:,0],y41[:,1])
434
        R423, pc = compute_curvature_radius(y423[:,0],y423[:,1])
435
        R44, pc = compute_curvature_radius(y44[:,0],y44[:,1])
436
        fig = plt.figure()
437
        plt.plot(yy[:,0], yy[:,1], 'bo')
438
        plt.plot(y[:,0], y[:,1], 'r')
439
        plt.plot(y[first][0], y[first][1], 'ro')
440
        plt.plot(middle_point[0], middle_point[1], 'ro')
441
        plt.plot(y[last][0], y[last][1], 'ro')
442
        plt.plot(yy[height_index][0], yy[height_index][1], 'go')
443
        plt.plot(pc[0], pc[1], 'bx')
444
        plt.gca().set_aspect('equal', adjustable='box')
445
        #plt.show()
446
        fig.savefig(graph_name)
447
        #plt.close()
448
        # write the data into a file
449
        FILE = open(outfilename,"a")
450
        FILE.write(name+';'+str(length)+';'+str(R)+';'+str(flatlength)+';'+str(height)+'\n')
451
        FILE.close()
452
        return length, flatlength, height, R, R21, R22, R41, R423, R44
453

    
454
def imsave2D(filename, matrix):
455
        fig = plt.figure()
456
        plt.gca().imshow(np.transpose(matrix), interpolation='none')
457
        fig.savefig(filename)
458
        return
459

    
460

    
461

    
462
def register_objects(img_flo, img_ref, preregisterd=True, ph=6, pl=2, es=5, fs=3, save_files=True, iterations=2):
463
        # -- "Specify paths to image files" --
464
        # ------------------------------------------------
465
        sequence_name = "register_"
466
        file_times = [1, 2]
467
        filenames = [sequence_name + str(t).zfill(2)  for t in file_times]
468
        list_images = [img_flo, img_ref]
469

    
470
        images = {}
471
        for i in [0,1]:
472
                images[filenames[i]] = list_images[i]
473

    
474
        rigid_images = {}
475
        rigid_transformations = {}
476
        affine_images = {}
477
        affine_transformations = {}
478
        registered_images = {}
479
        non_linear_transformations = {}
480
        [reference_filename, floating_filename, reference_time, floating_time] = [ filenames[0], filenames[1], file_times[0], file_times[1]]
481
        #for reference_filename, floating_filename, reference_time, floating_time, in zip(filenames[1:],filenames[:-1],file_times[1:],file_times[:-1]):
482
        print("================================")
483
        print("Registering ", floating_time, " on ", reference_time)
484
        print("================================")
485

    
486
        ###################################################
487
        # Output structure
488
        ###################################################
489

    
490
        namestring = "_ph"+str(ph)+"_pl"+str(pl)+"_es"+str(es)+"_fs"+str(fs)
491

    
492
        output_dirname = dirname + '/' + sequence_name + "_" + str(floating_time).zfill(2) + "_on_" + str(reference_time).zfill(2) + "" + namestring
493
        if not os.path.exists(output_dirname):
494
                os.makedirs(output_dirname)
495

    
496
        reference_img = images[reference_filename]
497
        floating_img = images[floating_filename]
498

    
499
        ####################################################################
500

    
501
        # Registration of the floating images on ref
502
        # -----------------------------------------------------
503
        
504
        if (not preregistered) :
505
                # A. Find optimised rigid transformations
506
                rigid_img, rigid_trsf = find_rigid_transfo2(reference_img, floating_img)
507
                rigid_images[floating_filename] = rigid_img
508
                rigid_transformations[floating_filename] = rigid_trsf
509
                
510
                if save_files:
511
                        # rigid-registered images
512
                        rigid_filename = output_dirname + '/' + floating_filename + "_rigid_on_" + str(reference_time).zfill(2) + ".inr.gz"
513
                        imsave(rigid_filename, rigid_img)
514

    
515
                        # optimised (with block-matching) rigid transformations
516
                        rigid_trsf_filename = output_dirname + '/tr_' + floating_filename + '_rigid.txt'
517
                        tfsave(rigid_trsf_filename, rigid_trsf)
518

    
519
                # B. Find optimised affine transformations (initialised by the rigid tfs computed above)
520
                affine_img, affine_trsf = find_affine_transfo(reference_img, floating_img, init_trsf=rigid_trsf)
521
                affine_images[floating_filename] = affine_img
522
                affine_transformations[floating_filename] = affine_trsf
523

    
524
                if save_files:
525
                        # affine-registered images
526
                        affine_filename = output_dirname + '/' + floating_filename + "_affine_on_" + str(reference_time).zfill(2) + ".inr.gz"
527
                        imsave(affine_filename, affine_img)
528

    
529
                        # optimised (with block-matching) affine transformations
530
                        affine_trsf_filename = output_dirname + '/tr_' + floating_filename + '_affine.txt'
531
                        tfsave(affine_filename, affine_trsf)
532
                floating_img0=affine_img
533
        else :
534
                floating_img0=floating_img
535
        # C. Find nonlinear transformations which register the affine-transformed images
536
        #registered_img, nl_trsf = find_nl_transfo(reference_img, affine_img, ph=ph, pl=pl, es=es, fs=fs)
537
        for it in range(iterations):
538
                registered_img, nl_trsf = find_nl_transfo(reference_img, floating_img0, ph=ph, pl=pl, es=es, fs=fs)
539
                registered_images[floating_filename] = registered_img
540
                non_linear_transformations[floating_filename] = nl_trsf
541

    
542
                # paths to nonlinearly registered images
543
                registered_filename = output_dirname + '/' + floating_filename + "_registered_on_" + str(reference_time).zfill(2) + "_it"+str(it)+".inr.gz"
544
                imsave(registered_filename, registered_img)
545
                floating_img0=registered_img
546

    
547
                if save_files:
548
                        # non-linear transformations
549
                        nl_trsf_filename = output_dirname + '/' + floating_filename + "_it"+str(it)+"_vectorfield.inr.gz"
550
                        save_trsf(nl_trsf, nl_trsf_filename, compress=True)
551
        return registered_img
552