comparison split.py @ 3:d45a07063da1 draft default tip

planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/split_image/ commit df96ae15da34285b0a9d435a48924665fff37d6a
author imgteam
date Sat, 04 Apr 2026 21:22:07 +0000
parents 227e8928af6e
children
comparison
equal deleted inserted replaced
2:227e8928af6e 3:d45a07063da1
1 import argparse 1 import argparse
2 import math 2 import math
3 import os
4 import pathlib 3 import pathlib
5 import shutil
6 4
7 import giatools 5 import giatools
6 import giatools.io
8 import numpy as np 7 import numpy as np
9 import tifffile
10 8
11 9
12 class OutputWriter: 10 class OutputWriter:
13 11
14 def __init__(self, dir_path: pathlib.Path, num_images: int, squeeze: bool, verbose: bool): 12 def __init__(
15 print(f'Writing {num_images} image(s)') 13 self,
14 dir_path: pathlib.Path,
15 num_images: int,
16 squeeze: bool,
17 verbose: bool,
18 offset: int = 0,
19 step: int = 1,
20 count: int | None = None,
21 ):
22 self.positions = np.arange(num_images)[offset::step] + 1
23 if count is not None:
24 self.positions = self.positions[:count]
25
26 print(f'Writing {len(self.positions)} out of {num_images} image(s)')
16 decimals = math.ceil(math.log10(1 + num_images)) 27 decimals = math.ceil(math.log10(1 + num_images))
17 self.output_filepath_pattern = str(dir_path / f'%0{decimals}d.tiff') 28 self.output_filepath_pattern = str(dir_path / f'%0{decimals}d.tiff')
18 self.last_idx = 0 29 self.last_pos = 0
19 self.squeeze = squeeze 30 self.squeeze = squeeze
20 self.verbose = verbose 31 self.verbose = verbose
21 32
22 def write(self, img: giatools.Image): 33 def write(self, img: giatools.Image):
23 self.last_idx += 1 34 self.last_pos += 1
24 if self.squeeze: 35 if self.last_pos in self.positions:
25 img = img.squeeze() 36 if self.squeeze:
26 if self.last_idx == 1 or self.verbose: 37 img = img.squeeze()
27 prefix = f'Output {self.last_idx}' if self.verbose else 'Output' 38 if self.last_pos == self.positions[0] or self.verbose:
28 print(f'{prefix} axes:', img.axes) 39 prefix = f'Output {self.last_pos}' if self.verbose else 'Output'
29 print(f'{prefix} shape:', img.data.shape) 40 print(f'{prefix} axes:', img.axes)
30 img.write(self.output_filepath_pattern % self.last_idx) 41 print(f'{prefix} shape:', img.data.shape)
42 img.write(self.output_filepath_pattern % self.last_pos)
31 43
32 44
33 if __name__ == '__main__': 45 if __name__ == '__main__':
34 46
35 parser = argparse.ArgumentParser() 47 parser = argparse.ArgumentParser()
36 parser.add_argument('input', type=pathlib.Path) 48 parser.add_argument('input', type=pathlib.Path)
37 parser.add_argument('axis', type=str, choices=list(giatools.default_normalized_axes) + ['S', '']) 49 parser.add_argument('axis', type=str, choices=list(giatools.default_normalized_axes) + ['S', ''])
38 parser.add_argument('output', type=pathlib.Path) 50 parser.add_argument('output', type=pathlib.Path)
39 parser.add_argument('--squeeze', action='store_true', default=False) 51 parser.add_argument('--squeeze', action='store_true', default=False)
52 parser.add_argument('offset', type=int)
53 parser.add_argument('step', type=int)
54 parser.add_argument('--count', type=int)
40 args = parser.parse_args() 55 args = parser.parse_args()
41 56
42 # If splitting a file that contains multiple images... 57 # If splitting a file that contains multiple images...
43 if args.axis == '': 58 if args.axis == '':
44 59
45 # Peek the number of series in the input file (if it is a TIFF) 60 # Peek the number of images
46 try: 61 num_images = giatools.io.peek_num_images_in_file(args.input)
47 with tifffile.TiffFile(args.input) as tiff: 62 print(f'Found {num_images} image(s) in file')
48 num_tiff_series = len(tiff.series)
49 print(f'Found TIFF with {num_tiff_series} series')
50 except tifffile.TiffFileError:
51 num_tiff_series = 0 # not a TIFF file
52 print('Not a TIFF file')
53 63
54 # If the file is a multi-series TIFF, extract the individual series 64 # Extract the individual images
55 # (for consistency, also accept only a single series if squeezing is requested) 65 output = OutputWriter(
56 if num_tiff_series >= 2 or (num_tiff_series == 1 and args.squeeze): 66 dir_path=args.output,
57 output = OutputWriter( 67 num_images=num_images,
58 dir_path=args.output, 68 squeeze=args.squeeze,
59 num_images=num_tiff_series, 69 verbose=(num_images > 1),
60 squeeze=args.squeeze, 70 offset=args.offset,
61 verbose=True, 71 step=args.step,
62 ) 72 count=args.count,
63 for series in range(num_tiff_series): 73 )
64 img = giatools.Image.read(args.input, series=series) 74 for position in range(num_images):
65 output.write( 75 img = giatools.Image.read(args.input, position=position, normalize_axes=None)
66 img.squeeze_like(img.original_axes), 76 output.write(img)
67 )
68
69 # Otherwise, there is nothing to be split (or squeeze)
70 # (the input is either a single-series TIFF or not a TIFF at all)
71 elif num_tiff_series == 1: # input is a single-series TIFF (output = input)
72 try:
73 os.symlink(args.input, args.output / '1.tiff')
74 except OSError:
75 shutil.copyfile(args.input, args.output / '1.tiff')
76 else: # input is not a TIFF, conversion needed
77 img = giatools.Image.read(args.input)
78 OutputWriter(
79 dir_path=args.output,
80 num_images=1,
81 squeeze=args.squeeze,
82 verbose=False,
83 ).write(
84 img.squeeze_like(img.original_axes),
85 )
86 77
87 # If splitting along an image axes... 78 # If splitting along an image axes...
88 else: 79 else:
89 80
90 # Validate and normalize input parameters 81 # Validate and normalize input parameters
103 output = OutputWriter( 94 output = OutputWriter(
104 dir_path=args.output, 95 dir_path=args.output,
105 num_images=arr.shape[0], 96 num_images=arr.shape[0],
106 squeeze=args.squeeze, 97 squeeze=args.squeeze,
107 verbose=False, 98 verbose=False,
99 offset=args.offset,
100 step=args.step,
101 count=args.count,
108 ) 102 )
109 for img_idx, img in enumerate(arr): 103 for img_idx, img in enumerate(arr):
110 img = np.moveaxis(img[None], 0, axis_pos) 104 img = np.moveaxis(img[None], 0, axis_pos)
111 105
112 # Construct the output image, remove axes added by normalization 106 # Construct the output image, remove axes added by normalization