comparison split.py @ 2:390943df8a35 draft default tip

planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/split_image/ commit 5e452f10eb88f0fa8a420eec66c6c97e3060e433
author imgteam
date Fri, 12 Dec 2025 21:02:39 +0000
parents 73d7a4ffc03d
children
comparison
equal deleted inserted replaced
1:73d7a4ffc03d 2:390943df8a35
1 import argparse 1 import argparse
2 import math 2 import math
3 import os
4 import pathlib
5 import shutil
3 6
4 import giatools 7 import giatools
5 import giatools.util
6 import numpy as np 8 import numpy as np
7 import tifffile 9 import tifffile
8 10
9 11
10 parser = argparse.ArgumentParser() 12 class OutputWriter:
11 parser.add_argument('input', type=str)
12 parser.add_argument('axis', type=str)
13 parser.add_argument('output', type=str)
14 parser.add_argument('--squeeze', action='store_true', default=False)
15 args = parser.parse_args()
16 13
17 # Validate and normalize input parameters 14 def __init__(self, dir_path: pathlib.Path, num_images: int, squeeze: bool, verbose: bool):
18 assert len(args.axis) == 1, 'Axis input must be a single character.' 15 print(f'Writing {num_images} image(s)')
19 axis = args.axis.replace('S', 'C') 16 decimals = math.ceil(math.log10(1 + num_images))
17 self.output_filepath_pattern = str(dir_path / f'%0{decimals}d.tiff')
18 self.last_idx = 0
19 self.squeeze = squeeze
20 self.verbose = verbose
20 21
21 # Read input image with normalized axes 22 def write(self, img: giatools.Image):
22 img_in = giatools.Image.read(args.input) 23 self.last_idx += 1
24 if self.squeeze:
25 img = img.squeeze()
26 if self.last_idx == 1 or self.verbose:
27 prefix = f'Output {self.last_idx}' if self.verbose else 'Output'
28 print(f'{prefix} axes:', img.axes)
29 print(f'{prefix} shape:', img.data.shape)
30 img.write(self.output_filepath_pattern % self.last_idx)
23 31
24 # Determine the axis to split along
25 axis_pos = img_in.axes.index(axis)
26 32
27 # Perform the splitting 33 if __name__ == '__main__':
28 arr = np.moveaxis(img_in.data, axis_pos, 0)
29 decimals = math.ceil(math.log10(1 + arr.shape[0]))
30 output_filename_pattern = f'{args.output}/%0{decimals}d.tiff'
31 for img_idx, img in enumerate(arr):
32 img = np.moveaxis(img[None], 0, axis_pos)
33 34
34 # Construct the output image, remove axes added by normalization 35 parser = argparse.ArgumentParser()
35 img_out = giatools.Image( 36 parser.add_argument('input', type=pathlib.Path)
36 data=img, 37 parser.add_argument('axis', type=str, choices=list(giatools.default_normalized_axes) + ['S', ''])
37 axes=img_in.axes, 38 parser.add_argument('output', type=pathlib.Path)
38 ).squeeze_like( 39 parser.add_argument('--squeeze', action='store_true', default=False)
39 img_in.original_axes, 40 args = parser.parse_args()
40 )
41 41
42 # Optionally, squeeze the image 42 # If splitting a file that contains multiple images...
43 if args.squeeze: 43 if args.axis == '':
44 s = [ 44
45 axis_pos for axis_pos in range(len(img_out.axes)) 45 # Peek the number of series in the input file (if it is a TIFF)
46 if img_out.data.shape[axis_pos] == 1 and img_out.axes[axis_pos] not in 'YX' 46 try:
47 ] 47 with tifffile.TiffFile(args.input) as tiff:
48 img_out = img_out.squeeze_like( 48 num_tiff_series = len(tiff.series)
49 giatools.util.str_without_positions(img_out.axes, s), 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
54 # If the file is a multi-series TIFF, extract the individual series
55 # (for consistency, also accept only a single series if squeezing is requested)
56 if num_tiff_series >= 2 or (num_tiff_series == 1 and args.squeeze):
57 output = OutputWriter(
58 dir_path=args.output,
59 num_images=num_tiff_series,
60 squeeze=args.squeeze,
61 verbose=True,
62 )
63 for series in range(num_tiff_series):
64 img = giatools.Image.read(args.input, series=series)
65 output.write(
66 img.squeeze_like(img.original_axes),
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
87 # If splitting along an image axes...
88 else:
89
90 # Validate and normalize input parameters
91 axis = args.axis.replace('S', 'C')
92
93 # Read input image with normalized axes
94 img_in = giatools.Image.read(args.input)
95 print('Input image axes:', img_in.original_axes)
96 print('Input image shape:', img_in.squeeze_like(img_in.original_axes).data.shape)
97
98 # Determine the axis to split along
99 axis_pos = img_in.axes.index(axis)
100
101 # Perform the splitting
102 arr = np.moveaxis(img_in.data, axis_pos, 0)
103 output = OutputWriter(
104 dir_path=args.output,
105 num_images=arr.shape[0],
106 squeeze=args.squeeze,
107 verbose=False,
50 ) 108 )
109 for img_idx, img in enumerate(arr):
110 img = np.moveaxis(img[None], 0, axis_pos)
51 111
52 # Save the result 112 # Construct the output image, remove axes added by normalization
53 filename = output_filename_pattern % (img_idx + 1) 113 img_out = giatools.Image(
54 tifffile.imwrite(filename, img_out.data, metadata=dict(axes=img_out.axes)) 114 data=img,
115 axes=img_in.axes,
116 metadata=img_in.metadata,
117 ).squeeze_like(
118 img_in.original_axes,
119 )
120
121 # Save the result (write stdout during first iteration)
122 output.write(img_out)