oct-to-tiff 0.5.0__py3-none-any.whl → 0.6.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
oct_to_tiff/cli.py CHANGED
@@ -6,24 +6,25 @@ from typing import Any
6
6
 
7
7
  import defusedxml.ElementTree as DET
8
8
  import numpy as np
9
+ import numpy.typing as npt
9
10
  import tifffile
10
- from numpy.typing import NDArray
11
+ from roifile import ROI_TYPE, ImagejRoi, roiwrite
11
12
 
12
13
  logger = logging.getLogger(__name__)
13
14
 
14
15
 
15
16
  def reshape_volume(
16
- volume: NDArray[Any],
17
+ volume: npt.NDArray[Any],
17
18
  frames_per_data_group: int,
18
19
  total_data_groups: int,
19
20
  oct_window_height: int,
20
21
  xy_scan_length: int,
21
- ) -> NDArray[Any]:
22
+ ) -> npt.NDArray[Any]:
22
23
  """Reshape a 1-dimensional array to a 3-dimensional array.
23
24
 
24
25
  Parameters
25
26
  ----------
26
- volume : NDArray[Any]
27
+ volume : npt.NDArray[Any]
27
28
  A 1-dimensional array.
28
29
  frames_per_data_group : int
29
30
  The number of frames per data group.
@@ -36,7 +37,7 @@ def reshape_volume(
36
37
 
37
38
  Returns
38
39
  -------
39
- volume : NDArray[Any]
40
+ volume : npt.NDArray[Any]
40
41
  A 3-dimensional array.
41
42
 
42
43
  """
@@ -51,29 +52,9 @@ def reshape_volume(
51
52
  return volume
52
53
 
53
54
 
54
- def rotate_volume(
55
- volume: NDArray[Any],
56
- ) -> NDArray[Any]:
57
- """Rotate a 3-dimensional array 90 degrees left (anti-clockwise) about the z-axis.
58
-
59
- Parameters
60
- ----------
61
- volume : NDArray[Any]
62
- A 3-dimensional array.
63
-
64
- Returns
65
- -------
66
- volume : NDArray[Any]
67
- A rotated version of the input volume.
68
-
69
- """
70
- volume = np.rot90(volume, k=1, axes=(1, 2))
71
- return volume
72
-
73
-
74
55
  def write_volume(
75
56
  output_path: Path,
76
- volume: NDArray[Any],
57
+ volume: npt.NDArray[Any],
77
58
  pixel_size_x: float,
78
59
  pixel_size_y: float,
79
60
  pixel_size_z: float,
@@ -84,7 +65,7 @@ def write_volume(
84
65
  ----------
85
66
  output_path : Path
86
67
  The specified output path.
87
- volume : NDArray[Any]
68
+ volume : npt.NDArray[Any]
88
69
  A 3-dimensional array.
89
70
  pixel_size_x : float
90
71
  The pixel (voxel) width in mm.
@@ -110,7 +91,7 @@ def write_volume(
110
91
  )
111
92
 
112
93
 
113
- def extract_boundaries(input_path: str | Path) -> None:
94
+ def boundaries_to_arrays(input_path: str | Path) -> list[npt.NDArray[np.int_]]:
114
95
  """Extract segmentation lines.
115
96
 
116
97
  Parameters
@@ -118,6 +99,10 @@ def extract_boundaries(input_path: str | Path) -> None:
118
99
  input_path : str | Path
119
100
  The specified input path.
120
101
 
102
+ Returns
103
+ -------
104
+ arrays : list[npt.NDArray[np.int_]]
105
+ A list of 2-dimensional arrays.
121
106
  """
122
107
  input_path = Path(input_path)
123
108
  tree = DET.parse(input_path)
@@ -128,14 +113,36 @@ def extract_boundaries(input_path: str | Path) -> None:
128
113
  int(point.text) if point.text else 0
129
114
  for point in root.findall("./Curve_Set/Image/Curve/D")
130
115
  ]
131
- scan_length = np.arange(len(data_points))
132
- num_files = len(data_points) // array_size
133
- for i in range(num_files):
116
+ num_arrays = len(data_points) // array_size
117
+
118
+ arrays = []
119
+ for i in range(num_arrays):
134
120
  start = i * array_size
135
121
  end = start + array_size
136
- table = np.column_stack([scan_length[start:end], data_points[start:end]])
137
- table_path = f"{input_path.parent}/{input_path.stem}_{i+1}.txt"
138
- np.savetxt(table_path, table, delimiter="\t", fmt="%d")
122
+ array = np.column_stack([np.arange(array_size), data_points[start:end]])
123
+ arrays.append(array)
124
+
125
+ return arrays
126
+
127
+
128
+ def arrays_to_rois(arrays: list[npt.NDArray[np.int_]], output_path: Path) -> None:
129
+ """
130
+ Convert a list of 2-dimensional arrays to ImageJ ROIs (ZIP file).
131
+
132
+ Parameters
133
+ ----------
134
+ arrays : list[npt.NDArray[np.int_]]
135
+ A list of 2-dimensional arrays.
136
+ output_path : Path
137
+ The specified output path.
138
+ """
139
+ rois = []
140
+ for array in arrays:
141
+ roi = ImagejRoi.frompoints(array)
142
+ roi.roitype = ROI_TYPE(4) # FREELINE
143
+ rois.append(roi)
144
+
145
+ roiwrite(output_path, rois, mode="w")
139
146
 
140
147
 
141
148
  def main() -> None:
@@ -202,18 +209,22 @@ def main() -> None:
202
209
  else:
203
210
  dir_name = input_path.parent
204
211
  file_name = input_path.stem
205
- file_extension = ".ome.tif"
212
+ if args.boundaries:
213
+ file_extension = "_rois.zip"
214
+ else:
215
+ file_extension = ".ome.tif"
206
216
  output_path = dir_name / (file_name + file_extension)
207
217
 
208
218
  if Path.is_file(output_path):
209
219
  if args.overwrite:
210
- pass
220
+ logger.warning(f"Overwriting {output_path}")
211
221
  else:
212
222
  logger.error(f"{output_path} already exists.")
213
223
  return
214
224
 
215
225
  if args.boundaries:
216
- extract_boundaries(input_path)
226
+ arrays = boundaries_to_arrays(input_path)
227
+ arrays_to_rois(arrays, output_path)
217
228
  return
218
229
 
219
230
  with open(input_path, "rb") as f:
@@ -257,6 +268,32 @@ def main() -> None:
257
268
  pixel_size_x = 0.007797
258
269
  pixel_size_y = 0.003071
259
270
  pixel_size_z = 0.040000
271
+
272
+ volume = reshape_volume(
273
+ volume,
274
+ frames_per_data_group,
275
+ total_data_groups,
276
+ oct_window_height,
277
+ xy_scan_length,
278
+ )
279
+ volume = np.rot90(volume, k=1, axes=(1, 2))
280
+ volume_main = volume[:101]
281
+ volume_align = volume[101:frames_per_data_group]
282
+ align_path = dir_name / (file_name + "_Align.ome.tif")
283
+ pixel_size_x_align = 0.003899
284
+ pixel_size_y_align = 0.003071
285
+ pixel_size_z_align = 0.040000
286
+ write_volume(
287
+ output_path, volume_main, pixel_size_x, pixel_size_y, pixel_size_z
288
+ )
289
+ write_volume(
290
+ align_path,
291
+ volume_align,
292
+ pixel_size_x_align,
293
+ pixel_size_y_align,
294
+ pixel_size_z_align,
295
+ )
296
+ return
260
297
  elif "3D Disc" in file_name:
261
298
  volume = np.frombuffer(f.read(), dtype=np.single)
262
299
  frames_per_data_group = 106
@@ -465,7 +502,7 @@ def main() -> None:
465
502
  )
466
503
 
467
504
  if not args.en_face and not args.seg_curve:
468
- volume = rotate_volume(volume)
505
+ volume = np.rot90(volume, k=1, axes=(1, 2))
469
506
 
470
507
  write_volume(output_path, volume, pixel_size_x, pixel_size_y, pixel_size_z)
471
508
 
@@ -1,63 +1,35 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: oct-to-tiff
3
- Version: 0.5.0
3
+ Version: 0.6.0
4
4
  Summary: A command line tool for converting optical coherence tomography angiography (OCTA) data.
5
5
  Author-email: Cameron Lloyd <lloyd@med.unideb.hu>
6
6
  Maintainer-email: Cameron Lloyd <lloyd@med.unideb.hu>
7
- License: BSD 3-Clause License
8
-
9
- Copyright (c) 2021, Cameron Lloyd
10
- All rights reserved.
11
-
12
- Redistribution and use in source and binary forms, with or without
13
- modification, are permitted provided that the following conditions are met:
14
-
15
- 1. Redistributions of source code must retain the above copyright notice, this
16
- list of conditions and the following disclaimer.
17
-
18
- 2. Redistributions in binary form must reproduce the above copyright notice,
19
- this list of conditions and the following disclaimer in the documentation
20
- and/or other materials provided with the distribution.
21
-
22
- 3. Neither the name of the copyright holder nor the names of its
23
- contributors may be used to endorse or promote products derived from
24
- this software without specific prior written permission.
25
-
26
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27
- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28
- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
29
- DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
30
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31
- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32
- SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
33
- CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
34
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36
-
7
+ License-Expression: BSD-3-Clause
37
8
  Project-URL: Homepage, https://github.com/camlloyd/oct-to-tiff
38
9
  Project-URL: Bug Tracker, https://github.com/camlloyd/oct-to-tiff/issues
39
10
  Project-URL: Changelog, https://github.com/camlloyd/oct-to-tiff/blob/main/CHANGELOG.md
40
11
  Keywords: angiography,cli,oct,octa
41
12
  Classifier: Development Status :: 3 - Alpha
42
13
  Classifier: Intended Audience :: Science/Research
43
- Classifier: License :: OSI Approved :: BSD License
44
14
  Classifier: Natural Language :: English
45
15
  Classifier: Operating System :: OS Independent
46
16
  Classifier: Programming Language :: Python :: 3
47
- Classifier: Programming Language :: Python :: 3.10
48
17
  Classifier: Programming Language :: Python :: 3.11
49
18
  Classifier: Programming Language :: Python :: 3.12
50
19
  Classifier: Programming Language :: Python :: 3.13
51
- Requires-Python: >=3.10
20
+ Classifier: Programming Language :: Python :: 3.14
21
+ Requires-Python: >=3.11
52
22
  Description-Content-Type: text/markdown
53
23
  License-File: LICENSE.txt
54
24
  Requires-Dist: defusedxml
55
25
  Requires-Dist: numpy
26
+ Requires-Dist: roifile
56
27
  Requires-Dist: tifffile
57
28
  Provides-Extra: dev
58
29
  Requires-Dist: mypy; extra == "dev"
59
30
  Requires-Dist: ruff; extra == "dev"
60
31
  Requires-Dist: types-defusedxml; extra == "dev"
32
+ Dynamic: license-file
61
33
 
62
34
  # oct-to-tiff
63
35
 
@@ -214,4 +186,4 @@ This project uses [Ruff](https://github.com/astral-sh/ruff) for linting and form
214
186
 
215
187
  ## Requirements
216
188
 
217
- Requires Python 3.10 or higher.
189
+ Requires Python 3.11 or higher.
@@ -0,0 +1,8 @@
1
+ oct_to_tiff/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ oct_to_tiff/cli.py,sha256=GmIMXLuNfAEZaijX2_93XB95V0Mdr1yb73Q_j8eBiEI,17232
3
+ oct_to_tiff-0.6.0.dist-info/licenses/LICENSE.txt,sha256=8KO0dluzLStmIF0HM18BOP9T2miIcX8q-GOfMOw6Ngk,1521
4
+ oct_to_tiff-0.6.0.dist-info/METADATA,sha256=7atS8U7OhVhVpU48NjbGzqMtbGhlA_l4Dh6jZUiu010,4913
5
+ oct_to_tiff-0.6.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
6
+ oct_to_tiff-0.6.0.dist-info/entry_points.txt,sha256=mKWNdkTThZm2JKtLwp4PGMpXkvAWk-xnQDAOyRsCo9Y,53
7
+ oct_to_tiff-0.6.0.dist-info/top_level.txt,sha256=_ovqm7f48yb_IAiVqWzB3VPnHXwzkkEqQQ_ZJz_McSY,12
8
+ oct_to_tiff-0.6.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.6.0)
2
+ Generator: setuptools (80.9.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,8 +0,0 @@
1
- oct_to_tiff/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
- oct_to_tiff/cli.py,sha256=tHRUNBff0TTTtc0pnecF_t5mLWyoGG0kNKNVopyL4Sw,15934
3
- oct_to_tiff-0.5.0.dist-info/LICENSE.txt,sha256=8KO0dluzLStmIF0HM18BOP9T2miIcX8q-GOfMOw6Ngk,1521
4
- oct_to_tiff-0.5.0.dist-info/METADATA,sha256=8-nIJ6Pg_vvfxovcjIHgax-D1nMQaWYZ_9cJLT7lq2g,6649
5
- oct_to_tiff-0.5.0.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
6
- oct_to_tiff-0.5.0.dist-info/entry_points.txt,sha256=mKWNdkTThZm2JKtLwp4PGMpXkvAWk-xnQDAOyRsCo9Y,53
7
- oct_to_tiff-0.5.0.dist-info/top_level.txt,sha256=_ovqm7f48yb_IAiVqWzB3VPnHXwzkkEqQQ_ZJz_McSY,12
8
- oct_to_tiff-0.5.0.dist-info/RECORD,,