Skip to content

Commit d1cc20d

Browse files
authored
Merge pull request #53 from thewtex/compress-encode-multiscale
2 parents 9a57cc3 + dc91f3c commit d1cc20d

File tree

2 files changed

+40
-1
lines changed

2 files changed

+40
-1
lines changed

server/scripts/compress_encode.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,19 @@
44
import itk
55
from numcodecs import Blosc
66
import zarr
7+
from pathlib import Path
8+
import numpy as np
79

810
def compress_encode(input_filepath,
911
output_directory,
12+
multiscale=True,
1013
chunk_size=64,
1114
cname='zstd',
1215
clevel=5,
1316
shuffle=True):
1417
image = itk.imread(input_filepath)
1518
image_da = itk.xarray_from_image(image)
16-
dataset_name = input_filepath
19+
dataset_name = str(Path(input_filepath))
1720
image_ds = image_da.to_dataset(name=dataset_name)
1821

1922
store_name = output_directory
@@ -31,6 +34,37 @@ def compress_encode(input_filepath,
3134

3235
zarr.consolidate_metadata(store)
3336

37+
if multiscale:
38+
# multi-resolution pyramid
39+
pyramid = [image_da]
40+
reduced = image
41+
while not np.all(np.array(itk.size(reduced)) < 64):
42+
scale = len(pyramid)
43+
shrink_factors = [2**scale]*3
44+
reduced = itk.bin_shrink_image_filter(image, shrink_factors=shrink_factors)
45+
reduced_da = itk.xarray_from_image(reduced)
46+
pyramid.append(reduced_da)
47+
48+
pyramid_group_paths = [""]
49+
for scale in range(1, len(pyramid)):
50+
pyramid_group_paths.append('scale_{0}'.format(scale))
51+
52+
for scale in range(1, len(pyramid)):
53+
ds = pyramid[scale].to_dataset(name=dataset_name)
54+
ds.to_zarr(store,
55+
mode='w',
56+
group=pyramid_group_paths[scale],
57+
compute=True,
58+
encoding={dataset_name: {'chunks': [chunk_size]*3, 'compressor': compressor}})
59+
60+
# Re-consolidate entire dataset
61+
zarr.consolidate_metadata(store)
62+
for scale in range(1, len(pyramid)):
63+
store = zarr.DirectoryStore(str(Path(store_name) / pyramid_group_paths[scale]))
64+
# Also consolidate the metadata on the pyramid scales so they can be used independently
65+
zarr.consolidate_metadata(store)
66+
67+
3468
if __name__ == '__main__':
3569
parser = argparse.ArgumentParser('Convert and encode a medical image file in a compressed Zarr directory store.')
3670
parser.add_argument('input_filepath', help='Path to input image file, e.g. a NIFTI file.')
@@ -40,11 +74,13 @@ def compress_encode(input_filepath,
4074
parser.add_argument('--chunk-size', default=64, type=int, help='Compression chunk size along one dimension.')
4175
parser.add_argument('--cname', default='zstd', help='Base compression codec.')
4276
parser.add_argument('--clevel', default=5, type=int, help='Compression level.')
77+
parser.add_argument('--no-multi-scale', action='store_true', help='Do not generate a multi-scale pyramid.')
4378

4479
args = parser.parse_args()
4580

4681
compress_encode(args.input_filepath,
4782
args.output_directory,
83+
multiscale=not args.no_multi_scale,
4884
chunk_size=args.chunk_size,
4985
cname=args.cname,
5086
clevel=args.clevel,

server/scripts/requirements.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
itk
2+
xarray
3+
zarr

0 commit comments

Comments
 (0)