Package: medio
medioMedical images I/O python packageThis package unifies the io engines of itk, nibabel, and pydicom (including dicom-numpy) packages
in a simple and comprehensive interface.It includes conversion between the metadata conventions, reorientations, affine matrix computation
for itk and pydicom and saving dicom series or file.InstallationFirst, make sure you have the latest pip version (better to close PyCharm or any other program that
uses the environments):(<env-name>) >pip install -U pipInstallmediowith:(<env-name>) >pip install -U medioThis will install the medio python package and its dependencies in your environment.RequirementsThe dependencies are:python (at least 3.6)numpyitknibabelpydicomdicom-numpyA conda environment .yml file is in the project's root.
Some dicom images may require installation of additional packages, gdcm for example.UsageThere are 3 main functions in medio:read_img,save_imgandsave_dir.frommedioimportread_img,save_img# read a dicom series from a folderarray,metadata=read_img('data/dicom-folder/',desired_ornt='IAR')# do your stuff and save in any formatsave_img('ct.nii.gz',array,metadata,backend='nib')DocumentationReading and Saving Imagesread_imgmedio.read_img(input_path, desired_ornt=None, backend=None, dtype=None, header=False,  channels_axis=-1, coord_sys='itk', **kwargs)input_path:path-likePath for the data to be read (str or pathlib.Path object for example). It can be a file or a
folder (in the case of a dicom series). It is the only required parameter.
If the input path is a folder, it should contain a single dicom series.
If there is more than a single series, the optional parameterseriescan help.Returns:array, metadataarray of typenumpy.ndarrayand metadata of typemedio.MetaData. The first is a numpy array
of the image, and the second is a metadata object of the image (seeMetaDataclass
documentation).Optional parameters:desired_ornt:orientation string or NoneThe desired orientation of the returned image array, e.g. 'RAI'. If None, no reorientation is
performed.
The desired orientation is in the standard defined bycoord_sys(itk by default).
See alsoOrientation).Ifdesired_orntis the same as the original image's orientation, no reorientation is performed.backend:'nib', 'itk', 'pydicom', 'pdcm', or NoneThe backend IO engine to use: 'nib' (nibabel), 'itk' or 'pydicom' (also 'pdcm'). If None, the
backend is chosen automatically: 'nib' for nifti files (e.g. '.nii' or '.nii.gz' suffix),
otherwise 'itk'.dtype:numpy data-type or NoneIf not None, equivalent toarray.astype(dtype)on the returned image array.header:boolIf True, the returned metadata includes also ametadata.headerattribute that stores the raw
metadata of the file as a dictionary.This is not implemented for series of files (folderinput_path), and not used during saving.channels_axis:int or NoneIf not None and the image has more than a single channel / component (e.g. RGB or RGBA), the
channels axis ischannels_axis. If None, the backend's original convention is used.coord_sys:'itk', 'nib', or NoneThe coordinate system (or convention) of thedesired_orntparameter and the returned metadata.
None means that the backend will determinecoord_sys, but it can lead to a backend-dependent
array and metadata.**kwargsare additional per-backend optional parameters:'itk' backend:pixel_type=itk.SS:itk pixel-type or NoneItk pixel type of the image file/folder. The default value is int16 (itk.SS- Signed Short).
Other common pixel types are:itk.UC- uint8,itk.US- uint16.You can use the functionitk.ctypein order to convert C-types to itk types. For example:itk.ctype('unsigned short') == itk.USfallback_only=True:boolIf True, the pixel type is automatically found and if failed thenpixel_typeis used
(pixel_typemust not be None in this case).Note: ifitk.imread(input_path)fails, usingfallback_only=Truewill result in a slightly
inferior performance. If you know what is pixel-type of the image beforehand, you can set it
withpixel_typeand usefallback_only=False.series=None:str, int or NoneIfinput_pathis a directory that contains multiple dicom series, selecting a specific one is
possible with theseriesargument. It can be the exact series instance UID (str), an int
between 0 and n-1, where n is the number of series in the directory, or None.Ifseriesis None and there are multiple series in the directory, a detailed error message
is raised.'pydicom' backendglobber='*':strRelevant for a directory - glob pattern for selecting the series files (all the files in the
directory by default).allow_default_affine=False:boolRelevant for a multiframe dicom file - if True and the dicom misses some physical tags for the
affine calculation, use a default affine value.series=None:str, int or NoneThe counterpart ofseriesin itk backend, see the explanation above.save_imgmedio.save_img(filename, np_image, metadata, use_original_ornt=True, backend=None, dtype=None,  channels_axis=None, mkdir=False, parents=False, **kwargs)filename:path-likeThe file to be saved, including the format suffix.np_image:numpy.ndarrayThe image array.metadata:medio.MetaDataThe corresponding metadata, frommedio.read_imgfor example. In the absence of a known
metadata, a default one can be constructed withmedio.MetaData(np.eye(4)).Optional parameters:use_original_ornt:boolWhether to save in the original orientation stored inmetadata.orig_orntor not.backend:'nib', 'itk' or NoneThe backend to use: 'nib' or 'itk'. If None, 'nib' is chosen for nifti files and 'itk' otherwise.dtype:numpy data-type or NoneIf not None, equivalent to passingnp_image.astype(dtype). Note that not every dtype is
supported in saving, so make sure what is the dtype of the image array you want to save.channels_axis:int or NoneIf not None, the image has channels (e.g. RGB) along the axischannels_axisofnp_image.mkdir:boolIf True, creates the directory offilename.parents:boolTo be used withmkdir=True. If True, creates also the parent directories.'itk' backend optional parameters (**kwargs):allow_dcm_reorient=False:boolWhen saving a dicom file ('.dcm' or '.dicom' suffix) the image orientation should be right-handed.
If it is left-handed, the image can be reoriented to a right-handed orientation by setting this
parameter to True, which flips the last axis direction.compression=False:boolWhether to use compression in itk writer. Using a '.nii.gz' suffix infilenamealso compresses
the image.save_dirmedio.save_dir(dirname, np_image, metadata, use_original_ornt=True, dtype=None, channels_axis=None, parents=False, exist_ok=False, allow_dcm_reorient=False, **kwargs)Save a 3d numpy arraynp_imageas a dicom series of 2d slices in the directorydirname(itk
backend).dirname:path-likeThe directory to save the files in (str or pathlib.Path). If it exists, it must be empty (unlessexist_okis True).The other parameters:np_image,metadata,use_original_ornt,dtype,channels_axis,parentsandallow_dcm_reorientare equivalent to those ofsave_img.Additional optional parameters (**kwargs):exist_ok:boolIf True, non-empty existing directory will not raise an error.pattern='IM{}.dcm':strPattern for the filenames to save, including a placeholder ('{}') for the slice number.
For example, one can use:pattern={:03d}.metadata_dict=None:dict or NoneDictionary of metadata for adding tags or overriding the default values. For example,metadata_dict={'0008|0060': 'US'}will override the default 'CT' modality and set it to 'US'
(ultrasound).Metadata ObjectsAffinemedio.AffineThe affine of an image is a transformation between the index space of the array to the physical 3d
space. The Affine class is a subclass of numpy.ndarray with some special properties (attributes):spacing,origin, anddirection, which can be accessed and set. The methodindex2coordmaps
the indices to the physical space,cloneclones the affine.This class includes also some static methods for affine construction from its components (spacing,
origin and direction) and also the inverse methods for getting the spacing, origin and direction
matrix from a general affine matrix.For a mathematical explanation about the affine matrix seeNiBabel's affine documentation.Some usage examples:>>>importnumpyasnp>>>frommedioimportAffine>>>affine1=Affine(np.eye(4))>>>affine2=Affine(direction=np.eye(3),spacing=[0.33,1,0.33],origin=[-90.3,10,1.44])>>>index=[4,0,9]>>>coord=affine2.index2coord(index)>>>print(coord)[-88.9810.4.41]MetaDatamedio.MetaDataTogether with the image's numpy array, the MetaData object is a necessary component for the I/O
functions.A MetaData object 'metadata' is mainly comprised of:metadata.affine: the affine (of class Affine)metadata.coord_sys: coordinate system ('itk' or 'nib')metadata.orig_ornt: the original orientation of the image (used for saving)metadata.header: a dictionary that includes additional metadata properties whenheader=Trueinread_img, otherwise NoneOther properties of the metadata are derived from the affine:metadata.spacing: voxels spacing (a reference tometadata.affine.spacing)metadata.ornt: the current image orientation (depends on the coordinate systemcoord_sys)All these properties can be viewed easily in the console:>>>importmedio>>>array,metadata=medio.read_img('avg152T1_LR_nifti.nii.gz',header=False)>>>print(metadata)Affine:[[-2.0.0.90.][0.2.0.-126.][0.0.2.-72.][0.0.0.1.]]Spacing:[2.2.2.]Coordinatesystem:nibOrientation:LASOriginalorientation:LASHeader:NoneThe MetaData methodmetadata.is_right_handed_ornt()checks for a right handed orientation
according to the determinant of the direction matrix (metadata.affine.direction). This method can
be useful before saving a dicom file or series, which should have a right-handed orientation.The methodcloneclones the metadata object,convertconverts the metadata in-place to the
given coordinate system.OrientationThe orientation of a 3d image is string of length 3 that is derived from its affine and coordinate
system (the convention). It denotes along which physical axis we move when we increase a single
index out ofi, j, kin the expressionnp_image[i, j, k].For example, 'RAS' orientation in itk:Right to Left,Anterior to Posterior,Superior to Inferior'RAS' in nib - also 'RAS+':Left toRight, Posterior toAnterior, Inferior toSuperiorNote that the conventions are opposite. For stability reasons, we use itk convention by default
forread_img's argumentdesired_ornt, although one can choose otherwise with the parametercoord_sys.For further discussion seeNiBabel's image orientation documentation.Array and Metadata OperationsSome operations on an image affect also its metadata, for example resizing, rotations and cropping.The class MedImg (medio.medimg.medimg.MedImg) holds an image array with its metadata, and
supports some of these operations through the indexing syntax:>>>frommedio.medimg.medimgimportMedImg>>>mimg=MedImg(np_image,metadata)>>>new_mimg=mimg[:,4:-4,::3]>>>print(new_mimg.metadata)Ellipsis ('...') syntax is also supported. This indexing allows cropping and basic down-sampling,
along with correct metadata update.