Coverage for /usr/local/lib/python3.8/site-packages/spam/helpers/tsvio.py: 97%
352 statements
« prev ^ index » next coverage.py v7.2.3, created at 2023-11-22 13:26 +0000
« prev ^ index » next coverage.py v7.2.3, created at 2023-11-22 13:26 +0000
1"""
2Library of SPAM functions for reading and writing TSV files.
3Copyright (C) 2020 SPAM Contributors
5This program is free software: you can redistribute it and/or modify it
6under the terms of the GNU General Public License as published by the Free
7Software Foundation, either version 3 of the License, or (at your option)
8any later version.
10This program is distributed in the hope that it will be useful, but WITHOUT
11ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13more details.
15You should have received a copy of the GNU General Public License along with
16this program. If not, see <http://www.gnu.org/licenses/>.
17"""
19import numpy
20import os
23def writeRegistrationTSV(fileName, regCentre, regReturns):
24 '''
25 This function writes a correctly formatted TSV file from the result of a single `register()` call, allowing it to be used as an initial registration.
27 Parameters
28 ----------
29 fileName : string
30 The file name for output, suggestion: it should probably end with ".tsv"
32 regCentre : 3-component list
33 A list containing the point at which `Phi` has been measured.
34 This is typically the middle of the image, and can be obtained as follows:
35 (numpy.array( im.shape )-1)/2.0
36 The conversion to a numpy array is necessary, since tuples cannot be divided by a number directly.
38 regReturns : dictionary
39 This should be the return dictionary from `register`.
40 From this dictionary will be extracted: 'Phi', 'error', 'iterations', 'returnStatus', 'deltaPhiNorm'
42 '''
43 try:
44 regPhi = regReturns['Phi']
45 except:
46 print("spam.helpers.tsvio.writeRegistrationTSV(): Attempting to read old format")
47 regPhi = regReturns['PhiCentre']
49 # catch 2D images
50 if len(regCentre) == 2:
51 regCentre = [0, regCentre[0], regCentre[1]]
53 # Make one big array for writing:
54 header = "NodeNumber\tZpos\tYpos\tXpos\tFzz\tFzy\tFzx\tZdisp\tFyz\tFyy\tFyx\tYdisp\tFxz\tFxy\tFxx\tXdisp\terror\titerations\treturnStatus\tdeltaPhiNorm"
55 try:
56 outMatrix = numpy.array([[1],
57 [regCentre[0]],
58 [regCentre[1]],
59 [regCentre[2]],
60 [regPhi[0, 0]],
61 [regPhi[0, 1]],
62 [regPhi[0, 2]],
63 [regPhi[0, 3]],
64 [regPhi[1, 0]],
65 [regPhi[1, 1]],
66 [regPhi[1, 2]],
67 [regPhi[1, 3]],
68 [regPhi[2, 0]],
69 [regPhi[2, 1]],
70 [regPhi[2, 2]],
71 [regPhi[2, 3]],
72 [regReturns['error']],
73 [regReturns['iterations']],
74 [regReturns['returnStatus']],
75 [regReturns['deltaPhiNorm']]])
76 except:
77 print("spam.helpers.tsvio.writeRegistrationTSV(): Attempting to read old format")
78 outMatrix = numpy.array([[1],
79 [regCentre[0]],
80 [regCentre[1]],
81 [regCentre[2]],
82 [regPhi[0, 0]],
83 [regPhi[0, 1]],
84 [regPhi[0, 2]],
85 [regPhi[0, 3]],
86 [regPhi[1, 0]],
87 [regPhi[1, 1]],
88 [regPhi[1, 2]],
89 [regPhi[1, 3]],
90 [regPhi[2, 0]],
91 [regPhi[2, 1]],
92 [regPhi[2, 2]],
93 [regPhi[2, 3]],
94 [regReturns['error']],
95 [regReturns['iterationNumber']],
96 [regReturns['returnStatus']],
97 [regReturns['deltaPhiNorm']]])
99 numpy.savetxt(fileName,
100 outMatrix.T,
101 fmt='%.7f',
102 delimiter='\t',
103 newline='\n',
104 comments='',
105 header=header)
108def writeStrainTSV(fileName, points, decomposedFfield, firstColumn="StrainPointNumber", startRow=0):
109 """
110 This function writes strains to a TSV file, hiding the complexity of counting and naming columns
112 Parameters
113 ----------
114 fileName : string
115 fileName including full path and .tsv at the end to write
117 points : Nx3 numpy array
118 Points at which the strain is defined
120 decomposedFfield : dictionary
121 Dictionary containing strain components as per output from spam.deformation.FfieldRegularQ8, FfieldRegularGeers or FfieldBagi
123 firstColumn : string, optional
124 How to name the first column (series number) of the TSV
125 Default = "StrainPointNumber"
127 startRow : int, optional
128 Are your points and strains offset from zero? Offset TSV by adding blank lines, don't use this if you don't know what you're doing
129 Default = 0
131 Returns
132 -------
133 None
134 """
135 # This is the minimum header for everyone
136 header = "{}\tZpos\tYpos\tXpos".format(firstColumn)
138 # Allocate minimum output array
139 outMatrix = numpy.array([numpy.arange(points.shape[0]),
140 points[:, 0],
141 points[:, 1],
142 points[:, 2]]).T
144 nCols = 4
146 for component in decomposedFfield.keys():
147 if component == 'vol' or component == 'dev' or component == 'volss' or component == 'devss':
148 header = header + "\t{}".format(component)
149 outMatrix = numpy.hstack([outMatrix, numpy.array([decomposedFfield[component].ravel()]).T])
150 nCols += 1
152 if component == 'r' or component == 'z':
153 for n, di in enumerate(['z', 'y', 'x']):
154 header = header + "\t{}{}".format(component, di)
155 outMatrix = numpy.hstack([outMatrix, numpy.array([decomposedFfield[component].reshape(-1,3)[:,n].ravel()]).T])
156 nCols += 1
158 if component == 'e' or component == 'U':
159 for n, di in enumerate(['z', 'y', 'x']):
160 for m, dj in enumerate(['z', 'y', 'x']):
161 if m>=n:
162 header = header + "\t{}{}{}".format(component, di, dj)
163 outMatrix = numpy.hstack([outMatrix, numpy.array([decomposedFfield[component].reshape(-1,3,3)[:,n,m].ravel()]).T])
164 nCols += 1
166 # This is mostly for discrete Strains, where we can avoid or not the zero-numbered grain
167 if startRow > 0:
168 for i in range(startRow):
169 header = header+'\n0.0'
170 for j in range(1,nCols):
171 header = header+'\t0.0'
173 numpy.savetxt(fileName,
174 outMatrix,
175 delimiter='\t',
176 fmt='%.7f',
177 newline='\n',
178 comments='',
179 header=header)
182def readCorrelationTSV(fileName, fieldBinRatio=1.0, readOnlyDisplacements=False, readConvergence=True, readPixelSearchCC=False, readError=False, readLabelDilate=False):
183 """
184 This function reads a TSV file containing a field of deformation functions **Phi** at one or a number of points.
185 This is typically the output of the spam-ldic and spam-ddic scripts,
186 or anything written by `writeRegistrationTSV`.
188 Parameters
189 ----------
190 fileName : string
191 Name of the file
193 fieldBinRatio : int, optional
194 if the input field is refer to a binned version of the image
195 `e.g.`, if ``fieldBinRatio = 2`` the field_name values have been calculated
196 for an image half the size of what the returned PhiField is referring to
197 Default = 1.0
199 readOnlyDisplacements : bool, optional
200 Read "zDisp", "yDisp", "xDisp", displacements from the TSV file, and not the rest of the Phi matrix?
201 Default = False
203 readConvergence : bool, optional
204 Read "returnStatus", "deltaPhiNorm", "iterations", from file
205 Default = True
207 readPixelSearchCC : bool, optional
208 Read "pixelSearchCC" from file
209 Default = False
211 readError : bool, optional
212 Read '"error"from file
213 Default = False
215 readLabelDilate : bool, optional
216 Read "LabelDilate" from file
217 Default = False
219 Returns
220 -------
221 Dictionary containing:
222 fieldDims: 1x3 array of the field dimensions (ZYX) (for a regular grid DIC result)
224 numberOfLabels: number of labels (for a discrete DIC result)
226 fieldCoords: nx3 array of n points coordinates (ZYX)
228 PhiField: nx4x4 array of n points transformation operators
230 returnStatus: nx1 array of n points returnStatus from the correlation
232 deltaPhiNorm: nx1 array of n points deltaPhiNorm from the correlation
234 iterations: nx1 array of n points iterations from the correlation
236 pixelSearchCC: nx1 array of n points pixelSearchCC from the correlation
238 error: nx1 array of n points error from the correlation
240 labelDilate: nx1 array of n points labelDilate from the correlation
242 """
243 if not os.path.isfile(fileName):
244 print("\n\tspam.tsvio.readCorrelationTSV(): {} is not a file. Exiting.".format(fileName))
245 return
247 f = numpy.genfromtxt(fileName, delimiter="\t", names=True)
248 # RS = []
249 # deltaPhiNorm = []
250 # pixelSearchCC = []
252 # If this is a one-line TSV file (an initial registration for example)
253 if f.size == 1:
254 #print("\tspam.tsvio.readCorrelationTSV(): {} seems only to have one line.".format(fileName))
255 nPoints = 1
256 numberOfLabels = 1
257 fieldDims = [1, 1, 1]
259 # Sort out the field coordinates
260 fieldCoords = numpy.zeros((nPoints, 3))
261 fieldCoords[:, 0] = f['Zpos'] * fieldBinRatio
262 fieldCoords[:, 1] = f['Ypos'] * fieldBinRatio
263 fieldCoords[:, 2] = f['Xpos'] * fieldBinRatio
265 # Sort out the components of Phi
266 PhiField = numpy.zeros((nPoints, 4, 4))
267 PhiField[0] = numpy.eye(4)
269 # Fill in displacements
270 try:
271 PhiField[0, 0, 3] = f['Zdisp'] * fieldBinRatio
272 PhiField[0, 1, 3] = f['Ydisp'] * fieldBinRatio
273 PhiField[0, 2, 3] = f['Xdisp'] * fieldBinRatio
274 except ValueError:
275 PhiField[0, 0, 3] = f['F14'] * fieldBinRatio
276 PhiField[0, 1, 3] = f['F24'] * fieldBinRatio
277 PhiField[0, 2, 3] = f['F34'] * fieldBinRatio
279 if not readOnlyDisplacements:
280 try:
281 # Get non-displacement components
282 PhiField[0, 0, 0] = f['Fzz']
283 PhiField[0, 0, 1] = f['Fzy']
284 PhiField[0, 0, 2] = f['Fzx']
285 PhiField[0, 1, 0] = f['Fyz']
286 PhiField[0, 1, 1] = f['Fyy']
287 PhiField[0, 1, 2] = f['Fyx']
288 PhiField[0, 2, 0] = f['Fxz']
289 PhiField[0, 2, 1] = f['Fxy']
290 PhiField[0, 2, 2] = f['Fxx']
291 except:
292 print("spam.helpers.tsvio.readCorrelationTSV(): Attempting to read old format, please update your TSV file (F11 should be Fzz and so on)")
293 # Get non-displacement components
294 PhiField[0, 0, 0] = f['F11']
295 PhiField[0, 0, 1] = f['F12']
296 PhiField[0, 0, 2] = f['F13']
297 PhiField[0, 1, 0] = f['F21']
298 PhiField[0, 1, 1] = f['F22']
299 PhiField[0, 1, 2] = f['F23']
300 PhiField[0, 2, 0] = f['F31']
301 PhiField[0, 2, 1] = f['F32']
302 PhiField[0, 2, 2] = f['F33']
304 if readConvergence:
305 try:
306 # Return ReturnStatus, SubPixelDeltaFnorm, SubPixelIterations
307 RS = f['returnStatus']
308 deltaPhiNorm = f['deltaPhiNorm']
309 iterations = f['iterations']
310 except:
311 print("spam.helpers.tsvio.readCorrelationTSV(): Attempting to read old format, please update your TSV file (SubPix should be )")
312 # Return ReturnStatus, SubPixelDeltaFnorm, SubPixelIterations
313 RS = f['SubPixReturnStat']
314 deltaPhiNorm = f['SubPixDeltaPhiNorm']
315 iterations = f['SubPixIterations']
316 if readError:
317 try:
318 error = f['error']
319 except ValueError:
320 pass
321 # Return pixelSearchCC
322 if readPixelSearchCC:
323 pixelSearchCC = numpy.zeros(nPoints)
324 try:
325 pixelSearchCC = f['pixelSearchCC']
326 except ValueError:
327 pass
329 # Return error
330 if readError:
331 error = numpy.zeros(nPoints)
332 try:
333 error = f['error']
334 except ValueError:
335 pass
336 # Return labelDilate
337 if readLabelDilate:
338 labelDilate = numpy.zeros(nPoints)
339 try:
340 labelDilate = f['LabelDilate']
341 except ValueError:
342 pass
345 pixelSearchCC = 0
347 # there is more than one line in the TSV file -- a field -- typical case
348 else:
349 nPoints = f.size
351 # check if it is a ddic or ldic result
352 try:
353 f["NodeNumber"]
354 # it's a local DIC result with grid points regularly spaced
355 DICgrid = True
356 DICdiscrete = False
357 except ValueError:
358 # it's a discrete DIC result with values in each label's centre of mass
359 DICdiscrete = True
360 DICgrid = False
362 # Sort out the field coordinates
363 fieldCoords = numpy.zeros((nPoints, 3))
364 fieldCoords[:, 0] = f['Zpos'] * fieldBinRatio
365 fieldCoords[:, 1] = f['Ypos'] * fieldBinRatio
366 fieldCoords[:, 2] = f['Xpos'] * fieldBinRatio
368 if DICgrid:
369 fieldDims = numpy.array([len(numpy.unique(f['Zpos'])), len(numpy.unique(f['Ypos'])), len(numpy.unique(f['Xpos']))])
370 numberOfLabels = 0
371 print("\tspam.tsvio.readCorrelationTSV(): Field dimensions: {}".format(fieldDims))
372 elif DICdiscrete:
373 numberOfLabels = len(f["Label"])
374 fieldDims = [0, 0, 0]
375 print("\tspam.tsvio.readCorrelationTSV(): Number of labels: {}".format(numberOfLabels))
377 # create ReturnStatus and deltaPhiNorm matrices if asked
378 if readConvergence:
379 try:
380 RS = numpy.zeros(nPoints)
381 RS[:] = f[:]['returnStatus']
382 deltaPhiNorm = numpy.zeros(nPoints)
383 deltaPhiNorm = f[:]['deltaPhiNorm']
384 iterations = numpy.zeros(nPoints)
385 iterations = f[:]['iterations']
386 except:
387 print("spam.helpers.tsvio.readCorrelationTSV(): Attempting to read old format, please update your TSV file")
388 RS = numpy.zeros(nPoints)
389 RS[:] = f[:]['SubPixReturnStat']
390 deltaPhiNorm = numpy.zeros(nPoints)
391 deltaPhiNorm = f[:]['SubPixDeltaPhiNorm']
392 iterations = numpy.zeros(nPoints)
393 iterations = f[:]['SubPixIterations']
395 # Return pixelSearchCC
396 if readPixelSearchCC:
397 pixelSearchCC = numpy.zeros(nPoints)
398 try:
399 pixelSearchCC = f[:]['pixelSearchCC']
400 except ValueError:
401 pass
403 # Return error
404 if readError:
405 error = numpy.zeros(nPoints)
406 try:
407 error = f[:]['error']
408 except ValueError:
409 pass
410 # Return labelDilate
411 if readLabelDilate:
412 labelDilate = numpy.zeros(nPoints)
413 try:
414 labelDilate = f[:]['LabelDilate']
415 except ValueError:
416 pass
418 # Sort out the components of Phi
419 PhiField = numpy.zeros((nPoints, 4, 4))
420 for n in range(nPoints):
421 # Initialise with Identity matrix
422 PhiField[n] = numpy.eye(4)
424 # Fill in displacements
425 try:
426 PhiField[n, 0, 3] = f[n]['Zdisp'] * fieldBinRatio
427 PhiField[n, 1, 3] = f[n]['Ydisp'] * fieldBinRatio
428 PhiField[n, 2, 3] = f[n]['Xdisp'] * fieldBinRatio
429 except ValueError:
430 PhiField[n, 0, 3] = f[n]['F14'] * fieldBinRatio
431 PhiField[n, 1, 3] = f[n]['F24'] * fieldBinRatio
432 PhiField[n, 2, 3] = f[n]['F34'] * fieldBinRatio
434 if not readOnlyDisplacements:
435 try:
436 # Get non-displacement components
437 PhiField[n, 0, 0] = f[n]['Fzz']
438 PhiField[n, 0, 1] = f[n]['Fzy']
439 PhiField[n, 0, 2] = f[n]['Fzx']
440 PhiField[n, 1, 0] = f[n]['Fyz']
441 PhiField[n, 1, 1] = f[n]['Fyy']
442 PhiField[n, 1, 2] = f[n]['Fyx']
443 PhiField[n, 2, 0] = f[n]['Fxz']
444 PhiField[n, 2, 1] = f[n]['Fxy']
445 PhiField[n, 2, 2] = f[n]['Fxx']
446 except:
447 print("spam.helpers.tsvio.readCorrelationTSV(): Attempting to read old format, please update your TSV file (F11 should be Fzz and so on)")
448 # Get non-displacement components
449 PhiField[n, 0, 0] = f[n]['F11']
450 PhiField[n, 0, 1] = f[n]['F12']
451 PhiField[n, 0, 2] = f[n]['F13']
452 PhiField[n, 1, 0] = f[n]['F21']
453 PhiField[n, 1, 1] = f[n]['F22']
454 PhiField[n, 1, 2] = f[n]['F23']
455 PhiField[n, 2, 0] = f[n]['F31']
456 PhiField[n, 2, 1] = f[n]['F32']
457 PhiField[n, 2, 2] = f[n]['F33']
459 output = {"fieldDims": fieldDims,
460 "numberOfLabels": numberOfLabels,
461 "fieldCoords": fieldCoords}
462 if readConvergence:
463 output.update({"returnStatus": RS,
464 "deltaPhiNorm": deltaPhiNorm,
465 "iterations": iterations})
466 if readError:
467 output.update({"error": error})
468 if readPixelSearchCC:
469 output.update({"pixelSearchCC": pixelSearchCC})
470 if readLabelDilate:
471 output.update({"LabelDilate": labelDilate})
473 if readOnlyDisplacements:
474 output.update({"displacements": PhiField[:, 0:3, -1]})
475 else:
476 output.update({"PhiField": PhiField})
478 return output
481def readStrainTSV(fileName):
482 """
483 This function reads a strain TSV file written by `spam-discreteStrain` or `spam-regularStrain`
485 Parameters
486 ----------
487 fileName : string
488 Name of the file
490 Returns
491 -------
492 Dictionary containing:
494 fieldDims: 1x3 array of the field dimensions (ZYX)
496 fieldCoords : nx3 array of the field coordinates (ZYX)
498 numberOfLabels: number of labels (for a discrete strain result)
500 vol: nx1 array of n points with volumetric strain computed under the hypotesis of large strains (if computed)
502 dev: nx1 array of n points with deviatoric strain computed under the hypotesis of large strains (if computed)
504 volss: nx1 array of n points with volumetric strain computed under the hypotesis of small strains (if computed)
506 devss: nx1 array of n points with deviatoric strain computed under the hypotesis of small strains (if computed)
508 r : nx3 array of n points with the components of the rotation vector (if computed)
510 z : nx3 array of n points with the components of the zoom vector (if computed)
512 U : nx3x3 array of n points with the components of the right-hand stretch tensor (if computed)
514 e : nx3x3 array of n points with the components of the strain tensor in small strains (if computed)
516 """
518 if not os.path.isfile(fileName):
519 print("\n\tspam.tsvio.readStrainTSV(): {} is not a file. Exiting.".format(fileName))
520 return
521 #Read the TSV
522 f = numpy.genfromtxt(fileName, delimiter="\t", names=True)
524 #Number of points
525 nPoints = f.size
527 #Get keys from file
528 keys = f.dtype.names
530 #Create empyt dictionary to be filled
531 output = {}
533 #Read and add the label coordinates
534 fieldCoords = numpy.zeros((nPoints, 3))
535 fieldCoords[:, 0] = f['Zpos']
536 fieldCoords[:, 1] = f['Ypos']
537 fieldCoords[:, 2] = f['Xpos']
538 output['fieldCoords'] = fieldCoords
540 #Check if we are working with a regular grid or discrete
541 grid = False
542 discrete = False
543 if numpy.abs(fieldCoords[2,0] - fieldCoords[3,0]) == 0:
544 grid = True
545 else:
546 discrete = True
548 if grid:
549 fieldDims = numpy.array([len(numpy.unique(f['Zpos'])), len(numpy.unique(f['Ypos'])), len(numpy.unique(f['Xpos']))])
550 output['fieldDims'] = fieldDims
551 output['numberOfLabels'] = 0
552 else:
553 output['fieldDims'] = [0, 0, 0]
554 output['numberOfLabels'] = nPoints
556 #Check for all the possible keys
557 if 'vol' in keys:
558 volStrain = numpy.zeros((nPoints, 1))
559 volStrain[:, 0] = f['vol']
560 output['vol'] = volStrain
562 if 'dev' in keys:
563 devStrain = numpy.zeros((nPoints, 1))
564 devStrain[:, 0] = f['dev']
565 output['dev'] = devStrain
567 if 'volss' in keys:
568 volss = numpy.zeros((nPoints, 1))
569 volss[:, 0] = f['volss']
570 output['volss'] = volss
572 if 'devss' in keys:
573 devss = numpy.zeros((nPoints, 1))
574 devss[:, 0] = f['devss']
575 output['devss'] = devss
577 if 'rz' in keys:
578 r = numpy.zeros((nPoints, 3))
579 r[:, 0] = f['rz']
580 r[:, 1] = f['ry']
581 r[:, 2] = f['rx']
582 output['r'] = r
584 if 'zz' in keys:
585 # Zooms, these are very badly named like this
586 z = numpy.zeros((nPoints, 3))
587 z[:, 0] = f['zz']
588 z[:, 1] = f['zy']
589 z[:, 2] = f['zx']
590 output['z'] = z
592 if 'Uzz' in keys:
593 # Symmetric, so fill in both sides
594 U = numpy.zeros((nPoints, 3, 3))
595 U[:, 0, 0] = f['Uzz']
596 U[:, 1, 1] = f['Uyy']
597 U[:, 2, 2] = f['Uxx']
598 U[:, 0, 1] = f['Uzy']
599 U[:, 1, 0] = f['Uzy']
600 U[:, 0, 2] = f['Uzx']
601 U[:, 2, 0] = f['Uzx']
602 U[:, 1, 2] = f['Uyx']
603 U[:, 2, 1] = f['Uyx']
604 output['U'] = U
606 if 'ezz' in keys:
607 # Symmetric, so fill in both sides
608 e = numpy.zeros((nPoints, 3, 3))
609 e[:, 0, 0] = f['ezz']
610 e[:, 1, 1] = f['eyy']
611 e[:, 2, 2] = f['exx']
612 e[:, 0, 1] = f['ezy']
613 e[:, 1, 0] = f['ezy']
614 e[:, 0, 2] = f['ezx']
615 e[:, 2, 0] = f['ezx']
616 e[:, 1, 2] = f['eyx']
617 e[:, 2, 1] = f['eyx']
618 output['e'] = e
620 return output
623def TSVtoTIFF(fileName, fieldBinRatio=1.0, lab=None, returnRS=False, outDir=None, prefix=None):
624 '''
625 This function converts a TSV file (typically the output of spam-ldic and spam-ddic scripts)
626 to a tiff file for visualising the deformation field.
628 Parameters
629 ----------
630 fileName : string
631 Name of the file
633 fieldBinRatio : int, optional
634 if the input field is refer to a binned version of the image
635 `e.g.`, if ``fieldBinRatio = 2`` the field_name values have been calculated
636 for an image half the size of what the returned PhiField is referring to
637 Default = 1.0
639 lab : 3D numpy array, optional
640 The labelled image of the reference state. Highly recommended argument in case of a discrete correlation result.
641 Default = None
643 returnRS : bool, optional
644 if True: will return the returnStatus of the correlation as a tiff file
645 Default = False
647 outDir : string, optional
648 Output directory
649 Default is directory of the input field file
651 prefix : string, optional
652 Prefix for output files
653 Default is the basename of the input field file (without extension)
654 '''
656 import tifffile
657 # use the helper function to read the TSV file
658 fi = readCorrelationTSV(fileName, fieldBinRatio=fieldBinRatio, readOnlyDisplacements=True, readConvergence=returnRS)
659 displacements = fi["displacements"]
660 PhiComponents = [['Zdisp', 0],
661 ['Ydisp', 1],
662 ['Xdisp', 2]]
664 # set output directory if none
665 if outDir is None:
666 if os.path.dirname(fileName) == "":
667 outDir = "./"
668 else:
669 outDir = os.path.dirname(fileName)
670 else:
671 os.makedirs(outDir)
673 # output file name prefix
674 if prefix is None:
675 prefix = os.path.splitext(os.path.basename(fileName))[0]
677 # check if it is a ddic result
678 if fi["numberOfLabels"] != 0:
679 if lab:
680 labelled = tifffile.imread(lab)
681 import spam.label
683 for component in PhiComponents:
684 tifffile.imwrite("{}/{}-{}.tif".format(outDir, prefix, component[0]),
685 spam.label.convertLabelToFloat(labelled, displacements[:, component[1]]).astype('<f4'))
686 if returnRS:
687 tifffile.imwrite("{}/{}-RS.tif".format(outDir, prefix),
688 spam.label.convertLabelToFloat(labelled, fi["returnStatus"]).astype('<f4'))
689 else:
690 print("\tspam.tsvio.TSVtoTIFF(): The labelled image of the reference state is needed as input. Exiting.")
691 return
693 # if not, is a ldic result
694 else:
695 dims = fi["fieldDims"]
697 for component in PhiComponents:
698 tifffile.imwrite("{}/{}-{}.tif".format(outDir, prefix, component[0]),
699 displacements[:, component[1]].reshape(dims).astype('<f4'))
701 if returnRS:
702 tifffile.imwrite("{}/{}-RS.tif".format(outDir, prefix),
703 fi["returnStatus"].reshape(dims).astype('<f4'))
706def TSVtoVTK(fileName, fieldBinRatio=1.0, pixelSize=1.0, returnRS=False, outDir=None, prefix=None):
707 '''
708 This function converts a TSV file (typically the output of the ldic and ddic scripts)
709 to a VTK file for visualising the deformation field.
711 Parameters
712 ----------
713 fileName : string
714 Name of the file
716 fieldBinRatio : int, optional
717 if the input field is refer to a binned version of the image
718 `e.g.`, if ``fieldBinRatio = 2`` the field values have been calculated
719 for an image half the size of what the returned PhiField is referring to
720 Default = 1.0
722 pixelSize: float
723 physical size of a pixel (i.e. 1mm/px)
724 Default = 1.0
726 returnRS : bool, optional
727 if True: will return the SubPixelReturnStatus of the correlation
728 Default = False
730 outDir : string
731 Output directory
732 Default is directory of the input field file
734 prefix : string
735 Prefix for output files
736 Default is the basename of the input field file (without extension)
737 '''
738 import spam.helpers
739 # use the helper function to read the TSV file
740 fi = readCorrelationTSV(fileName, fieldBinRatio=fieldBinRatio)
741 PhiField = fi["PhiField"]
743 # set output directory if none
744 if outDir is None:
745 if os.path.dirname(fileName) == "":
746 outDir = "./"
747 else:
748 outDir = os.path.dirname(fileName)
749 else:
750 os.makedirs(outDir)
752 # output file name prefix
753 if prefix is None:
754 prefix = os.path.splitext(os.path.basename(fileName))[0]
756 # check if it is a ddic result
757 if fi["numberOfLabels"] != 0:
758 coords = fi["fieldCoords"][1:] * pixelSize
759 if not returnRS:
760 pointData = {"displacements": PhiField[1:, :-1, 3] * pixelSize}
762 else:
763 pointData = {"displacements": PhiField[1:, :-1, 3] * pixelSize,
764 "returnStatus": fi["returnStatus"][1:]}
766 spam.helpers.writeGlyphsVTK(coords, pointData, fileName="{}/{}.vtk".format(outDir, prefix))
768 # if not, is a ldic result
769 else:
770 dims = fi["fieldDims"]
771 coords = fi["fieldCoords"] * pixelSize
772 aspectRatio = numpy.array([numpy.unique(coords[:, i])[1] - numpy.unique(coords[:, i])[0] if len(numpy.unique(coords[:, i])) > 1 else numpy.unique(coords[:, i])[0] for i in range(3)])
773 origin = coords[0] - aspectRatio/2.0
775 if not returnRS:
776 cellData = {"displacements": (PhiField[:, :-1, 3] * pixelSize).reshape((dims[0], dims[1], dims[2], 3))}
778 else:
779 cellData = {"displacements": (PhiField[:, :-1, 3] * pixelSize).reshape((dims[0], dims[1], dims[2], 3)),
780 "returnStatus": fi["returnStatus"].reshape(dims[0], dims[1], dims[2])}
782 spam.helpers.writeStructuredVTK(aspectRatio=aspectRatio, origin = origin, cellData=cellData, fileName="{}/{}.vtk".format(outDir, prefix))