Mercurial > repos > imgteam > split_image
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 |
