vigra - VIGRA Python Bindings

[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

VIGRA Python Bindings |

See also the full vigranumpy reference!

When you configure VIGRA with the option `-DWITH_VIGRANUMPY=1` while running cmake, a Python module `vigra` will be compiled and installed. It exposes most of VIGRA's functionality for easy scripting and prototyping in Python. Most importantly, VIGRA's Python bindings are fully integrated with the popular 'numpy' package so that you can call vigra functions directly with numpy `ndarrays`. No explicit or implicit conversion of data formats is required.

The syntax of the Python version is usually very similar to the C++ syntax, with one important difference: You do not have to pass pre-allocated result arrays to the functions. That is, while the call to `gaussianSmoothing()` in C++ is written like this

MultiArray<2, float> inputImage(Shape2(width, height)),
resultImage(inputImage.shape()); // pre-allocate result with correct shape
... // fill inputImage
// smooth image with Gaussian filter with sigma=1.5
// (pre-allocated resultImage must be passed to the function)
gaussianSmoothing(inputImage, resultImage, 1.5);

the corresponding Python call is

>>> import numpy, vigra
>>> inputImage = numpy.zeros((width, height), dtype=numpy.float32)
... # fill inputImage
>>> resultImage = vigra.filters.gaussianSmoothing(inputImage, 1.5);

The result image is automatically allocated and returned by the function. Nonetheless, it is still possible to pass a result array of appropriate shape explicitly by means of the `out` parameter:

>>> resultImage = numpy.zeros(inputImage.shape, dtype=numpy.float32)
>>> vigra.filters.gaussianSmoothing(inputImage, 1.5, out=resultImage)

This is, for example, useful when the same result image should be reused in several calls of the same function to avoid the repeated creation of new result arrays. Another possible use is the application of a function to only a rectangular region-of-interest: When the full result array is already allocated, you can pass a view of the approriate subarray to the `out` parameter in order to fill just the desired ROI.

When a C++ function provides options, they are exposed on the Python side as keyword arguments:

>>> labeling, max_label = vigra.analysis.watersheds(inputImage, seeds=seedImage, method='UnionFind')

In general, the correspondence between a Python function and its C++ counterpart is straightforward, and the Python documentation frequently refers to the C++ documentation for details. However, there is a crucial difference: the default axis interpretation is different in VIGRA's `MultiArray` (which interpretes axes as x, y, z, so called 'Fortran' order) and in numpy's `ndarray` (which interpretes them as z, y, x, so called 'C'-order). To help you deal with this difficulty, vigranumpy provides a subclass VigraArray of `ndarray` and the concept of axistags. Please take the time to read this material in order to avoid surprises.

The full vigranumpy reference is available via HTML or can be obtained directly at the Python prompt by the `help()` command:

>>> help(vigra.filters.gaussianSmoothing)

Another important difference between C++ and Python is that vigranumpy exposes most functions only for a restricted set of pixel types. This restriction is necessary because support for all possible type combinations would result in a combinatorial explosion and unreasonably large Python modules. In general, all functions are implemented for `float` pixel types (called `numpy.float32` on the Python side), and some provide `uint8` and/or `uint32` versions in addition. If you call a function with an unsupported pixel type, an error message listing the supported types will be printed:

>>> a = vigra.ScalarImage((20,20), dtype=numpy.float64)
>>> vigra.gaussianSmoothing(a, 1) # doesn't support numpy.float64
ArgumentError: Python argument types in
vigra.filters.gaussianSmoothing(numpy.ndarray, int)
did not match C++ signature:
gaussianSmoothing(class vigra::NumpyArray<3,struct vigra::Multiband<float>,struct vigra::StridedArrayTag> array, class boost::python::api::object sigma, class vigra::NumpyArray<3,struct vigra::Multiband<float>,struct vigra::StridedArrayTag> out=None, class boost::python::api::object sigma_d=0.0, class boost::python::api::object step_size=1.0, double window_size=0.0, class boost::python::api::object roi=None)
gaussianSmoothing(class vigra::NumpyArray<4,struct vigra::Multiband<float>,struct vigra::StridedArrayTag> array, class boost::python::api::object sigma, class vigra::NumpyArray<4,struct vigra::Multiband<float>,struct vigra::StridedArrayTag> out=None, class boost::python::api::object sigma_d=0.0, class boost::python::api::object step_size=1.0, double window_size=0.0, class boost::python::api::object roi=None)

The error message is automatically generated by boost::python and therefore rather technical. It says that `gaussianSmoothing()` supports 3- and 4-dimensional arrays where the rightmost dimension is interpreted as a channel axis, and the pixel type must be `float` (these properties are indicated by the type specifications `NumpyArray<3,struct vigra::Multiband<float>` and `NumpyArray<4,struct vigra::Multiband<float>` respectively). Thus, the input array must be a `float32` image or volume with either no explicit channel axis (in which case a singleton channel axis will be inserted automatically) or with arbitrary many channels (e.g. RGB).

Axistags allow vigranumpy to distinguish if a given 3-dimensional array is to be interpreted as a 2D image with multiple channels, or as a 3D volume with only a single channel. If no axistags are attached to the array, it is unspecified which version of an algorithm will be called. Axistags are automatically specified when arrays are created with one of the factory functions in the `vigra` module, for example:

>>> a = vigra.ScalarImage((30, 20))
>>> print("%s \n %r" % (a.shape, a.axistags))
(30L, 20L)
x y
>>> a = vigra.RGBImage((30, 20))
>>> print("%s \n %r" % (a.shape, a.axistags))
(30L, 20L, 3L)
x y c
>>> a = vigra.ScalarVolume((30, 20, 10))
>>> print("%s \n %r" % (a.shape, a.axistags))
(30L, 20L, 10L)
x y z
>>> a = vigra.RGBVolume((30, 20, 10))
>>> print("%s \n %r" % (a.shape, a.axistags))
(30L, 20L, 10L, 3L)
x y z c

Axistags are encoded 'x', 'y', 'z' for the three spatial axes, 'c' for a channel axis, and 't' for a time axis. If the channel axis is missing, vigranumpy will assume that the array has only a single channel. That is, arrays with shape (30, 20, 1) and axistags 'x y c' are equivalent to arrays with shape (30, 20) and axistags 'x y'. Functions that change the order of the axes (such as `array.transpose()`) or reduce the number of axes (e.g. `array[:, 1, :]`) also modify the axistags accordingly, so that you can always ask for the axis meaning by simply calling `array.axistags`.

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany | html generated using doxygen and Python vigra 1.11.0 (Fri May 19 2017)