diff --git a/tools/2d_feature_extraction/2d_feature_extraction.py b/tools/2d_feature_extraction/2d_feature_extraction.py index 3b7584dda..90e2e81cf 100644 --- a/tools/2d_feature_extraction/2d_feature_extraction.py +++ b/tools/2d_feature_extraction/2d_feature_extraction.py @@ -1,127 +1,115 @@ -import argparse - -import giatools.io +import giatools import numpy as np import pandas as pd -import skimage.feature +import scipy.ndimage as ndi import skimage.measure -import skimage.morphology -import skimage.segmentation +# Fail early if an optional backend is not available +giatools.require_backend('omezarr') -if __name__ == '__main__': - parser = argparse.ArgumentParser(description='Extract image features') - - # TODO create factory for boilerplate code - features = parser.add_argument_group('compute features') - features.add_argument('--all', dest='all_features', action='store_true') - features.add_argument('--label', dest='add_label', action='store_true') - features.add_argument('--patches', dest='add_roi_patches', action='store_true') - features.add_argument('--max_intensity', dest='max_intensity', action='store_true') - features.add_argument('--mean_intensity', dest='mean_intensity', action='store_true') - features.add_argument('--min_intensity', dest='min_intensity', action='store_true') - features.add_argument('--moments_hu', dest='moments_hu', action='store_true') - features.add_argument('--centroid', dest='centroid', action='store_true') - features.add_argument('--bbox', dest='bbox', action='store_true') - features.add_argument('--area', dest='area', action='store_true') - features.add_argument('--filled_area', dest='filled_area', action='store_true') - features.add_argument('--convex_area', dest='convex_area', action='store_true') - features.add_argument('--perimeter', dest='perimeter', action='store_true') - features.add_argument('--extent', dest='extent', action='store_true') - features.add_argument('--eccentricity', dest='eccentricity', action='store_true') - features.add_argument('--equivalent_diameter', dest='equivalent_diameter', action='store_true') - features.add_argument('--euler_number', dest='euler_number', action='store_true') - features.add_argument('--inertia_tensor_eigvals', dest='inertia_tensor_eigvals', action='store_true') - features.add_argument('--major_axis_length', dest='major_axis_length', action='store_true') - features.add_argument('--minor_axis_length', dest='minor_axis_length', action='store_true') - features.add_argument('--orientation', dest='orientation', action='store_true') - features.add_argument('--solidity', dest='solidity', action='store_true') - features.add_argument('--moments', dest='moments', action='store_true') - features.add_argument('--convexity', dest='convexity', action='store_true') - - parser.add_argument('--label_file_binary', dest='label_file_binary', action='store_true') - - parser.add_argument('--raw', dest='raw_file', type=argparse.FileType('r'), - help='Original input file', required=False) - parser.add_argument('label_file', type=argparse.FileType('r'), - help='Label input file') - parser.add_argument('output_file', type=argparse.FileType('w'), - help='Tabular output file') - args = parser.parse_args() - - label_file_binary = args.label_file_binary - label_file = args.label_file.name - out_file = args.output_file.name - add_patch = args.add_roi_patches - - raw_image = None - if args.raw_file is not None: - raw_image = giatools.io.imread(args.raw_file.name) - - raw_label_image = giatools.io.imread(label_file) - - df = pd.DataFrame() - if label_file_binary: - raw_label_image = skimage.measure.label(raw_label_image) - regions = skimage.measure.regionprops(raw_label_image, intensity_image=raw_image) - - df['it'] = np.arange(len(regions)) - - if add_patch: - df['image'] = df['it'].map(lambda ait: regions[ait].image.astype(np.float).tolist()) - df['intensity_image'] = df['it'].map(lambda ait: regions[ait].intensity_image.astype(np.float).tolist()) - - # TODO no matrix features, but split in own rows? - if args.add_label or args.all_features: - df['label'] = df['it'].map(lambda ait: regions[ait].label) - - if raw_image is not None: - if args.max_intensity or args.all_features: - df['max_intensity'] = df['it'].map(lambda ait: regions[ait].max_intensity) - if args.mean_intensity or args.all_features: - df['mean_intensity'] = df['it'].map(lambda ait: regions[ait].mean_intensity) - if args.min_intensity or args.all_features: - df['min_intensity'] = df['it'].map(lambda ait: regions[ait].min_intensity) - if args.moments_hu or args.all_features: - df['moments_hu'] = df['it'].map(lambda ait: regions[ait].moments_hu) - - if args.centroid or args.all_features: - df['centroid'] = df['it'].map(lambda ait: regions[ait].centroid) - if args.bbox or args.all_features: - df['bbox'] = df['it'].map(lambda ait: regions[ait].bbox) - if args.area or args.all_features: - df['area'] = df['it'].map(lambda ait: regions[ait].area) - if args.filled_area or args.all_features: - df['filled_area'] = df['it'].map(lambda ait: regions[ait].filled_area) - if args.convex_area or args.all_features: - df['convex_area'] = df['it'].map(lambda ait: regions[ait].convex_area) - if args.perimeter or args.all_features: - df['perimeter'] = df['it'].map(lambda ait: regions[ait].perimeter) - if args.extent or args.all_features: - df['extent'] = df['it'].map(lambda ait: regions[ait].extent) - if args.eccentricity or args.all_features: - df['eccentricity'] = df['it'].map(lambda ait: regions[ait].eccentricity) - if args.equivalent_diameter or args.all_features: - df['equivalent_diameter'] = df['it'].map(lambda ait: regions[ait].equivalent_diameter) - if args.euler_number or args.all_features: - df['euler_number'] = df['it'].map(lambda ait: regions[ait].euler_number) - if args.inertia_tensor_eigvals or args.all_features: - df['inertia_tensor_eigvals'] = df['it'].map(lambda ait: regions[ait].inertia_tensor_eigvals) - if args.major_axis_length or args.all_features: - df['major_axis_length'] = df['it'].map(lambda ait: regions[ait].major_axis_length) - if args.minor_axis_length or args.all_features: - df['minor_axis_length'] = df['it'].map(lambda ait: regions[ait].minor_axis_length) - if args.orientation or args.all_features: - df['orientation'] = df['it'].map(lambda ait: regions[ait].orientation) - if args.solidity or args.all_features: - df['solidity'] = df['it'].map(lambda ait: regions[ait].solidity) - if args.moments or args.all_features: - df['moments'] = df['it'].map(lambda ait: regions[ait].moments) - if args.convexity or args.all_features: - perimeter = df['it'].map(lambda ait: regions[ait].perimeter) - area = df['it'].map(lambda ait: regions[ait].area) - df['convexity'] = area / (perimeter * perimeter) - - del df['it'] - df.to_csv(out_file, sep='\t', lineterminator='\n', index=False) +def surface(labels: np.ndarray, label: int) -> int: + """ + Ad-hoc implementation for computation of the "perimeter" of an object in 3D (that is a surface). + """ + assert labels.ndim == 3 # sanity check + + # Create 3-D structuring element with 4-connectivity + selem = np.zeros((3, 3, 3), bool) + for ijk in np.ndindex(*selem.shape): + if (np.array(ijk) == 1).sum() >= 2: + selem[*ijk] = True # noqa: E999 + assert selem.sum() == 7 # sanity check + + # Compute the area of the surface + cc = (labels == label) + cc_interior = ndi.binary_erosion(cc, selem) + surface = np.logical_xor(cc, cc_interior) + return surface.sum() # number of voxels on the surface of the object + + +def compute_if_dask(obj): + """ + Return the computed object or array if it is a Dask array or deferred computable Dask object. + """ + return obj.compute() if hasattr(obj, 'compute') else obj + + +if __name__ == '__main__': + tool = giatools.ToolBaseplate() + tool.add_input_image('labels') + tool.add_input_image('intensities', required=False) + tool.parser.add_argument('--output', type=str) + tool.parse_args() + + # Validate the input image + try: + label_image = tool.args.input_images['labels'] + if any(label_image.shape[label_image.axes.index(axis)] > 1 for axis in label_image.axes if axis not in 'ZYX'): + raise ValueError(f'This tool is not applicable to images with {label_image.original_axes} axes.') + + # Extract the image features + for section in tool.run('ZYX'): # the validation code above guarantees that we will have only a single iteration + df = pd.DataFrame() + + # Get the labels array and cast to `uint8` if it is `bool` (`skimage.measure.regionprops` refuses `bool` typed arrays) + labels_section_data = section['labels'].data.squeeze() + if np.issubdtype(labels_section_data.dtype, bool): + print('Convert labels from bool to uint8') + labels_section_data = labels_section_data.astype(np.uint8) + + # Some features currently cannot be computed from Dask arrays + if any( + feature_name in tool.args.params['features'] for feature_name in ( + 'inertia_tensor_eigvals', + 'axis_major_length', + 'axis_minor_length', + 'eccentricity', + 'orientation', + 'moments_hu', + ) + ): + labels_section_data = compute_if_dask(labels_section_data) + + # Compute the image features + if 'intensities' in tool.args.input_images: + regions = skimage.measure.regionprops(labels_section_data, intensity_image=section['intensities'].data.squeeze()) + else: + regions = skimage.measure.regionprops(labels_section_data, intensity_image=None) + df['it'] = np.arange(len(regions)) + for feature_name in tool.args.params['features']: + + # Add the object label + if feature_name == 'label': + df['label'] = df['it'].map(lambda ait: regions[ait].label) + + # Add the object perimeter/surface + elif feature_name == 'perimeter' and labels_section_data.ndim == 3: + df['perimeter'] = df['it'].map( + lambda ait: surface(labels_section_data, regions[ait].label), # `skimage.measure.regionprops` cannot compute perimeters for 3-D data + ) + + # Skip features that are not available when processing 3-D images + elif feature_name in ('eccentricity', 'moments_hu', 'orientation') and labels_section_data.ndim == 3: + print(f'Skip feature that is not available for 3-D images: "{feature_name}"') + + # Add another feature from `regions` that was computed via `skimage.measure.regionprops` + else: + try: + df[feature_name] = df['it'].map(lambda ait: getattr(regions[ait], feature_name)) + except TypeError: + raise ValueError(f'Unknown feature: "{feature_name}"') + + # Resolve any remaining Dask objects to the actual values (e.g., when processing Zarrs) + df = df.map(compute_if_dask) + + # Convert lists/tuples/arrays to lists of plain Python numbers (e.g., float instead of np.float64) + df = df.map( + lambda obj: np.asarray(obj).tolist() if type(obj) in (list, tuple, np.ndarray) else obj, + ) + + del df['it'] + df.to_csv(tool.args.raw_args.output, sep='\t', lineterminator='\n', index=False) + + except ValueError as err: + exit(err.args[0]) diff --git a/tools/2d_feature_extraction/2d_feature_extraction.xml b/tools/2d_feature_extraction/2d_feature_extraction.xml index 20ef5ac0f..e0c595423 100644 --- a/tools/2d_feature_extraction/2d_feature_extraction.xml +++ b/tools/2d_feature_extraction/2d_feature_extraction.xml @@ -2,84 +2,122 @@ with scikit-image creators.xml - 0.18.1 + validators.xml + 0.25.2 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + operation_3443 scikit-image + giatools + galaxy_image_analysis scikit-image scikit-image pandas - numpy - tifffile - giatools + giatools + ome-zarr - - - + + + + + + + - - - - - + + + + + + + + - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + @@ -87,23 +125,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + + + - **Computes features of a label map.** +**Computes features of a label map.** + +The computed features are computed based solely on the properties of the objects in the label map, or, optionally, by also taking the intensities from a corresponding intensity image into account. Labels with value 0 are ignored. + +Both images must be 2-D or 3-D single-channel images. + +Supported Features +================== + +**Area:** Area of the region i.e. number of pixels of the region scaled by pixel-area. + +**Convex area:** Area of the convex hull image, which is the smallest convex polygon that encloses the region. + +**Filled area:** Area of the region with all the holes filled in. + +**Major axis length:** The length of the major axis of the ellipse that has the same normalized second central moments as the region. + +**Minor axis length:** The length of the minor axis of the ellipse that has the same normalized second central moments as the region. + +**Bounding box:** Bounding box `(min_row, min_col, max_row, max_col)`. Pixels belonging to the bounding box are in the half-open interval `[min_row; max_row)` and `[min_col; max_col)`. + +**Centroid:** Centroid coordinate tuple `(row, col)`. + +**Eccentricity:** Eccentricity of the ellipse that has the same second-moments as the region. The eccentricity is the ratio of the focal distance (distance between focal points) over the major axis length. The value is in the interval [0, 1). When it is 0, the ellipse becomes a circle. + +**Equivalent diameter:** The diameter of a circle with the same area as the region. + +**Euler number:** Euler characteristic of the set of non-zero pixels. Computed as number of connected components subtracted by number of holes (input.ndim connectivity). In 3-D, number of connected components plus number of holes subtracted by number of tunnels. + +**Extent:** Ratio of pixels in the region to pixels in the total bounding box. Computed as `area / (rows * cols)`. + +**Inertia tensor eigenvalues:** The eigenvalues of the inertia tensor in decreasing order. + +**Moments:** Spatial moments up to 3rd order: `m_ij = sum{ array(row, col) * row^i * col^j }` where the sum is over the row, col coordinates of the region. + +**Moments Hu:** Hu moments (translation, scale and rotation invariant). + +**Orientation:** Angle between the vertical axis (rows) and the major axis of the ellipse that has the same second moments as the region, ranging from `-pi/2` to `pi/2` counter-clockwise. - The computed features are computed based solely on the properties of the labels in the label map, - or, optionally, by also taking the intensities from a corresponding intensity image into account. +**Perimeter:** Perimeter of object which approximates the contour as a line through the centers of border pixels using a 4-connectivity. Generalizes to the surface of an object in 3-D, which uses a different approximation. - The label map must be a 2-D or 3-D single-channel image. +**Solidity:** Ratio of pixels in the region to pixels of the convex hull image. diff --git a/tools/2d_feature_extraction/test-data/input.tiff b/tools/2d_feature_extraction/test-data/input.tiff deleted file mode 100644 index 91aea92a1..000000000 Binary files a/tools/2d_feature_extraction/test-data/input.tiff and /dev/null differ diff --git a/tools/2d_feature_extraction/test-data/input/README.md b/tools/2d_feature_extraction/test-data/input/README.md new file mode 100644 index 000000000..aef6c8ef1 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/README.md @@ -0,0 +1,73 @@ +# Overview of the test images + +## Label maps + +### `input9.zarr`: + +- axes: `ZYX` +- resolution: `(2, 100, 100)` +- dtype: `bool` +- binary image +- metadata: + - resolution: `(1.0, 1.0)` + - z-spacing: `1.0` + - unit: `um` + +### `input11.tiff` + +- axes: `YX` +- resolution: `(265, 329)` +- dtype: `uint16` +- binary image + +### `input12.png` + +- axes: `YX` +- resolution: `(58, 64)` +- dtype: `uint8` +- labels: `0...24` + +### `input13.zarr` + +- axes: `YX` +- resolution: `(265, 329)` +- dtype: `uint8` +- labels: `0...2` + +## Intensity images + +### `input1_uint8.tiff`: + +- axes: `YX` +- resolution: `(265, 329)` +- dtype: `uint8` +- metadata: none + +### `input3_uint16.tiff`: + +- axes: `YXC` +- resolution: `(58, 64, 3)` +- dtype: `uint16` +- metadata: + - resolution: `(2.0, 1.0)` + - unit: `mm` + +### `input8_zyx.zarr`: + +- axes: `ZYX` +- resolution: `(2, 100, 100)` +- dtype: `float64` +- metadata: + - resolution: `(1.0, 1.0)` + - z-spacing: `1.0` + - unit: `um` + +### `input10.zarr`: + +- axes: `CYX` +- resolution: `(2, 64, 64)` +- dtype: `uint8` +- metadata: + - resolution: `(1.0, 1.0)` + - z-spacing: `1.0` + - unit: `um` diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/0/c/0/0/0 b/tools/2d_feature_extraction/test-data/input/input10.zarr/0/c/0/0/0 new file mode 100644 index 000000000..2ef34775f Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input10.zarr/0/c/0/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/0/c/1/0/0 b/tools/2d_feature_extraction/test-data/input/input10.zarr/0/c/1/0/0 new file mode 100644 index 000000000..e2860f6a6 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input10.zarr/0/c/1/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/0/zarr.json b/tools/2d_feature_extraction/test-data/input/input10.zarr/0/zarr.json new file mode 100644 index 000000000..d71c27690 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input10.zarr/0/zarr.json @@ -0,0 +1,46 @@ +{ + "shape": [ + 2, + 64, + 64 + ], + "data_type": "uint8", + "chunk_grid": { + "name": "regular", + "configuration": { + "chunk_shape": [ + 1, + 100, + 100 + ] + } + }, + "chunk_key_encoding": { + "name": "default", + "configuration": { + "separator": "/" + } + }, + "fill_value": 0, + "codecs": [ + { + "name": "bytes" + }, + { + "name": "zstd", + "configuration": { + "level": 0, + "checksum": false + } + } + ], + "attributes": {}, + "dimension_names": [ + "c", + "y", + "x" + ], + "zarr_format": 3, + "node_type": "array", + "storage_transformers": [] +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/1/c/0/0/0 b/tools/2d_feature_extraction/test-data/input/input10.zarr/1/c/0/0/0 new file mode 100644 index 000000000..33c5341dc Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input10.zarr/1/c/0/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/1/c/1/0/0 b/tools/2d_feature_extraction/test-data/input/input10.zarr/1/c/1/0/0 new file mode 100644 index 000000000..cb86b5f1c Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input10.zarr/1/c/1/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/1/zarr.json b/tools/2d_feature_extraction/test-data/input/input10.zarr/1/zarr.json new file mode 100644 index 000000000..f60292e64 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input10.zarr/1/zarr.json @@ -0,0 +1,46 @@ +{ + "shape": [ + 2, + 32, + 32 + ], + "data_type": "uint8", + "chunk_grid": { + "name": "regular", + "configuration": { + "chunk_shape": [ + 1, + 100, + 100 + ] + } + }, + "chunk_key_encoding": { + "name": "default", + "configuration": { + "separator": "/" + } + }, + "fill_value": 0, + "codecs": [ + { + "name": "bytes" + }, + { + "name": "zstd", + "configuration": { + "level": 0, + "checksum": false + } + } + ], + "attributes": {}, + "dimension_names": [ + "c", + "y", + "x" + ], + "zarr_format": 3, + "node_type": "array", + "storage_transformers": [] +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/2/c/0/0/0 b/tools/2d_feature_extraction/test-data/input/input10.zarr/2/c/0/0/0 new file mode 100644 index 000000000..278b9f4bf Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input10.zarr/2/c/0/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/2/c/1/0/0 b/tools/2d_feature_extraction/test-data/input/input10.zarr/2/c/1/0/0 new file mode 100644 index 000000000..6cedb9a26 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input10.zarr/2/c/1/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/2/zarr.json b/tools/2d_feature_extraction/test-data/input/input10.zarr/2/zarr.json new file mode 100644 index 000000000..7c0d81839 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input10.zarr/2/zarr.json @@ -0,0 +1,46 @@ +{ + "shape": [ + 2, + 16, + 16 + ], + "data_type": "uint8", + "chunk_grid": { + "name": "regular", + "configuration": { + "chunk_shape": [ + 1, + 100, + 100 + ] + } + }, + "chunk_key_encoding": { + "name": "default", + "configuration": { + "separator": "/" + } + }, + "fill_value": 0, + "codecs": [ + { + "name": "bytes" + }, + { + "name": "zstd", + "configuration": { + "level": 0, + "checksum": false + } + } + ], + "attributes": {}, + "dimension_names": [ + "c", + "y", + "x" + ], + "zarr_format": 3, + "node_type": "array", + "storage_transformers": [] +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/3/c/0/0/0 b/tools/2d_feature_extraction/test-data/input/input10.zarr/3/c/0/0/0 new file mode 100644 index 000000000..dd9423634 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input10.zarr/3/c/0/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/3/c/1/0/0 b/tools/2d_feature_extraction/test-data/input/input10.zarr/3/c/1/0/0 new file mode 100644 index 000000000..089f8dac2 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input10.zarr/3/c/1/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/3/zarr.json b/tools/2d_feature_extraction/test-data/input/input10.zarr/3/zarr.json new file mode 100644 index 000000000..2055db168 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input10.zarr/3/zarr.json @@ -0,0 +1,46 @@ +{ + "shape": [ + 2, + 8, + 8 + ], + "data_type": "uint8", + "chunk_grid": { + "name": "regular", + "configuration": { + "chunk_shape": [ + 1, + 100, + 100 + ] + } + }, + "chunk_key_encoding": { + "name": "default", + "configuration": { + "separator": "/" + } + }, + "fill_value": 0, + "codecs": [ + { + "name": "bytes" + }, + { + "name": "zstd", + "configuration": { + "level": 0, + "checksum": false + } + } + ], + "attributes": {}, + "dimension_names": [ + "c", + "y", + "x" + ], + "zarr_format": 3, + "node_type": "array", + "storage_transformers": [] +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/4/c/1/0/0 b/tools/2d_feature_extraction/test-data/input/input10.zarr/4/c/1/0/0 new file mode 100644 index 000000000..2df69a708 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input10.zarr/4/c/1/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/4/zarr.json b/tools/2d_feature_extraction/test-data/input/input10.zarr/4/zarr.json new file mode 100644 index 000000000..f56724b79 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input10.zarr/4/zarr.json @@ -0,0 +1,46 @@ +{ + "shape": [ + 2, + 4, + 4 + ], + "data_type": "uint8", + "chunk_grid": { + "name": "regular", + "configuration": { + "chunk_shape": [ + 1, + 100, + 100 + ] + } + }, + "chunk_key_encoding": { + "name": "default", + "configuration": { + "separator": "/" + } + }, + "fill_value": 0, + "codecs": [ + { + "name": "bytes" + }, + { + "name": "zstd", + "configuration": { + "level": 0, + "checksum": false + } + } + ], + "attributes": {}, + "dimension_names": [ + "c", + "y", + "x" + ], + "zarr_format": 3, + "node_type": "array", + "storage_transformers": [] +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input10.zarr/zarr.json b/tools/2d_feature_extraction/test-data/input/input10.zarr/zarr.json new file mode 100644 index 000000000..107c0f027 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input10.zarr/zarr.json @@ -0,0 +1,95 @@ +{ + "attributes": { + "ome": { + "version": "0.5", + "multiscales": [ + { + "datasets": [ + { + "path": "0", + "coordinateTransformations": [ + { + "type": "scale", + "scale": [ + 1.0, + 1.0, + 1.0 + ] + } + ] + }, + { + "path": "1", + "coordinateTransformations": [ + { + "type": "scale", + "scale": [ + 1.0, + 2.0, + 2.0 + ] + } + ] + }, + { + "path": "2", + "coordinateTransformations": [ + { + "type": "scale", + "scale": [ + 1.0, + 4.0, + 4.0 + ] + } + ] + }, + { + "path": "3", + "coordinateTransformations": [ + { + "type": "scale", + "scale": [ + 1.0, + 8.0, + 8.0 + ] + } + ] + }, + { + "path": "4", + "coordinateTransformations": [ + { + "type": "scale", + "scale": [ + 1.0, + 16.0, + 16.0 + ] + } + ] + } + ], + "name": "/", + "axes": [ + { + "name": "c", + "type": "channel" + }, + { + "name": "y", + "type": "space" + }, + { + "name": "x", + "type": "space" + } + ] + } + ] + } + }, + "zarr_format": 3, + "node_type": "group" +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input11.tiff b/tools/2d_feature_extraction/test-data/input/input11.tiff new file mode 100644 index 000000000..b2afd0a68 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input11.tiff differ diff --git a/tools/2d_feature_extraction/test-data/input/input12.png b/tools/2d_feature_extraction/test-data/input/input12.png new file mode 100644 index 000000000..d5082ecd9 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input12.png differ diff --git a/tools/2d_feature_extraction/test-data/input/input13.zarr/0/c/0/0 b/tools/2d_feature_extraction/test-data/input/input13.zarr/0/c/0/0 new file mode 100644 index 000000000..494658b65 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input13.zarr/0/c/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input13.zarr/0/zarr.json b/tools/2d_feature_extraction/test-data/input/input13.zarr/0/zarr.json new file mode 100644 index 000000000..f2dd2c325 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input13.zarr/0/zarr.json @@ -0,0 +1,43 @@ +{ + "shape": [ + 265, + 329 + ], + "data_type": "uint8", + "chunk_grid": { + "name": "regular", + "configuration": { + "chunk_shape": [ + 265, + 329 + ] + } + }, + "chunk_key_encoding": { + "name": "default", + "configuration": { + "separator": "/" + } + }, + "fill_value": 0, + "codecs": [ + { + "name": "bytes" + }, + { + "name": "zstd", + "configuration": { + "level": 0, + "checksum": false + } + } + ], + "attributes": {}, + "dimension_names": [ + "Y", + "X" + ], + "zarr_format": 3, + "node_type": "array", + "storage_transformers": [] +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input13.zarr/zarr.json b/tools/2d_feature_extraction/test-data/input/input13.zarr/zarr.json new file mode 100644 index 000000000..c49cd690b --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input13.zarr/zarr.json @@ -0,0 +1,38 @@ +{ + "attributes": { + "ome": { + "version": "0.5", + "multiscales": [ + { + "datasets": [ + { + "path": "0", + "coordinateTransformations": [ + { + "type": "scale", + "scale": [ + 1.0, + 1.0 + ] + } + ] + } + ], + "name": "/", + "axes": [ + { + "name": "Y", + "type": "space" + }, + { + "name": "X", + "type": "space" + } + ] + } + ] + } + }, + "zarr_format": 3, + "node_type": "group" +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input1_uint8.tiff b/tools/2d_feature_extraction/test-data/input/input1_uint8.tiff new file mode 100644 index 000000000..0d1b003b4 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input1_uint8.tiff differ diff --git a/tools/2d_feature_extraction/test-data/input/input3_uint16.tiff b/tools/2d_feature_extraction/test-data/input/input3_uint16.tiff new file mode 100644 index 000000000..a78268fb1 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input3_uint16.tiff differ diff --git a/tools/2d_feature_extraction/test-data/input/input8_zyx.zarr b/tools/2d_feature_extraction/test-data/input/input8_zyx.zarr new file mode 120000 index 000000000..7af6099fa --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input8_zyx.zarr @@ -0,0 +1 @@ +ome-zarr-examples/image-03.zarr \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/0/c/0/0/0 b/tools/2d_feature_extraction/test-data/input/input9.zarr/0/c/0/0/0 new file mode 100644 index 000000000..0a7819de0 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input9.zarr/0/c/0/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/0/c/1/0/0 b/tools/2d_feature_extraction/test-data/input/input9.zarr/0/c/1/0/0 new file mode 100644 index 000000000..fef65d096 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input9.zarr/0/c/1/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/0/zarr.json b/tools/2d_feature_extraction/test-data/input/input9.zarr/0/zarr.json new file mode 100644 index 000000000..a42884236 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input9.zarr/0/zarr.json @@ -0,0 +1,46 @@ +{ + "shape": [ + 2, + 100, + 100 + ], + "data_type": "bool", + "chunk_grid": { + "name": "regular", + "configuration": { + "chunk_shape": [ + 1, + 100, + 100 + ] + } + }, + "chunk_key_encoding": { + "name": "default", + "configuration": { + "separator": "/" + } + }, + "fill_value": false, + "codecs": [ + { + "name": "bytes" + }, + { + "name": "zstd", + "configuration": { + "level": 0, + "checksum": false + } + } + ], + "attributes": {}, + "dimension_names": [ + "z", + "y", + "x" + ], + "zarr_format": 3, + "node_type": "array", + "storage_transformers": [] +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/1/c/0/0/0 b/tools/2d_feature_extraction/test-data/input/input9.zarr/1/c/0/0/0 new file mode 100644 index 000000000..0c9f3c08b Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input9.zarr/1/c/0/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/1/c/1/0/0 b/tools/2d_feature_extraction/test-data/input/input9.zarr/1/c/1/0/0 new file mode 100644 index 000000000..f58c34bd8 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input9.zarr/1/c/1/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/1/zarr.json b/tools/2d_feature_extraction/test-data/input/input9.zarr/1/zarr.json new file mode 100644 index 000000000..548820b7d --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input9.zarr/1/zarr.json @@ -0,0 +1,46 @@ +{ + "shape": [ + 2, + 50, + 50 + ], + "data_type": "bool", + "chunk_grid": { + "name": "regular", + "configuration": { + "chunk_shape": [ + 1, + 100, + 100 + ] + } + }, + "chunk_key_encoding": { + "name": "default", + "configuration": { + "separator": "/" + } + }, + "fill_value": false, + "codecs": [ + { + "name": "bytes" + }, + { + "name": "zstd", + "configuration": { + "level": 0, + "checksum": false + } + } + ], + "attributes": {}, + "dimension_names": [ + "z", + "y", + "x" + ], + "zarr_format": 3, + "node_type": "array", + "storage_transformers": [] +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/2/c/0/0/0 b/tools/2d_feature_extraction/test-data/input/input9.zarr/2/c/0/0/0 new file mode 100644 index 000000000..caf7b4257 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input9.zarr/2/c/0/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/2/c/1/0/0 b/tools/2d_feature_extraction/test-data/input/input9.zarr/2/c/1/0/0 new file mode 100644 index 000000000..f5331c9a9 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input9.zarr/2/c/1/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/2/zarr.json b/tools/2d_feature_extraction/test-data/input/input9.zarr/2/zarr.json new file mode 100644 index 000000000..dc4b3315d --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input9.zarr/2/zarr.json @@ -0,0 +1,46 @@ +{ + "shape": [ + 2, + 25, + 25 + ], + "data_type": "bool", + "chunk_grid": { + "name": "regular", + "configuration": { + "chunk_shape": [ + 1, + 100, + 100 + ] + } + }, + "chunk_key_encoding": { + "name": "default", + "configuration": { + "separator": "/" + } + }, + "fill_value": false, + "codecs": [ + { + "name": "bytes" + }, + { + "name": "zstd", + "configuration": { + "level": 0, + "checksum": false + } + } + ], + "attributes": {}, + "dimension_names": [ + "z", + "y", + "x" + ], + "zarr_format": 3, + "node_type": "array", + "storage_transformers": [] +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/3/c/0/0/0 b/tools/2d_feature_extraction/test-data/input/input9.zarr/3/c/0/0/0 new file mode 100644 index 000000000..a33bd7699 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input9.zarr/3/c/0/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/3/c/1/0/0 b/tools/2d_feature_extraction/test-data/input/input9.zarr/3/c/1/0/0 new file mode 100644 index 000000000..ffa5f4c0e Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input9.zarr/3/c/1/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/3/zarr.json b/tools/2d_feature_extraction/test-data/input/input9.zarr/3/zarr.json new file mode 100644 index 000000000..6e41e8dc3 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input9.zarr/3/zarr.json @@ -0,0 +1,46 @@ +{ + "shape": [ + 2, + 12, + 12 + ], + "data_type": "bool", + "chunk_grid": { + "name": "regular", + "configuration": { + "chunk_shape": [ + 1, + 100, + 100 + ] + } + }, + "chunk_key_encoding": { + "name": "default", + "configuration": { + "separator": "/" + } + }, + "fill_value": false, + "codecs": [ + { + "name": "bytes" + }, + { + "name": "zstd", + "configuration": { + "level": 0, + "checksum": false + } + } + ], + "attributes": {}, + "dimension_names": [ + "z", + "y", + "x" + ], + "zarr_format": 3, + "node_type": "array", + "storage_transformers": [] +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/4/c/0/0/0 b/tools/2d_feature_extraction/test-data/input/input9.zarr/4/c/0/0/0 new file mode 100644 index 000000000..f3eedd45a Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input9.zarr/4/c/0/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/4/c/1/0/0 b/tools/2d_feature_extraction/test-data/input/input9.zarr/4/c/1/0/0 new file mode 100644 index 000000000..4aa4866f0 Binary files /dev/null and b/tools/2d_feature_extraction/test-data/input/input9.zarr/4/c/1/0/0 differ diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/4/zarr.json b/tools/2d_feature_extraction/test-data/input/input9.zarr/4/zarr.json new file mode 100644 index 000000000..266304c53 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input9.zarr/4/zarr.json @@ -0,0 +1,46 @@ +{ + "shape": [ + 2, + 6, + 6 + ], + "data_type": "bool", + "chunk_grid": { + "name": "regular", + "configuration": { + "chunk_shape": [ + 1, + 100, + 100 + ] + } + }, + "chunk_key_encoding": { + "name": "default", + "configuration": { + "separator": "/" + } + }, + "fill_value": false, + "codecs": [ + { + "name": "bytes" + }, + { + "name": "zstd", + "configuration": { + "level": 0, + "checksum": false + } + } + ], + "attributes": {}, + "dimension_names": [ + "z", + "y", + "x" + ], + "zarr_format": 3, + "node_type": "array", + "storage_transformers": [] +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/input9.zarr/zarr.json b/tools/2d_feature_extraction/test-data/input/input9.zarr/zarr.json new file mode 100644 index 000000000..b96da58f9 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/input9.zarr/zarr.json @@ -0,0 +1,98 @@ +{ + "attributes": { + "ome": { + "version": "0.5", + "multiscales": [ + { + "datasets": [ + { + "path": "0", + "coordinateTransformations": [ + { + "type": "scale", + "scale": [ + 1.0, + 1.0, + 1.0 + ] + } + ] + }, + { + "path": "1", + "coordinateTransformations": [ + { + "type": "scale", + "scale": [ + 1.0, + 2.0, + 2.0 + ] + } + ] + }, + { + "path": "2", + "coordinateTransformations": [ + { + "type": "scale", + "scale": [ + 1.0, + 4.0, + 4.0 + ] + } + ] + }, + { + "path": "3", + "coordinateTransformations": [ + { + "type": "scale", + "scale": [ + 1.0, + 8.333333333333334, + 8.333333333333334 + ] + } + ] + }, + { + "path": "4", + "coordinateTransformations": [ + { + "type": "scale", + "scale": [ + 1.0, + 16.666666666666668, + 16.666666666666668 + ] + } + ] + } + ], + "name": "/", + "axes": [ + { + "name": "z", + "type": "space", + "unit": "micrometer" + }, + { + "name": "y", + "type": "space", + "unit": "micrometer" + }, + { + "name": "x", + "type": "space", + "unit": "micrometer" + } + ] + } + ] + } + }, + "zarr_format": 3, + "node_type": "group" +} diff --git a/tools/2d_feature_extraction/test-data/input/ome-zarr-examples/LICENSE b/tools/2d_feature_extraction/test-data/input/ome-zarr-examples/LICENSE new file mode 100644 index 000000000..fe10a3ceb --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/ome-zarr-examples/LICENSE @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2023, Tommaso Comparin + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tools/2d_feature_extraction/test-data/input/ome-zarr-examples/image-03.zarr/.zattrs b/tools/2d_feature_extraction/test-data/input/ome-zarr-examples/image-03.zarr/.zattrs new file mode 100644 index 000000000..b8cfbbd17 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/ome-zarr-examples/image-03.zarr/.zattrs @@ -0,0 +1,40 @@ +{ + "multiscales": [ + { + "axes": [ + { + "name": "z", + "type": "space", + "unit": "micrometer" + }, + { + "name": "y", + "type": "space", + "unit": "micrometer" + }, + { + "name": "x", + "type": "space", + "unit": "micrometer" + } + ], + "datasets": [ + { + "coordinateTransformations": [ + { + "scale": [ + 1.0, + 1.0, + 1.0 + ], + "type": "scale" + } + ], + "path": "0" + } + ], + "version": "0.4" + } + ], + "version": "0.4" +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/ome-zarr-examples/image-03.zarr/.zgroup b/tools/2d_feature_extraction/test-data/input/ome-zarr-examples/image-03.zarr/.zgroup new file mode 100644 index 000000000..3b7daf227 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/ome-zarr-examples/image-03.zarr/.zgroup @@ -0,0 +1,3 @@ +{ + "zarr_format": 2 +} \ No newline at end of file diff --git a/tools/2d_feature_extraction/test-data/input/ome-zarr-examples/image-03.zarr/0/.zarray b/tools/2d_feature_extraction/test-data/input/ome-zarr-examples/image-03.zarr/0/.zarray new file mode 100644 index 000000000..37c8bbba3 --- /dev/null +++ b/tools/2d_feature_extraction/test-data/input/ome-zarr-examples/image-03.zarr/0/.zarray @@ -0,0 +1,25 @@ +{ + "chunks": [ + 1, + 50, + 100 + ], + "compressor": { + "blocksize": 0, + "clevel": 5, + "cname": "lz4", + "id": "blosc", + "shuffle": 1 + }, + "dimension_separator": "/", + "dtype": "