Mentions légales du service

Skip to content
Snippets Groups Projects
Commit 28ccd1d2 authored by MALANDAIN Gregoire's avatar MALANDAIN Gregoire
Browse files

Merge branch 'feature/vtImageBridgePython' of...

Merge branch 'feature/vtImageBridgePython' of gitlab.inria.fr:morpheme/vt-python into feature/vtImageBridgePython
parents 4424c78b 38002a94
No related branches found
No related tags found
No related merge requests found
dist/
__pycache__
*.egg-info
.coverage
# ITK and VTK #
###################
......
# VT-python library
This package contains python wrappers for the C library [`vt`](https://gitlab.inria.fr/morpheme/vt).
It uses `conda` to create environments and install dependencies.
If you do not have `conda` installed, look [here](https://docs.conda.io/projects/conda/en/latest/user-guide/install/index.html).
## User install
Using conda, you can easily install the library as follow:
## User install:
Using conda, you can easily install the `vt-python` library and its dependencies, in a newly created environment named `morpheme`, as follow:
```bash
conda install vt-python -n morpheme -c morpheme
```
Note: `-c morpheme` indicate the morpheme channel in [Anaconda Cloud](https://anaconda.org/).
You may want to install `ipython` too:
```bash
conda activate morpheme
conda install ipython -n morpheme
```
You can now use the `vt-python` library:
```python
import vt
img = vt.vtImage("<my_image.tif>")
```
## Developer install:
First you have to decide if you also need to install the sources for the C library `vt`.
## Developer install
### 1. A - `vt` source install:
If so, follow `vt` sources install instructions [here](https://gitlab.inria.fr/morpheme/vt).
### Dependencies:
First install the *VT* library accessible here: https://gitlab.inria.fr/morpheme/vt
Then update `morpheme` environment (created during the `vt` source install) with `vt-python` dependencies:
```bash
conda env update -n morpheme --file vt-python/pkg/env/vt-python_dev.yaml
```
Note: `vt-python/pkg/env/vt-python_dev.yaml` contains all required dependencies and channels.
### 1. B - `vt` conda package install:
You can also use the conda environment recipe for `vt-python`:
```bash
conda env create -n morpheme -f vt-python/pkg/env/vt-python_dev.yaml
```
Note: this will create an environment named `morpheme`.
- from the source, follow the instructions;
- using the conda package: `conda create -n morpheme
### Clone the source and install:
### 2. Clone `vt-python` sources:
Then clone the sources:
```bash
git clone https://gitlab.inria.fr/morpheme/vt-python.git
```
To install, in the same **activated** conda environment where *VT* is installed, simply run:
### 3. Install `vt-python` sources:
To install `vt-python` sources in the `morpheme` environment, simply run:
```bash
conda activate morpheme
cd vt-python
python setup.py develop
```
Note: Do not forget to clean the `build` directory -if any- before installing.
```bash
cd vt-python
**Notes:** Do not forget to clean the `build` directory -if any- before installing.
if [[ -d build ]]
then
rm -rf build
fi
```
## Contributing:
### Build & upload conda package
**WARNING**: this should be done from the `base` environment!
```bash
conda activate base
```
Using the given recipe in `pkg/env/vt.yaml` it is easy to build the `vt-python` conda package:
Install `conda-build`, and `anaconda-client` if you want to upload your package:
```bash
conda install conda-build anaconda-client
```
**WARNING:** For macOS, follow these [instructions](https://docs.conda.io/projects/conda-build/en/latest/resources/compiler-tools.html#macos-sdk) to install the required `macOS 10.9 SDK`.
Using the given recipe, it is easy to build the `vt-python` conda package:
```bash
conda-build pkg/recipe/ -c conda-forge -c dtk
conda build vt-python/pkg/recipe/ -c conda-forge -c morpheme
```
This requires the installation of the `conda-build` package: `conda install conda-build`
Note: `-c conda-forge` & `-c morpheme` are required for proper channels definition.
Optionally, to upload you package on [anaconda cloud](https://anaconda.org) you will need a valid account.
Follow this [procedure](https://docs.conda.io/projects/conda-build/en/latest/user-guide/tutorials/build-pkgs-skeleton.html#optional-uploading-packages-to-anaconda-org).
Then you can build and automatically upload upon completion:
Then, you can build and automatically upload to your account or organization upon completion:
```bash
conda-build pkg/recipe/ -c dtk -c conda-forge -c morpheme --user morpheme
conda build vt-python/pkg/recipe/ -c dtk -c conda-forge -c morpheme --user morpheme
```
**Note** that you may want to change the `user`.
Note: that you may want to change the `user`.
### Running tests:
If you want to **run the tests**, you will have to install ``nose``, and ``coverage`` to get report on tests coverage.
If you want to **run the tests**, you will have to install ``nose`` and ``coverage`` to get report on tests coverage.
* [nose](http://nose.readthedocs.io/en/latest/): testing, all platforms
* [coverage](http://coverage.readthedocs.org/): testing coverage, all platforms
......
......@@ -4,11 +4,11 @@ channels:
- conda-forge
- morpheme
dependencies:
- xtensor
- vt
- xtensor-python
- xtl
- xtensor=0.20.10
- xtensor-python
- pybind11
- numpy
- numpy-base
- nose
- vt
name: vt-python_dev
channels:
- defaults
- conda-forge
- morpheme
dependencies:
- xtl
- xtensor
- xtensor-python
- pybind11
- numpy
- numpy-base
- nose
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# File author(s):
# Jonathan Legrand <jonathan.legrand@ens-lyon.fr>
#
# ------------------------------------------------------------------------------
import logging
import numpy as np
from vt import vtImage as vt_vtImage
def _round_list(input_list, dec_val=6):
"""Return rounded values to given number of decimals.
Parameters
----------
input_list : list
list of values to round-up
dec_val : int
max number of decimal to keep after round-up
Returns
-------
list
list with rounded values
"""
return np.around(input_list, decimals=dec_val).tolist()
def _new_from_vt_image(vt_img):
"""Extract objects to create an image from a ``vtImage`` or a ``vt_vtImage``.
Parameters
----------
vt_img : vt_vtImage or vtImage
An image object inheriting from vt_vtImage.
Returns
-------
numpy.ndarray
The converted array corresponding to the image.
list
The voxelsize of the image.
list
The origin of the image.
dict
The dictionary of metadata associated to the image.
"""
# - Retrieve the image shape:
sh = vt_img.shape() # returns xyz ordered shape
sh.reverse() # convert to zyx ordered shape
# - Retrieve the image voxelsize:
vxs = _round_list(vt_img.spacing(), dec_val=6) # round it up to 6 decimals
vxs = vxs[::-1] # convert to zyx ordered voxelsize
# - 2D management:
if len(sh) == 3 and sh[0] == 1:
vxs = vxs[1:]
sh = sh[1:]
# - Retrieve the array:
arr = vt_img.copy_to_array()
# arr = arr.ravel().reshape(sh)
# - Not so important here...
ori = getattr(vt_img, 'origin', None)
md = getattr(vt_img, 'metadata', {})
return arr, vxs, ori, md
DEFAULT_ORIG_2D, DEFAULT_ORIG_3D = [0, 0], [0, 0, 0]
class vtImage(vt_vtImage):
"""Python wrapper for vt_vtImage.
Attributes
----------
ndim : int
Number of dimensions of the image.
"""
def __init__(self, image, voxelsize=None, **kwargs):
""" Constructor.
Parameters
----------
image : str or numpy.ndarray or vt_vtImage
If a ``str``, should match a file path to load.
If a ``numpy.ndarray``, the array of the image.
We assume they are sorted as (planes,) rows & columns ([Z,] Y, X).
voxelsize : list(float), optional
Specify the array voxelsize, only used if ``image`` is a ``numpy.ndarray``.
Should be sorted as (planes,) rows & columns ([Z,] Y, X).
"""
# Parse keyword arguments:
origin = kwargs.get('origin', None)
metadata = kwargs.get('metadata', {})
if isinstance(image, np.ndarray):
logging.debug(
"``vtImage`` constructor got a ``numpy.ndarray`` as input!")
if voxelsize is None:
super().__init__(image)
else:
super().__init__(image, voxelsize)
elif isinstance(image, vt_vtImage):
logging.debug(
"``vtImage`` constructor got a ``{}`` as input!".format(
type(image)))
arr, vxs, ori, md = _new_from_vt_image(image)
# super().__init__(arr, vxs[::-1])
self.__init__(arr, vxs[::-1], origin=ori, metadata=md)
elif isinstance(image, str):
logging.debug(
"``vtImage`` constructor got a filename ``str`` as input!")
super().__init__(image)
else:
raise TypeError(
"Could not make sense of object given in input, read the doc!")
# Specify `ndim` attribute:
sh = self.shape()
if len(sh) == 3 and 1 not in sh:
ndim = 3
else:
ndim = 2
if origin is None:
if ndim == 3:
origin = DEFAULT_ORIG_3D
else:
origin = DEFAULT_ORIG_2D
# Defines attributes:
self._metadata = metadata
self._origin = origin
self.ndim = ndim
if __name__ == '__main__':
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
from os.path import abspath, dirname, join
# - Defines the image path:
# file_path = '/home/jonathan/Projects/VT_Python/vt-python/data/p58-t0_INT_down_interp_2x.inr'
file_path = abspath(
join(dirname(__file__), "../..", "data", "p58-t0_INT_down_interp_2x.inr"))
print("Image file path is: {}".format(file_path))
# - Load it with vtImage from VT:
print("Load it with `vt_vtImage` (i.e. from VT)...")
vt_vtim = vt_vtImage(file_path)
assert isinstance(vt_vtim, vt_vtImage)
print("Successfully created `vt_vtImage` object:")
print(vt_vtim)
# - Manual creation of vt_vtImage from array and voxelsize:
arr = vt_vtim.copy_to_array()
vxs = vt_vtim.spacing()
# vt_vtim2 = vt_vtImage(arr, vxs)
# arr2 = vt_vtim2.copy_to_array()
# np.testing.assert_array_equal(arr, arr2)
# - Create a vtImage object a from array and voxelsize:
print("\n\n# - Instantiation of `vtImage` object from array and voxelsize...")
vtim = vtImage(arr, vxs)
isinstance(vtim, vtImage)
print("Successfully created `vtImage` object:")
print(vtim)
print("vtImage.ndim = {}".format(vtim.ndim))
print("Testing `spacing` method:", end=" ")
assert vtim.spacing() == vt_vtim.spacing()
print("OK!")
print("Testing `shape` method:", end=" ")
assert vtim.shape() == vt_vtim.shape()
print("OK!")
print("Testing `copy_to_array` method of `vt_vtImage` object:", end=" ")
vt_vtarr = vt_vtim.copy_to_array()
print("OK!")
print("Testing `copy_to_array` method of `vtImage` object:", end=" ")
vtarr = vtim.copy_to_array()
print("OK!")
print("Comparing arrays from `vt_vtImage` & `vtImage` objects:", end=" ")
np.testing.assert_array_equal(vt_vtarr, vtarr)
print("OK!")
# - Create a vtImage object a from `vt_vtImage`
print("\n\n# - Instantiation of `vtImage` object from `vt_vtImage`...")
vtim = vtImage(vt_vtim)
isinstance(vtim, vtImage)
print("Successfully created `vtImage` object:")
print(vtim)
print("vtImage.ndim = {}".format(vtim.ndim))
print("vtImage._origin = {}".format(vtim._origin))
print("vtImage._metadata = {}".format(vtim._metadata))
print("Testing `spacing` method:", end=" ")
assert vtim.spacing() == vt_vtim.spacing()
print("OK!")
print("Testing `shape` method:", end=" ")
assert vtim.shape() == vt_vtim.shape()
print("OK!")
print("Testing `copy_to_array` method of `vt_vtImage` object:", end=" ")
vt_vtarr = vt_vtim.copy_to_array()
print("OK!")
print("Testing `copy_to_array` method of `vtImage` object:", end=" ")
vtarr = vtim.copy_to_array()
print("OK!")
print("Comparing arrays from `vt_vtImage` & `vtImage` objects:", end=" ")
np.testing.assert_array_equal(vt_vtarr, vtarr)
print("OK!")
# !/usr/bin/env python
# -*- coding: utf-8 -*-
import unittest
import numpy as np
from os.path import abspath, dirname, join
from vt import vtImage as vt_vtImage
from vt.wrapping_vtImage import vtImage
class TestWrappingvtImage(unittest.TestCase):
@classmethod
def setUpClass(cls):
# Path to a real image file:
cls._file_path = abspath(join(dirname(__file__), "..", "data",
"p58-t1_INT_down_interp_2x.inr"))
# Use vt.vtImage to read image file:
cls._vt_vtim = vt_vtImage(cls._file_path)
def test_init_vt_vtimg_from_copy_to_array(self):
"""Test creation of vt_vtImage from array and voxelsize. """
arr = self._vt_vtim.copy_to_array()
assert isinstance(arr, np.ndarray)
vxs = self._vt_vtim.spacing()
vt_vtim2 = vt_vtImage(arr, vxs)
assert isinstance(vt_vtim2, vt_vtImage)
arr2 = vt_vtim2.copy_to_array()
assert isinstance(arr2, np.ndarray)
np.testing.assert_array_equal(arr, arr2)
def test_init_vtimg_from_copy_to_array(self):
"""Test creation of vtImage from array and voxelsize. """
arr = self._vt_vtim.copy_to_array()
assert isinstance(arr, np.ndarray)
vxs = self._vt_vtim.spacing()
vtim = vtImage(arr, vxs)
assert isinstance(vtim, vt_vtImage)
arr2 = vtim.copy_to_array()
assert isinstance(arr2, np.ndarray)
np.testing.assert_array_equal(arr, arr2)
def test_init_vtimg_from_vt_vtimg(self):
"""Test creation of vtImage from vt_vtImage. """
vtim = vtImage(self._vt_vtim)
assert isinstance(vtim, vt_vtImage)
arr2 = vtim.copy_to_array()
assert isinstance(arr2, np.ndarray)
print(np.array(np.where(self._vt_vtim.copy_to_array() != arr2)).T)
np.testing.assert_array_equal(self._vt_vtim.copy_to_array(), arr2)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment