Coverage for /usr/local/lib/python3.10/site-packages/spam/helpers/tsvio.py: 97%
353 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-24 17:26 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-04-24 17: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 os
21import numpy
24def writeRegistrationTSV(fileName, regCentre, regReturns):
25 """
26 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.
28 Parameters
29 ----------
30 fileName : string
31 The file name for output, suggestion: it should probably end with ".tsv"
33 regCentre : 3-component list
34 A list containing the point at which `Phi` has been measured.
35 This is typically the middle of the image, and can be obtained as follows:
36 (numpy.array( im.shape )-1)/2.0
37 The conversion to a numpy array is necessary, since tuples cannot be divided by a number directly.
39 regReturns : dictionary
40 This should be the return dictionary from `register`.
41 From this dictionary will be extracted: 'Phi', 'error', 'iterations', 'returnStatus', 'deltaPhiNorm'
43 """
44 try:
45 regPhi = regReturns["Phi"]
46 except:
47 print("spam.helpers.tsvio.writeRegistrationTSV(): Attempting to read old format")
48 regPhi = regReturns["PhiCentre"]
50 # catch 2D images
51 if len(regCentre) == 2:
52 regCentre = [0, regCentre[0], regCentre[1]]
54 # Make one big array for writing:
55 header = "NodeNumber\tZpos\tYpos\tXpos\tFzz\tFzy\tFzx\tZdisp\tFyz\tFyy\tFyx\tYdisp\tFxz\tFxy\tFxx\tXdisp\terror\titerations\treturnStatus\tdeltaPhiNorm"
56 try:
57 outMatrix = numpy.array(
58 [
59 [1],
60 [regCentre[0]],
61 [regCentre[1]],
62 [regCentre[2]],
63 [regPhi[0, 0]],
64 [regPhi[0, 1]],
65 [regPhi[0, 2]],
66 [regPhi[0, 3]],
67 [regPhi[1, 0]],
68 [regPhi[1, 1]],
69 [regPhi[1, 2]],
70 [regPhi[1, 3]],
71 [regPhi[2, 0]],
72 [regPhi[2, 1]],
73 [regPhi[2, 2]],
74 [regPhi[2, 3]],
75 [regReturns["error"]],
76 [regReturns["iterations"]],
77 [regReturns["returnStatus"]],
78 [regReturns["deltaPhiNorm"]],
79 ]
80 )
81 except:
82 print("spam.helpers.tsvio.writeRegistrationTSV(): Attempting to read old format")
83 outMatrix = numpy.array(
84 [
85 [1],
86 [regCentre[0]],
87 [regCentre[1]],
88 [regCentre[2]],
89 [regPhi[0, 0]],
90 [regPhi[0, 1]],
91 [regPhi[0, 2]],
92 [regPhi[0, 3]],
93 [regPhi[1, 0]],
94 [regPhi[1, 1]],
95 [regPhi[1, 2]],
96 [regPhi[1, 3]],
97 [regPhi[2, 0]],
98 [regPhi[2, 1]],
99 [regPhi[2, 2]],
100 [regPhi[2, 3]],
101 [regReturns["error"]],
102 [regReturns["iterationNumber"]],
103 [regReturns["returnStatus"]],
104 [regReturns["deltaPhiNorm"]],
105 ]
106 )
108 numpy.savetxt(fileName, outMatrix.T, fmt="%.7f", delimiter="\t", newline="\n", comments="", header=header)
111def writeStrainTSV(fileName, points, decomposedFfield, firstColumn="StrainPointNumber", startRow=0):
112 """
113 This function writes strains to a TSV file, hiding the complexity of counting and naming columns
115 Parameters
116 ----------
117 fileName : string
118 fileName including full path and .tsv at the end to write
120 points : Nx3 numpy array
121 Points at which the strain is defined
123 decomposedFfield : dictionary
124 Dictionary containing strain components as per output from spam.deformation.FfieldRegularQ8, FfieldRegularGeers or FfieldBagi
126 firstColumn : string, optional
127 How to name the first column (series number) of the TSV
128 Default = "StrainPointNumber"
130 startRow : int, optional
131 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
132 Default = 0
134 Returns
135 -------
136 None
137 """
138 # This is the minimum header for everyone
139 header = "{}\tZpos\tYpos\tXpos".format(firstColumn)
141 # Allocate minimum output array
142 outMatrix = numpy.array([numpy.arange(points.shape[0]), points[:, 0], points[:, 1], 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, outMatrix, delimiter="\t", fmt="%.7f", newline="\n", comments="", header=header)
176def readCorrelationTSV(fileName, fieldBinRatio=1.0, readOnlyDisplacements=False, readConvergence=True, readPixelSearchCC=False, readError=False, readLabelDilate=False, verbose=True):
177 """
178 This function reads a TSV file containing a field of deformation functions **Phi** at one or a number of points.
179 This is typically the output of the spam-ldic and spam-ddic scripts,
180 or anything written by `writeRegistrationTSV`.
182 Parameters
183 ----------
184 fileName : string
185 Name of the file
187 fieldBinRatio : int, optional
188 if the input field is refer to a binned version of the image
189 `e.g.`, if ``fieldBinRatio = 2`` the field_name values have been calculated
190 for an image half the size of what the returned PhiField is referring to
191 Default = 1.0
193 readOnlyDisplacements : bool, optional
194 Read "zDisp", "yDisp", "xDisp", displacements from the TSV file, and not the rest of the Phi matrix?
195 Default = False
197 readConvergence : bool, optional
198 Read "returnStatus", "deltaPhiNorm", "iterations", from file
199 Default = True
201 readPixelSearchCC : bool, optional
202 Read "pixelSearchCC" from file
203 Default = False
205 readError : bool, optional
206 Read '"error"from file
207 Default = False
209 readLabelDilate : bool, optional
210 Read "LabelDilate" from file
211 Default = False
213 Returns
214 -------
215 Dictionary containing:
216 fieldDims: 1x3 array of the field dimensions (ZYX) (for a regular grid DIC result)
218 numberOfLabels: number of labels (for a discrete DIC result)
220 fieldCoords: nx3 array of n points coordinates (ZYX)
222 PhiField: nx4x4 array of n points transformation operators
224 returnStatus: nx1 array of n points returnStatus from the correlation
226 deltaPhiNorm: nx1 array of n points deltaPhiNorm from the correlation
228 iterations: nx1 array of n points iterations from the correlation
230 pixelSearchCC: nx1 array of n points pixelSearchCC from the correlation
232 error: nx1 array of n points error from the correlation
234 labelDilate: nx1 array of n points labelDilate from the correlation
236 """
237 if not os.path.isfile(fileName):
238 print("\n\tspam.tsvio.readCorrelationTSV(): {} is not a file. Exiting.".format(fileName))
239 return
241 f = numpy.genfromtxt(fileName, delimiter="\t", names=True)
242 # RS = []
243 # deltaPhiNorm = []
244 # pixelSearchCC = []
246 # If this is a one-line TSV file (an initial registration for example)
247 if f.size == 1:
248 # print("\tspam.tsvio.readCorrelationTSV(): {} seems only to have one line.".format(fileName))
249 nPoints = 1
250 numberOfLabels = 1
251 fieldDims = [1, 1, 1]
253 # Sort out the field coordinates
254 fieldCoords = numpy.zeros((nPoints, 3))
255 fieldCoords[:, 0] = f["Zpos"] * fieldBinRatio
256 fieldCoords[:, 1] = f["Ypos"] * fieldBinRatio
257 fieldCoords[:, 2] = f["Xpos"] * fieldBinRatio
259 # Sort out the components of Phi
260 PhiField = numpy.zeros((nPoints, 4, 4))
261 PhiField[0] = numpy.eye(4)
263 # Fill in displacements
264 try:
265 PhiField[0, 0, 3] = f["Zdisp"] * fieldBinRatio
266 PhiField[0, 1, 3] = f["Ydisp"] * fieldBinRatio
267 PhiField[0, 2, 3] = f["Xdisp"] * fieldBinRatio
268 except ValueError:
269 PhiField[0, 0, 3] = f["F14"] * fieldBinRatio
270 PhiField[0, 1, 3] = f["F24"] * fieldBinRatio
271 PhiField[0, 2, 3] = f["F34"] * fieldBinRatio
273 if not readOnlyDisplacements:
274 try:
275 # Get non-displacement components
276 PhiField[0, 0, 0] = f["Fzz"]
277 PhiField[0, 0, 1] = f["Fzy"]
278 PhiField[0, 0, 2] = f["Fzx"]
279 PhiField[0, 1, 0] = f["Fyz"]
280 PhiField[0, 1, 1] = f["Fyy"]
281 PhiField[0, 1, 2] = f["Fyx"]
282 PhiField[0, 2, 0] = f["Fxz"]
283 PhiField[0, 2, 1] = f["Fxy"]
284 PhiField[0, 2, 2] = f["Fxx"]
285 except:
286 print("spam.helpers.tsvio.readCorrelationTSV(): Attempting to read old format, please update your TSV file (F11 should be Fzz and so on)")
287 # Get non-displacement components
288 PhiField[0, 0, 0] = f["F11"]
289 PhiField[0, 0, 1] = f["F12"]
290 PhiField[0, 0, 2] = f["F13"]
291 PhiField[0, 1, 0] = f["F21"]
292 PhiField[0, 1, 1] = f["F22"]
293 PhiField[0, 1, 2] = f["F23"]
294 PhiField[0, 2, 0] = f["F31"]
295 PhiField[0, 2, 1] = f["F32"]
296 PhiField[0, 2, 2] = f["F33"]
298 if readConvergence:
299 try:
300 # Return ReturnStatus, SubPixelDeltaFnorm, SubPixelIterations
301 RS = f["returnStatus"]
302 deltaPhiNorm = f["deltaPhiNorm"]
303 iterations = f["iterations"]
304 except:
305 print("spam.helpers.tsvio.readCorrelationTSV(): Attempting to read old format, please update your TSV file (SubPix should be )")
306 # Return ReturnStatus, SubPixelDeltaFnorm, SubPixelIterations
307 RS = f["SubPixReturnStat"]
308 deltaPhiNorm = f["SubPixDeltaPhiNorm"]
309 iterations = f["SubPixIterations"]
310 if readError:
311 try:
312 error = f["error"]
313 except ValueError:
314 pass
315 # Return pixelSearchCC
316 if readPixelSearchCC:
317 pixelSearchCC = numpy.zeros(nPoints)
318 try:
319 pixelSearchCC = f["pixelSearchCC"]
320 except ValueError:
321 pass
323 # Return error
324 if readError:
325 error = numpy.zeros(nPoints)
326 try:
327 error = f["error"]
328 except ValueError:
329 pass
330 # Return labelDilate
331 if readLabelDilate:
332 labelDilate = numpy.zeros(nPoints)
333 try:
334 labelDilate = f["LabelDilate"]
335 except ValueError:
336 pass
338 pixelSearchCC = 0
340 # there is more than one line in the TSV file -- a field -- typical case
341 else:
342 nPoints = f.size
344 # check if it is a ddic or ldic result
345 try:
346 f["NodeNumber"]
347 # it's a local DIC result with grid points regularly spaced
348 DICgrid = True
349 DICdiscrete = False
350 except ValueError:
351 # it's a discrete DIC result with values in each label's centre of mass
352 DICdiscrete = True
353 DICgrid = False
355 # Sort out the field coordinates
356 fieldCoords = numpy.zeros((nPoints, 3))
357 fieldCoords[:, 0] = f["Zpos"] * fieldBinRatio
358 fieldCoords[:, 1] = f["Ypos"] * fieldBinRatio
359 fieldCoords[:, 2] = f["Xpos"] * fieldBinRatio
361 if DICgrid:
362 fieldDims = numpy.array([len(numpy.unique(f["Zpos"])), len(numpy.unique(f["Ypos"])), len(numpy.unique(f["Xpos"]))])
363 numberOfLabels = 0
364 if verbose:
365 print("\tspam.tsvio.readCorrelationTSV(): Field dimensions: {}".format(fieldDims))
366 elif DICdiscrete:
367 numberOfLabels = len(f["Label"])
368 fieldDims = [0, 0, 0]
369 if verbose:
370 print("\tspam.tsvio.readCorrelationTSV(): Number of labels: {}".format(numberOfLabels))
372 # create ReturnStatus and deltaPhiNorm matrices if asked
373 if readConvergence:
374 try:
375 RS = numpy.zeros(nPoints)
376 RS[:] = f[:]["returnStatus"]
377 deltaPhiNorm = numpy.zeros(nPoints)
378 deltaPhiNorm = f[:]["deltaPhiNorm"]
379 iterations = numpy.zeros(nPoints)
380 iterations = f[:]["iterations"]
381 except:
382 print("spam.helpers.tsvio.readCorrelationTSV(): Attempting to read old format, please update your TSV file")
383 RS = numpy.zeros(nPoints)
384 RS[:] = f[:]["SubPixReturnStat"]
385 deltaPhiNorm = numpy.zeros(nPoints)
386 deltaPhiNorm = f[:]["SubPixDeltaPhiNorm"]
387 iterations = numpy.zeros(nPoints)
388 iterations = f[:]["SubPixIterations"]
390 # Return pixelSearchCC
391 if readPixelSearchCC:
392 pixelSearchCC = numpy.zeros(nPoints)
393 try:
394 pixelSearchCC = f[:]["pixelSearchCC"]
395 except ValueError:
396 pass
398 # Return error
399 if readError:
400 error = numpy.zeros(nPoints)
401 try:
402 error = f[:]["error"]
403 except ValueError:
404 pass
405 # Return labelDilate
406 if readLabelDilate:
407 labelDilate = numpy.zeros(nPoints)
408 try:
409 labelDilate = f[:]["LabelDilate"]
410 except ValueError:
411 pass
413 # Sort out the components of Phi
414 PhiField = numpy.zeros((nPoints, 4, 4))
415 for n in range(nPoints):
416 # Initialise with Identity matrix
417 PhiField[n] = numpy.eye(4)
419 # Fill in displacements
420 try:
421 PhiField[n, 0, 3] = f[n]["Zdisp"] * fieldBinRatio
422 PhiField[n, 1, 3] = f[n]["Ydisp"] * fieldBinRatio
423 PhiField[n, 2, 3] = f[n]["Xdisp"] * fieldBinRatio
424 except ValueError:
425 PhiField[n, 0, 3] = f[n]["F14"] * fieldBinRatio
426 PhiField[n, 1, 3] = f[n]["F24"] * fieldBinRatio
427 PhiField[n, 2, 3] = f[n]["F34"] * fieldBinRatio
429 if not readOnlyDisplacements:
430 try:
431 # Get non-displacement components
432 PhiField[n, 0, 0] = f[n]["Fzz"]
433 PhiField[n, 0, 1] = f[n]["Fzy"]
434 PhiField[n, 0, 2] = f[n]["Fzx"]
435 PhiField[n, 1, 0] = f[n]["Fyz"]
436 PhiField[n, 1, 1] = f[n]["Fyy"]
437 PhiField[n, 1, 2] = f[n]["Fyx"]
438 PhiField[n, 2, 0] = f[n]["Fxz"]
439 PhiField[n, 2, 1] = f[n]["Fxy"]
440 PhiField[n, 2, 2] = f[n]["Fxx"]
441 except:
442 print("spam.helpers.tsvio.readCorrelationTSV(): Attempting to read old format, please update your TSV file (F11 should be Fzz and so on)")
443 # Get non-displacement components
444 PhiField[n, 0, 0] = f[n]["F11"]
445 PhiField[n, 0, 1] = f[n]["F12"]
446 PhiField[n, 0, 2] = f[n]["F13"]
447 PhiField[n, 1, 0] = f[n]["F21"]
448 PhiField[n, 1, 1] = f[n]["F22"]
449 PhiField[n, 1, 2] = f[n]["F23"]
450 PhiField[n, 2, 0] = f[n]["F31"]
451 PhiField[n, 2, 1] = f[n]["F32"]
452 PhiField[n, 2, 2] = f[n]["F33"]
454 output = {"fieldDims": fieldDims, "numberOfLabels": numberOfLabels, "fieldCoords": fieldCoords}
455 if readConvergence:
456 output.update({"returnStatus": RS, "deltaPhiNorm": deltaPhiNorm, "iterations": iterations})
457 if readError:
458 output.update({"error": error})
459 if readPixelSearchCC:
460 output.update({"pixelSearchCC": pixelSearchCC})
461 if readLabelDilate:
462 output.update({"LabelDilate": labelDilate})
464 if readOnlyDisplacements:
465 output.update({"displacements": PhiField[:, 0:3, -1]})
466 else:
467 output.update({"PhiField": PhiField})
469 return output
472def readStrainTSV(fileName):
473 """
474 This function reads a strain TSV file written by `spam-discreteStrain` or `spam-regularStrain`
476 Parameters
477 ----------
478 fileName : string
479 Name of the file
481 Returns
482 -------
483 Dictionary containing:
485 fieldDims: 1x3 array of the field dimensions (ZYX)
487 fieldCoords : nx3 array of the field coordinates (ZYX)
489 numberOfLabels: number of labels (for a discrete strain result)
491 vol: nx1 array of n points with volumetric strain computed under the hypotesis of large strains (if computed)
493 dev: nx1 array of n points with deviatoric strain computed under the hypotesis of large strains (if computed)
495 volss: nx1 array of n points with volumetric strain computed under the hypotesis of small strains (if computed)
497 devss: nx1 array of n points with deviatoric strain computed under the hypotesis of small strains (if computed)
499 r : nx3 array of n points with the components of the rotation vector (if computed)
501 z : nx3 array of n points with the components of the zoom vector (if computed)
503 U : nx3x3 array of n points with the components of the right-hand stretch tensor (if computed)
505 e : nx3x3 array of n points with the components of the strain tensor in small strains (if computed)
507 """
509 if not os.path.isfile(fileName):
510 print("\n\tspam.tsvio.readStrainTSV(): {} is not a file. Exiting.".format(fileName))
511 return
512 # Read the TSV
513 f = numpy.genfromtxt(fileName, delimiter="\t", names=True)
515 # Number of points
516 nPoints = f.size
518 # Get keys from file
519 keys = f.dtype.names
521 # Create empyt dictionary to be filled
522 output = {}
524 # Read and add the label coordinates
525 fieldCoords = numpy.zeros((nPoints, 3))
526 fieldCoords[:, 0] = f["Zpos"]
527 fieldCoords[:, 1] = f["Ypos"]
528 fieldCoords[:, 2] = f["Xpos"]
529 output["fieldCoords"] = fieldCoords
531 # Check if we are working with a regular grid or discrete
532 grid = False
533 if numpy.abs(fieldCoords[2, 0] - fieldCoords[3, 0]) == 0:
534 grid = True
535 else:
536 pass
538 if grid:
539 fieldDims = numpy.array([len(numpy.unique(f["Zpos"])), len(numpy.unique(f["Ypos"])), len(numpy.unique(f["Xpos"]))])
540 output["fieldDims"] = fieldDims
541 output["numberOfLabels"] = 0
542 else:
543 output["fieldDims"] = [0, 0, 0]
544 output["numberOfLabels"] = nPoints
546 # Check for all the possible keys
547 if "vol" in keys:
548 volStrain = numpy.zeros((nPoints, 1))
549 volStrain[:, 0] = f["vol"]
550 output["vol"] = volStrain
552 if "dev" in keys:
553 devStrain = numpy.zeros((nPoints, 1))
554 devStrain[:, 0] = f["dev"]
555 output["dev"] = devStrain
557 if "volss" in keys:
558 volss = numpy.zeros((nPoints, 1))
559 volss[:, 0] = f["volss"]
560 output["volss"] = volss
562 if "devss" in keys:
563 devss = numpy.zeros((nPoints, 1))
564 devss[:, 0] = f["devss"]
565 output["devss"] = devss
567 if "rz" in keys:
568 r = numpy.zeros((nPoints, 3))
569 r[:, 0] = f["rz"]
570 r[:, 1] = f["ry"]
571 r[:, 2] = f["rx"]
572 output["r"] = r
574 if "zz" in keys:
575 # Zooms, these are very badly named like this
576 z = numpy.zeros((nPoints, 3))
577 z[:, 0] = f["zz"]
578 z[:, 1] = f["zy"]
579 z[:, 2] = f["zx"]
580 output["z"] = z
582 if "Uzz" in keys:
583 # Symmetric, so fill in both sides
584 U = numpy.zeros((nPoints, 3, 3))
585 U[:, 0, 0] = f["Uzz"]
586 U[:, 1, 1] = f["Uyy"]
587 U[:, 2, 2] = f["Uxx"]
588 U[:, 0, 1] = f["Uzy"]
589 U[:, 1, 0] = f["Uzy"]
590 U[:, 0, 2] = f["Uzx"]
591 U[:, 2, 0] = f["Uzx"]
592 U[:, 1, 2] = f["Uyx"]
593 U[:, 2, 1] = f["Uyx"]
594 output["U"] = U
596 if "ezz" in keys:
597 # Symmetric, so fill in both sides
598 e = numpy.zeros((nPoints, 3, 3))
599 e[:, 0, 0] = f["ezz"]
600 e[:, 1, 1] = f["eyy"]
601 e[:, 2, 2] = f["exx"]
602 e[:, 0, 1] = f["ezy"]
603 e[:, 1, 0] = f["ezy"]
604 e[:, 0, 2] = f["ezx"]
605 e[:, 2, 0] = f["ezx"]
606 e[:, 1, 2] = f["eyx"]
607 e[:, 2, 1] = f["eyx"]
608 output["e"] = e
610 return output
613def TSVtoTIFF(fileName, fieldBinRatio=1.0, lab=None, returnRS=False, outDir=None, prefix=None):
614 """
615 This function converts a TSV file (typically the output of spam-ldic and spam-ddic scripts)
616 to a tiff file for visualising the deformation field.
618 Parameters
619 ----------
620 fileName : string
621 Name of the file
623 fieldBinRatio : int, optional
624 if the input field is refer to a binned version of the image
625 `e.g.`, if ``fieldBinRatio = 2`` the field_name values have been calculated
626 for an image half the size of what the returned PhiField is referring to
627 Default = 1.0
629 lab : 3D numpy array, optional
630 The labelled image of the reference state. Highly recommended argument in case of a discrete correlation result.
631 Default = None
633 returnRS : bool, optional
634 if True: will return the returnStatus of the correlation as a tiff file
635 Default = False
637 outDir : string, optional
638 Output directory
639 Default is directory of the input field file
641 prefix : string, optional
642 Prefix for output files
643 Default is the basename of the input field file (without extension)
644 """
646 import tifffile
648 # use the helper function to read the TSV file
649 fi = readCorrelationTSV(fileName, fieldBinRatio=fieldBinRatio, readOnlyDisplacements=True, readConvergence=returnRS)
650 displacements = fi["displacements"]
651 PhiComponents = [["Zdisp", 0], ["Ydisp", 1], ["Xdisp", 2]]
653 # set output directory if none
654 if outDir is None:
655 if os.path.dirname(fileName) == "":
656 outDir = "./"
657 else:
658 outDir = os.path.dirname(fileName)
659 else:
660 os.makedirs(outDir)
662 # output file name prefix
663 if prefix is None:
664 prefix = os.path.splitext(os.path.basename(fileName))[0]
666 # check if it is a ddic result
667 if fi["numberOfLabels"] != 0:
668 if lab:
669 labelled = tifffile.imread(lab)
670 import spam.label
672 for component in PhiComponents:
673 tifffile.imwrite("{}/{}-{}.tif".format(outDir, prefix, component[0]), spam.label.convertLabelToFloat(labelled, displacements[:, component[1]]).astype("<f4"))
674 if returnRS:
675 tifffile.imwrite("{}/{}-RS.tif".format(outDir, prefix), spam.label.convertLabelToFloat(labelled, fi["returnStatus"]).astype("<f4"))
676 else:
677 print("\tspam.tsvio.TSVtoTIFF(): The labelled image of the reference state is needed as input. Exiting.")
678 return
680 # if not, is a ldic result
681 else:
682 dims = fi["fieldDims"]
684 for component in PhiComponents:
685 tifffile.imwrite("{}/{}-{}.tif".format(outDir, prefix, component[0]), displacements[:, component[1]].reshape(dims).astype("<f4"))
687 if returnRS:
688 tifffile.imwrite("{}/{}-RS.tif".format(outDir, prefix), fi["returnStatus"].reshape(dims).astype("<f4"))
691def TSVtoVTK(fileName, fieldBinRatio=1.0, pixelSize=1.0, returnRS=False, outDir=None, prefix=None):
692 """
693 This function converts a TSV file (typically the output of the ldic and ddic scripts)
694 to a VTK file for visualising the deformation field.
696 Parameters
697 ----------
698 fileName : string
699 Name of the file
701 fieldBinRatio : int, optional
702 if the input field is refer to a binned version of the image
703 `e.g.`, if ``fieldBinRatio = 2`` the field values have been calculated
704 for an image half the size of what the returned PhiField is referring to
705 Default = 1.0
707 pixelSize: float
708 physical size of a pixel (i.e. 1mm/px)
709 Default = 1.0
711 returnRS : bool, optional
712 if True: will return the SubPixelReturnStatus of the correlation
713 Default = False
715 outDir : string
716 Output directory
717 Default is directory of the input field file
719 prefix : string
720 Prefix for output files
721 Default is the basename of the input field file (without extension)
722 """
723 import spam.helpers
725 # use the helper function to read the TSV file
726 fi = readCorrelationTSV(fileName, fieldBinRatio=fieldBinRatio)
727 PhiField = fi["PhiField"]
729 # set output directory if none
730 if outDir is None:
731 if os.path.dirname(fileName) == "":
732 outDir = "./"
733 else:
734 outDir = os.path.dirname(fileName)
735 else:
736 os.makedirs(outDir)
738 # output file name prefix
739 if prefix is None:
740 prefix = os.path.splitext(os.path.basename(fileName))[0]
742 # check if it is a ddic result
743 if fi["numberOfLabels"] != 0:
744 coords = fi["fieldCoords"][1:] * pixelSize
745 if not returnRS:
746 pointData = {"displacements": PhiField[1:, :-1, 3] * pixelSize}
748 else:
749 pointData = {"displacements": PhiField[1:, :-1, 3] * pixelSize, "returnStatus": fi["returnStatus"][1:]}
751 spam.helpers.writeGlyphsVTK(coords, pointData, fileName="{}/{}.vtk".format(outDir, prefix))
753 # if not, is a ldic result
754 else:
755 dims = fi["fieldDims"]
756 coords = fi["fieldCoords"] * pixelSize
757 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)])
758 origin = coords[0] - aspectRatio / 2.0
760 if not returnRS:
761 cellData = {"displacements": (PhiField[:, :-1, 3] * pixelSize).reshape((dims[0], dims[1], dims[2], 3))}
763 else:
764 cellData = {"displacements": (PhiField[:, :-1, 3] * pixelSize).reshape((dims[0], dims[1], dims[2], 3)), "returnStatus": fi["returnStatus"].reshape(dims[0], dims[1], dims[2])}
766 spam.helpers.writeStructuredVTK(aspectRatio=aspectRatio, origin=origin, cellData=cellData, fileName="{}/{}.vtk".format(outDir, prefix))