# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['medio', 'medio.backends', 'medio.medimg', 'medio.metadata', 'medio.utils']

package_data = \
{'': ['*']}

install_requires = \
['dicom-numpy>=0.5.0,<1',
 'itk>=5.1.2,<6.0.0',
 'nibabel>=3.2.1,<4.0.0',
 'pydicom>=2.1.2,<3.0.0']

extras_require = \
{':python_version >= "3.7" and python_version < "3.11"': ['numpy>=1.21.5,<2.0.0'],
 ':python_version >= "3.8" and python_version < "4.0"': ['numpy>=1.22.2,<2.0.0']}

setup_kwargs = {
    'name': 'medio',
    'version': '0.4.2',
    'description': 'Medical images I/O Python package',
    'long_description': "[![Python version](\nhttps://img.shields.io/pypi/pyversions/medio.svg)](\nhttps://img.shields.io/pypi/pyversions/medio.svg)\n[![PyPI version](\nhttps://badge.fury.io/py/medio.svg)](\nhttps://badge.fury.io/py/medio)\n# medio\n\n**Medical images I/O python package**\n\nThis package unifies the io engines of itk, nibabel, and pydicom (including dicom-numpy) packages \nin a simple and comprehensive interface.\n\nIt includes conversion between the metadata conventions, reorientations, affine matrix computation \nfor itk and pydicom and saving dicom series or file.\n\n# Installation\nFirst, make sure you have the latest pip version (better to close PyCharm or any other program that \nuses the environments):\n```\n(<env-name>) >pip install -U pip\n```\nInstall *medio* with:\n```\n(<env-name>) >pip install -U medio\n```\nThis will install the medio python package and its dependencies in your environment.\n\n### Requirements\nThe dependencies are:\n- python (at least 3.6)\n- numpy\n- itk\n- nibabel\n- pydicom\n- dicom-numpy\n\nA conda environment .yml file is in the project's root.\nSome dicom images may require installation of additional packages, gdcm for example.\n\n# Usage\nThere are 3 main functions in medio: `read_img`, `save_img` and `save_dir`.\n```python\nfrom medio import read_img, save_img\n# read a dicom series from a folder\narray, metadata = read_img('data/dicom-folder/', desired_ornt='IAR')\n# do your stuff and save in any format\nsave_img('ct.nii.gz', array, metadata, backend='nib')\n```\n\n# Documentation\n## Reading and Saving Images\n\n### read_img\n`medio.read_img(input_path, desired_ornt=None, backend=None, dtype=None, header=False, \nchannels_axis=-1, coord_sys='itk', **kwargs)`\n- `input_path`: *path-like*<br>\n  Path for the data to be read (str or pathlib.Path object for example). It can be a file or a \n  folder (in the case of a dicom series). It is the only required parameter.\n  If the input path is a folder, it should contain a single dicom series. \n  If there is more than a single series, the optional parameter `series` can help. \n- Returns: *array, metadata*<br>\n  array of type *numpy.ndarray* and metadata of type *medio.MetaData*. The first is a numpy array \n  of the image, and the second is a metadata object of the image (see [MetaData](#metadata) class \n  documentation).\n\nOptional parameters:\n- `desired_ornt`: *orientation string or None*<br>\n  The desired orientation of the returned image array, e.g. 'RAI'. If None, no reorientation is \n  performed.\n  The desired orientation is in the standard defined by `coord_sys` (itk by default). \n  See also [Orientation](#orientation)).<br>\n  If `desired_ornt` is the same as the original image's orientation, no reorientation is performed.\n- `backend`: *'nib', 'itk', 'pydicom', 'pdcm', or None*<br>\n  The backend IO engine to use: 'nib' (nibabel), 'itk' or 'pydicom' (also 'pdcm'). If None, the \n  backend is chosen automatically: 'nib' for nifti files (e.g. '.nii' or '.nii.gz' suffix), \n  otherwise 'itk'.\n- `dtype`: *numpy data-type or None*<br>\n  If not None, equivalent to `array.astype(dtype)` on the returned image array.\n- `header`: *bool*<br>\n  If True, the returned metadata includes also a `metadata.header` attribute that stores the raw \n  metadata of the file as a dictionary.<br>\n  This is not implemented for series of files (folder `input_path`), and not used during saving.\n- `channels_axis`: *int or None*<br>\n  If not None and the image has more than a single channel / component (e.g. RGB or RGBA), the \n  channels axis is `channels_axis`. If None, the backend's original convention is used.\n- `coord_sys`: *'itk', 'nib', or None*<br>\n  The coordinate system (or convention) of the `desired_ornt` parameter and the returned metadata.\n  None means that the backend will determine `coord_sys`, but it can lead to a backend-dependent \n  array and metadata.\n\n`**kwargs` are additional per-backend optional parameters:\n- 'itk' backend:\n  - `pixel_type=itk.SS`: *itk pixel-type or None*<br>\n    Itk pixel type of the image file/folder. The default value is int16 (`itk.SS` - Signed Short). \n    Other common pixel types are: `itk.UC` - uint8, `itk.US` - uint16.<br>\n    You can use the function `itk.ctype` in order to convert C-types to itk types. For example:<br>\n    `itk.ctype('unsigned short') == itk.US`\n  - `fallback_only=True`: *bool*<br>\n    If True, the pixel type is automatically found and if failed then `pixel_type` is used \n    (`pixel_type` must not be None in this case).<br>\n    Note: if `itk.imread(input_path)` fails, using `fallback_only=True` will result in a slightly \n    inferior performance. If you know what is pixel-type of the image beforehand, you can set it \n    with `pixel_type` and use `fallback_only=False`.\n  - `series=None`: *str, int or None*<br>\n    If `input_path` is a directory that contains multiple dicom series, selecting a specific one is \n    possible with the `series` argument. It can be the exact series instance UID (str), an int \n    between 0 and n-1, where n is the number of series in the directory, or None.<br>\n    If `series` is None and there are multiple series in the directory, a detailed error message \n    is raised.\n\n- 'pydicom' backend\n  - `globber='*'`: *str*<br>\n    Relevant for a directory - glob pattern for selecting the series files (all the files in the \n    directory by default).\n  - `allow_default_affine=False`: *bool*<br>\n    Relevant for a multiframe dicom file - if True and the dicom misses some physical tags for the \n    affine calculation, use a default affine value.\n  - `series=None`: *str, int or None*<br>\n    The counterpart of `series` in itk backend, see the explanation above.\n\n### save_img\n`medio.save_img(filename, np_image, metadata, use_original_ornt=True, backend=None, dtype=None, \nchannels_axis=None, mkdir=False, parents=False, **kwargs)`\n- `filename`: *path-like*<br>\n  The file to be saved, including the format suffix.\n- `np_image`: *numpy.ndarray*<br>\n  The image array.\n- `metadata`: *medio.MetaData*<br>\n  The corresponding metadata, from `medio.read_img` for example. In the absence of a known \n  metadata, a default one can be constructed with `medio.MetaData(np.eye(4))`.\n\nOptional parameters:\n- `use_original_ornt`: *bool*<br> \n  Whether to save in the original orientation stored in `metadata.orig_ornt` or not.\n- `backend`: *'nib', 'itk' or None*<br>\n  The backend to use: 'nib' or 'itk'. If None, 'nib' is chosen for nifti files and 'itk' otherwise.\n- `dtype`: *numpy data-type or None*<br>\n  If not None, equivalent to passing `np_image.astype(dtype)`. Note that not every dtype is \n  supported in saving, so make sure what is the dtype of the image array you want to save.\n- `channels_axis`: *int or None*<br>\n  If not None, the image has channels (e.g. RGB) along the axis `channels_axis` of `np_image`.\n- `mkdir`: *bool*<br>\n  If True, creates the directory of `filename`.\n- `parents`: *bool*<br>\n  To be used with `mkdir=True`. If True, creates also the parent directories. \n\n'itk' backend optional parameters (`**kwargs`):\n- `allow_dcm_reorient=False`: *bool*<br>\n  When saving a dicom file ('.dcm' or '.dicom' suffix) the image orientation should be right-handed.\n  If it is left-handed, the image can be reoriented to a right-handed orientation by setting this \n  parameter to True, which flips the last axis direction.\n- `compression=False`: *bool*<br>\n  Whether to use compression in itk writer. Using a '.nii.gz' suffix in `filename` also compresses\n  the image.\n\n### save_dir\n`medio.save_dir(dirname, np_image, metadata, use_original_ornt=True, dtype=None, channels_axis=None,\nparents=False, exist_ok=False, allow_dcm_reorient=False, **kwargs)`\n\nSave a 3d numpy array `np_image` as a dicom series of 2d slices in the directory `dirname` (itk \nbackend).\n\n- `dirname`: *path-like*<br>\n  The directory to save the files in (str or pathlib.Path). If it exists, it must be empty (unless \n  `exist_ok` is True).\n\nThe other parameters: `np_image`, `metadata`, `use_original_ornt`, `dtype`, `channels_axis`, \n`parents` and `allow_dcm_reorient` are equivalent to those of [save_img](#save_img).\n\nAdditional optional parameters (`**kwargs`):\n- `exist_ok`: *bool*<br>\n  If True, non-empty existing directory will not raise an error.\n- `pattern='IM{}.dcm'`: *str*<br>\n  Pattern for the filenames to save, including a placeholder ('`{}`') for the slice number.\n  For example, one can use: `pattern={:03d}`.\n- `metadata_dict=None`: *dict or None*<br>\n  Dictionary of metadata for adding tags or overriding the default values. For example, \n  `metadata_dict={'0008|0060': 'US'}` will override the default 'CT' modality and set it to 'US' \n  (ultrasound).\n\n## Metadata Objects\n### Affine\n`medio.Affine`\n\nThe affine of an image is a transformation between the index space of the array to the physical 3d \nspace. The Affine class is a subclass of numpy.ndarray with some special properties (attributes): \n`spacing`, `origin`, and `direction`, which can be accessed and set. The method `index2coord` maps \nthe indices to the physical space, `clone` clones the affine.\n\nThis class includes also some static methods for affine construction from its components (spacing, \norigin and direction) and also the inverse methods for getting the spacing, origin and direction \nmatrix from a general affine matrix.\n\nFor a mathematical explanation about the affine matrix see \n[NiBabel's affine documentation](\nhttps://nipy.org/nibabel/coordinate_systems.html#the-affine-matrix-as-a-transformation-between-spaces).\n\nSome usage examples:\n```python\n>>> import numpy as np\n>>> from medio import Affine\n>>> affine1 = Affine(np.eye(4))\n>>> affine2 = Affine(direction=np.eye(3), spacing=[0.33, 1, 0.33], origin=[-90.3, 10, 1.44])\n>>> index = [4, 0, 9]\n>>> coord = affine2.index2coord(index)\n>>> print(coord)\n[-88.98  10.     4.41]\n```\n\n### MetaData\n`medio.MetaData`\n\nTogether with the image's numpy array, the MetaData object is a necessary component for the I/O \nfunctions.\n\nA MetaData object 'metadata' is mainly comprised of:\n- `metadata.affine`: the affine (of class Affine)\n- `metadata.coord_sys`: coordinate system ('itk' or 'nib') \n- `metadata.orig_ornt`: the original orientation of the image (used for saving)\n- `metadata.header`: a dictionary that includes additional metadata properties when `header=True` \n  in `read_img`, otherwise None\n\nOther properties of the metadata are derived from the affine:\n- `metadata.spacing`: voxels spacing (a reference to `metadata.affine.spacing`) \n- `metadata.ornt`: the current image orientation (depends on the coordinate system `coord_sys`)\n\nAll these properties can be viewed easily in the console:\n```python\n>>> import medio\n>>> array, metadata = medio.read_img('avg152T1_LR_nifti.nii.gz', header=False)\n>>> print(metadata)\nAffine:\n[[  -2.    0.    0.   90.]\n [   0.    2.    0. -126.]\n [   0.    0.    2.  -72.]\n [   0.    0.    0.    1.]]\nSpacing: [2. 2. 2.]\nCoordinate system: nib\nOrientation: LAS\nOriginal orientation: LAS\nHeader: None\n```\nThe MetaData method `metadata.is_right_handed_ornt()` checks for a right handed orientation \naccording to the determinant of the direction matrix (`metadata.affine.direction`). This method can \nbe useful before saving a dicom file or series, which should have a right-handed orientation.\n\nThe method `clone` clones the metadata object, `convert` converts the metadata in-place to the \ngiven coordinate system.\n\n#### Orientation\nThe orientation of a 3d image is string of length 3 that is derived from its affine and coordinate \nsystem (the convention). It denotes along which physical axis we move when we increase a single \nindex out of `i, j, k` in the expression `np_image[i, j, k]`.\n\nFor example, 'RAS' orientation in itk:\n- **R**ight to Left, **A**nterior to Posterior, **S**uperior to Inferior\n\n'RAS' in nib - also 'RAS+':\n- Left to **R**ight, Posterior to **A**nterior, Inferior to **S**uperior\n\nNote that the conventions are opposite. For stability reasons, we use itk convention by default \nfor `read_img`'s argument `desired_ornt`, although one can choose otherwise with the parameter \n`coord_sys`.\n\nFor further discussion see \n[NiBabel's image orientation documentation](\nhttps://nipy.org/nibabel/image_orientation.html#image-voxel-orientation).\n\n## Array and Metadata Operations\nSome operations on an image affect also its metadata, for example resizing, rotations and cropping.\n\nThe class MedImg (`medio.medimg.medimg.MedImg`) holds an image array with its metadata, and \nsupports some of these operations through the indexing syntax:\n```python\n>>> from medio.medimg.medimg import MedImg\n>>> mimg = MedImg(np_image, metadata)\n>>> new_mimg = mimg[:, 4:-4, ::3]\n>>> print(new_mimg.metadata)\n```\nEllipsis ('...') syntax is also supported. This indexing allows cropping and basic down-sampling, \nalong with correct metadata update.\n",
    'author': 'RSIP Vision',
    'author_email': 'info@rsipvision.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/RSIP-Vision/medio',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'extras_require': extras_require,
    'python_requires': '>=3.7,<4.0',
}


setup(**setup_kwargs)
