Skip to content

Latest commit

 

History

History
121 lines (89 loc) · 8.68 KB

File metadata and controls

121 lines (89 loc) · 8.68 KB

Contributing

This document is the attempt to collect some rough rules for tools to follow in this repository, to facilitate their consistency and interoperability. This document is an extension to the Naming and Annotation Conventions for Tools in the Image Community in Galaxy and compatibility should be maintained. This document is work in progress.

How to Contribute:

Terminology

Label maps are images with pixel-level annotations, usually corresponding to distinct image regions (e.g., objects). We avoid the terms label image and labeled image, since these can be easily confused with image-level annotations (instead of pixel-level). The labels (pixel values) must uniquely identify the labeled image regions (i.e. labels must be unique, even for non-adjacent image regions). If a label semantically corresponds to the image background, that label should be 0.

Binary images are a special case of label maps with only two labels (e.g., image background and image foreground). To facilitate visual perception, the foreground label should correspond to white (value 255 for uint8 images and value 65535 for uint16 images), since background corresponds to the label 0, which is black.

Intensity images are images which generally are not label maps (and thus neither binary images).

Image data representations and file types

Tools with label map inputs should accept PNG and TIFF files. Tools with label map outputs should produce either uint16 single-channel PNG or uint16 single-channel TIFF. Using uint8 instead of uint16 is also acceptable, if there definetely are no more than 256 different labels. Using uint8 should be preferred for binary images.

Note

It is a common misconception that PNG files must be RGB or RGBA, and that only uint8 pixel values are supported. For example, the cv2 module (OpenCV) can be used to write single-channel PNG files, or PNG files with uint16 pixel values. Such files can then be read by giatools.Image.read or skimage.io.imread without issues (however, skimage.io.imwrite seems not to be able to write such PNG files). Another common misconception is that JPG must be RGB—they can also be single-channel.

Tools with intensity image inputs should accept PNG and TIFF files. Tools with intensity image outputs can be any data type and either PNG or TIFF. Image outputs meant for visualization (e.g., segmentation overlays, charts) should be PNG.

giatools

In tool wrappers which use a Python script, image loading should be performed by using the giatools package (docs). This gives you out-of-the-box support for a veriety of file types, including TIFF, PNG, JPG, and OME-Zarr, and generally reduces the amount of redundant boilerplate code.

Another advantage is that giatools gives you out-of-the-box support for 3-D images, multi-channel-images, and other rather exotic format flavors, even if the wrapped image processing/analysis operation only supports 2-D image data. For example, if the wrapped operation only support single-channel 2-D images, the following tool wrapper code structure can be used to process all slices of 3-D images, all channels of multi-channel images, and so on:

if __name__ == '__main__':
    tool = giatools.ToolBaseplate()
    tool.add_input_image('input')
    tool.add_output_image('output')
    for section in tool.run('YX'):
        # Process each slice, e.g., copy the input slice:
        section['output'] = section['input'].data

This has also the advantage that the metadata of the output image will be preserved (based on the metadata of the first input image). The script can then be binded into the XML of the tool wrapper easily:

    <command detect_errors="aggressive"><![CDATA[
        python '$__tool_directory__/script.py'

        #if $input.extension == "zarr"
            --input '$input.extra_files_path/$input.metadata.store_root'
        #else
            --input '$input'
        #end if

        --output 'output.tiff'
        --verbose
    ]]></command>

The --verbose argument makes sure that useful metadata information will be printed to the standard output of the tool when run in Galaxy. In addition, arbitrary JSON-encoded parameters can be passed to the script via the --params argument. Those are then available as a plain dictionary by accessing tool.args.params within the script.

If you prefer to write the structure of the tool wrapper code yourself, you can also utilize giatools on a rather lower level:

image = giatools.Image.read(args.input)
for source_slice, section in image.iterate_jointly('XY'):
    ...  # process the 2-D `section` of the image

See the docs for details. You can also access the pixel/voxel data of the image directly (described below).

numpy

Instead of using functions from the global namespace of the numpy package to process the section or image.data, it is preferred to use the methods of the section and image.data objects directly (e.g., prefer image.data.mean() over numpy.mean(image.data)). This is because, for some file types (e.g., OME-Zarr), those objects will be Dask arrays, and although these should fit in transparently into the NumPy framework, using implementation-specific methods promises greater efficiency of the computational performance, especially for large datasets.

Testing

We recommend using macros for verification of image outputs. The macros are loaded as follows:

<macros>
    <import>tests.xml</import>
</macros>

Testing binary image outputs

For testing of binary image outputs we recommend using the mae metric (mean absolute error). The default value for eps of 0.01 is rather strict, and for 0/1 binary images this asserts that at most 1% of the image pixels are labeled differently:

<expand macro="tests/binary_image_diff" name="output" value="output.tif" ftype="tiff"/>

For 0/255 binary images, the same 1% tolerance would be achieved by increasing eps to 2.25. The macro also ensures that the image contains two distinct label values.

Testing label map outputs

For testing of non-binary label map outputs with interchangeable labels, we recommend using the iou metric (one minus the intersection over the union). With the default value of eps of 0.01, this asserts that there is no labeled image region with an intersection over the union of less than 99%:

<expand macro="tests/label_image_diff" name="output" value="output.tif" ftype="tiff"/>

Label 0 is commonly connotated as the image background, and is not interchangable by default. Use pin_labels="" to make it interchangable.

Testing intensity image outputs

For testing of intensity image outputs we recommend the rms metric (root mean square), because it is very sensitive to large pixel value differences, but tolerates smaller differences:

<expand macro="tests/intensity_image_diff" name="output" value="output.tif" ftype="tiff"/>

For uint8 and uint16 images, increasing the default value of eps to 1.0 should be tolerable, if required.

Future extensions

Below is a list of open questions:

  • How do we want to cope with multi-channel label maps? For example, do or can we distinguish RGB labels from multi-channel binary masks, which are sometimes used to represent overlapping objects?

Below is a list of changes that need to be reflected in this document: