1.. vigranumpy documentation master file, created by 2 sphinx-quickstart on Thu Dec 03 15:51:41 2009. 3 You can adapt this file completely to your liking, but it should at least 4 contain the root `toctree` directive. 5 6 7Vigranumpy Reference 8==================== 9 10.. contents:: 11 12.. toctree:: 13 :maxdepth: 2 14 15Introduction 16------------ 17 18Vigranumpy exports the functionality of the C++ image processing library `VIGRA <../vigra/index.html>`_ to Python. It can be invoked by importing the vigra module:: 19 20 import vigra 21 22Vigranumpy is based on the popular `numpy <http://numpy.scipy.org/>`_ module and uses its ndarray data structure to represent image and volume data. It introduces the C++ wrapper class NumpyArray_ to allow transparent execution of VIGRA C++ functions on numpy arrays. Thus, vigranumpy is fully interoperable with existing numpy functionality, including various tools for image display such as matplotlib. Since vigranumpy uses `boost_python <http://www.boost.org/doc/libs>`_, it is able to support function overloading (which plain Python does not provide), so that calling syntax is largely uniform, regardless of the type and dimension of the input arguments. 23 24Basic calling syntax is similar to C++, with one important difference: Arguments for output images are optional. If no output image is provided, vigranumpy will allocate it as appropriate. In either case, the output image will be returned by the function, for example:: 25 26 # allocate new result image 27 >>> smoothImage = vigra.gaussianSmoothing(inputImage, scale) 28 29 # reuse and overwrite existing result image 30 >>> smoothImage = vigra.gaussianSmoothing(inputImage, scale, out=smoothImage) 31 32Unless otherwise noted, all functions expect and create arrays with dtype=numpy.float32. 33 34Another important concern is the interpretation and ordering of the array axes. Numpy does not provide any means to attach semantics to axes, but relies purely on the convention that the most important axis is last, as in ``array[y, x]`` or ``array[z, y, x]`` ("C-order"). However, there is no way to enforce this convention in a program, since arrays can be transposed outside of the user's control (e.g. when saving data to a file). Moreover, many imaging libraries (e.g. `Image Magick <http://www.imagemagick.org/>`_, `OpenCV <http://opencv.willowgarage.com/>`_, `Qt <http://qt-project.org/>`_ and the C++ version of VIGRA) use the opposite convention where the x-axis comes first, as in ``array[x, y]`` or ``array[x, y, z]``. This makes it very difficult to convert solutions developed in Python into a fast C++ version, because one has to reverse all indices without making mistakes. Matters become even more complicated when multi-channel (e.g. color) images are considered -- should the color index now be first or last? 35 36To solve these ambiguities in a clean way, vigranumpy introduces the concept of **axistags** which is realized in class :class:`vigra.AxisTags`. Every :class:`~vigra.VigraArray` (which is a subclass of numpy.ndarray) gets a new property ``array.axistags`` that describes axis semantics, and all vigranumpy functions account for and preserve axistag information. Unfortunately, this functionality cannot easily be retrofitted to numpy.ndarray itself. Therefore, we employ the following conversion rules between Python and C++ arrays: 37 38* When the Python array has **no** ``array.axistags`` property, it is mapped to the C++ NumpyArray 39 **without** any change in axis ordering. Since most VIGRA functions can work on arbitrarily 40 transposed arrays, you will get correct results, but execution may be slower because the 41 processor cache is poorly utilized in certain axis orders. 42 43 Moreover, this may lead to overload resolution ambiguities. For example, when the array has shape 44 ``(3, 60, 40)``, vigranumpy has no way to decide if this is a 2-dimensional RGB image or 45 a 3-dimensional array that happens to have only 3 slices. Thus, vigranumpy may not always 46 execute the function you actually intended to call. 47 48* When the Python array **has** the ``array.axistags`` property, it is transposed into a 49 **canonical** axis ordering before vigranumpy executes a function, and the results are 50 transposed back into the original ordering. Likewise, functions that change axis ordering 51 (such as ``array.swapaxes(0,1)``) or reduce the number of axes (such as ``array.max(axis=1)``) 52 as well as array arithmetic operations preserve axistags (see section :ref:`sec-dtype-coercion`). 53 Thus, you can work in any desired axis order without loosing control. Overload ambiguities 54 can no longer occur because a function cannot be called when the axistags are unsuitable. 55 56Detailed information about the use of axistags is given in section :ref:`sec-vigraarray` below. Section :ref:`sec-own-modules` describes how you can take advantage of the axistags mechanism in your own C++ code. 57 58.. _sec-vigraarray: 59 60Axistags and the VigraArray Data Structure 61------------------------------------------ 62 63While vigranumpy can directly work on numpy.ndarrays, this would not give us the advantages of axistags as described above. Therefore, vigranumpy introduces its own array class :class:`~vigra.VigraArray` which is a subclass of numpy.ndarray, but re-implements many of its methods so that axistags are respected. Arrays with a conforming ``axistags`` property are most easily constructed by one of the predefined :ref:`array factories <subsec-array-factories>`. A **view with axistags** can be created from an existing numpy.ndarray by means of the function :py:func:`~vigra.taggedView` (in contrast, factory functions create copies of the given arrays, not views). We illustrate the ideas by some examples:: 64 65 >>> width, height, depth = 300, 200, 3 66 67 # create a 2-dimensional RGB image 68 >>> rgb = vigra.RGBImage((width, height)) 69 >>> rgb.shape 70 (300, 200, 3) 71 >>> rgb.axistags # short output: only axis keys 72 x y c 73 >>> print(rgb.axistags) # long output 74 AxisInfo: 'x' (type: Space) 75 AxisInfo: 'y' (type: Space) 76 AxisInfo: 'c' (type: Channels) RGB 77 78 # create a 3-dimensional scalar volume 79 >>> volume = vigra.ScalarVolume((width, height, depth)) 80 >>> volume.shape 81 (300, 200, 3) # same shape as before 82 >>> volume.axistags 83 x y z # but different semantic interpretation 84 >>> print(volume.axistags) 85 AxisInfo: 'x' (type: Space) 86 AxisInfo: 'y' (type: Space) 87 AxisInfo: 'z' (type: Space) 88 89It is also possible to attach additional information to the axistags, in particular the resolution of the axis, and a text comment. The resolution will be correctly adjusted when the image is resized:: 90 91 >>> rgb.axistags['x'].resolution = 1.2 # in some unit of length 92 >>> rgb.axistags['y'].resolution = 1.4 # in some unit of length 93 >>> rgb.axistags['c'].description = 'fluorescence microscopy, DAPI and GFP staining' 94 >>> print(rgb.axistags) 95 AxisInfo: 'x' (type: Space, resolution=1.2) 96 AxisInfo: 'y' (type: Space, resolution=1.4) 97 AxisInfo: 'c' (type: Channels) fluorescence microscopy, DAPI and GFP staining 98 99 # interpolate the image to twice its original size 100 >>> rgb2 = vigra.sampling.resize(rgb, shape=(2*width-1, 2*height-1)) 101 >>> print(rgb2.axistags) 102 AxisInfo: 'x' (type: Space, resolution=0.6) 103 AxisInfo: 'y' (type: Space, resolution=0.7) 104 AxisInfo: 'c' (type: Channels) fluorescence microscopy, DAPI and GFP staining 105 106When the array is transposed, the axistags are transposed accordingly. When axes are dropped from the array, the corresponding entries are dropped from the axistags property:: 107 108 # transpose the volume into reverse axis order 109 >>> transposed_volume = volume.transpose() 110 >>> transposed_volume.shape 111 (3, 200, 300) 112 >>> transposed_volume.axistags 113 z y x 114 115 # get a view to the first slice (z == 0) 116 >>> first_slice = volume[..., 0] 117 >>> first_slice.shape 118 (300, 200) 119 >>> first_slice.axistags 120 x y 121 122 # get the maximum of each slice 123 >>> volume.max(axis=0).max(axis=0) 124 VigraArray(shape=(3,), axistags=z, dtype=float32, data= 125 [ 0. 0. 0.]) 126 127 # likewise, but specify axes by their keys 128 >>> volume.max(axis='x').max(axis='y') 129 VigraArray(shape=(3,), axistags=z, dtype=float32, data= 130 [ 0. 0. 0.]) 131 132The initial ordering of the axes is controlled by the argument ``order`` that can optionally be passed to the VigraArray constuctor or the factory functions. If ``order`` is not explicitly provided, it is determined by the static property :attr:`VigraArray.defaultOrder` (which yields 'V' order). The following orders are currently supported: 133 134.. _array-order-parameter: 135 136 'C' order: 137 Both strides and axes are arranged in descending order, as in a 138 plain numpy.ndarray. For example, axistags will be 'y x c' or 139 'z y x c'. array.flags['C_CONTIGUOUS'] will be true. 140 141 'F' order: 142 Both strides and axes are arranged in ascending order, i.e. 143 opposite to 'C' order. For example, axistags will be 'c x y' 144 or 'c x y z'. array.flags['F_CONTIGUOUS'] will be true. 145 146 'V' order: 147 VIGRA-order is an interleaved memory layout that simulates 148 vector-valued pixels or voxels: Channels will be the last axis 149 and have the smallest stride, whereas all other axes are arranged 150 in ascending order. For example, axistags will be 'x y c' or 151 'x y z c'. 152 153 'A' order: 154 Defaults to 'V' when a new array is created, and means 155 'preserve order' when an existing array is copied. 156 157The meaning of 'ascending' or 'descending' order is determined by two rules: the primary order is according to axis type (see :class:`vigra.AxisType`), where ``Channels < Space < Angle < Time < Frequency < Unknown``. The secondary order (between axes of the same type) is lexicographic, such that 'x' < 'y' < 'z'. Usage examples:: 158 159 >>> rgbv = vigra.RGBImage((width, height), order='V') 160 >>> rgbv.shape 161 (300, 200, 3) 162 >>> rgbv.axistags 163 x y c 164 165 >>> rgbc = vigra.RGBImage((width, height), order='C') 166 >>> rgbc.shape 167 (200, 300, 3) 168 >>> rgbc.axistags 169 y x c 170 171 >>> rgbf = vigra.RGBImage((width, height), order='F') 172 >>> rgbf.shape 173 (3, 300, 200) 174 >>> rgbf.axistags 175 c x y 176 177Functions that reduce the array to a one-dimensional shape (``flatten()``, ``flat``, ``ravel()``, ``take()``) always transpose the array into 'C' order before flattening. 178 179Axistags are stored in a list-like class :class:`vigra.AxisTags`, whose individual entries are of type :class:`vigra.AxisInfo`. The simplest way to attach axistags to a plain numpy.ndarray (by creating a view of type VigraArray) is via the convenience function :func:`vigra.taggedView`. 180 181More On the Motivation and Use of Axistags 182------------------------------------------ 183 184History of the problem 185^^^^^^^^^^^^^^^^^^^^^^ 186 187A Fortran array declaration:: 188 189 real f(20,10) 190 191is compiled such that the elements of the first index are consecutive in memory. In contrast, a C array declaration:: 192 193 float c[20][10]; 194 195places the elements of the last index consecutive in memory. The two possibilities are commonly referred to as "Fortran order" and "C order", but we will see that these terms are actually ambiguous because their meaning depends on what the array is used for. 196 197Arrays as Matrices 198^^^^^^^^^^^^^^^^^^ 199 200When the array represents a matrix, users require the syntax to conform to the mathematical syntax conventions (in order to avoid bugs when typing formulas). In mathematics, m\ :sub:`ij` means that the first index i refers to rows, and the second index j refers to columns. Thus, Fortran's ``f(i, j)`` and C's ``c[i][j]`` have exactly the same meaning, but the memory layouts of the two matrices differ: Since in Fortran the first index changes quickest, this is referred to as the "column major" format (the elements of a column are consecutive in memory). In contrast, C uses the "row major" format (the elements of a row are consecutive in memory). 201 202In short: When the array is a matrix, the syntax is the same, but the memory layouts differ. 203 204Arrays as Images 205^^^^^^^^^^^^^^^^ 206 207When the array represents an image, users require the memory layout to be the same as in the image files which store the data (in order to ensure fast I/O). All image formats (JPEG, TIFF, PNG, ...) follow the convention of analog television to scan an image left to right, then top to bottom. Consequently, the horizontal pixels are consecutive in memory, and therefore Fortran (where the first axis changes fastest) must use the syntax ``f(x, y)``, whereas C (where the last axis changes fastest) must use ``c[y][x]``. 208 209In short: When the array is an image, the memory layout is the same, but the syntax differs. 210 211Thus, we have four basic conventions: FM and CM for matrices, FI and CI for images. The meaning of the terms "Fortran order" and "C order" depends on whether we are talking about matrices (where they refer to FM and CM, i.e. a difference in memory layout) or images (where they refer to FI and CI, i.e. a difference in index order). 212 213Multi-Dimensional Arrays 214^^^^^^^^^^^^^^^^^^^^^^^^ 215 216When we add more dimensions, the confusion increases, because there are no universally accepted memory and indexing conventions. For example, an RGB image can be stored in "interleaved format":: 217 218 RGB RGB RGB ... 219 RGB RGB RGB ... 220 : 221 : 222 223where the color values of each pixel are consecutive in memory, or in "banded format":: 224 225 R R R ... 226 R R R ... 227 : 228 G G G ... 229 G G G ... 230 : 231 B B B ... 232 B B B ... 233 : 234 235where we have a separate scalar image for each color. In Fortran, interleaved and banded images must be indexed as ``f(color, x, y)`` and ``f(x, y, color)`` respectively, whereas in C we must use ``c[y][x][color]`` or ``c[color][y][x]``. 236 237VIGRA and numpy 238^^^^^^^^^^^^^^^ 239 240From the beginning, VIGRA adopted Fortran conventions, i.e. its default behavior is according to FM and FI (this is possible because VIGRA uses array classes, where the mapping from indices to memory is encapsulated in the appropriate way). 241 242In contrast, numpy adopted C conventions, i.e. its default behavior is CM and CI. 243 244In addition, both packages provide array views which keep the memory layout intact, but change the index order. Thus, VIGRA also supports the CI convention, and numpy also supports FI. Note that changing the index order is only allowed for images. Matrices always use the fixed index order dictated by mathematics where transpose(m) is a well-defined mathematical operation (which just happens to revert the index order). Therefore, the existence of array views does not imply that VIGRA supports CM or numpy supports FM. 245 246However, numpy's array constructor provides an argument 'order' which can take the values 'C' (default) and 'F' to construct arrays with C or Fortran memory order. By this mechanism, numpy also supports the FM convention (and thus all four basic possibilities). 247 248But here is the catch: When you get a numpy array view, you have no way to tell which convention it adheres to. It simply doesn't contain this information. 249 250The usual solution to this problem is to enforce a fixed axis order in the entire application, but this workaround breaks down when the application must simultaneously handle arrays with different meaning (e.g. sequences 'xyt' vs. volumes 'xyz' vs. multi-spectral images 'xyc') or when the application uses modules with conflicting requirements (e.g. numpy's 'yx' vs. PyQt's 'xy'). 251 252Vigranumpy Axistags 253^^^^^^^^^^^^^^^^^^^ 254 255This is precisely where axistags enter: They attach information to array views that allows the user to figure out which convention applies to a given view. Thus, the primary purpose of axistags is entirely passive - they just keep track of how users manipulate the axis order when creating new array views. The main use case of axistags is therefore to re-adjust the axis order whenever an algorithm has specific order requirements. Using axistags, one can easily ensure that arrays conform to the desired order at the beginning of every algorithm. Consider the following example: Let 'image' be a scalar 2D image with axistags. Then we can ask for the image's width and height independently of the current axis order:: 256 257 width = image.width # this works for any axis order! 258 height = image.height 259 260Now suppose we want to execute a numpy algorithm which expects the [y, x] ordering. We simply transpose the array before calling the algorithm like this:: 261 262 # adjust the axis order 263 numpy_image = image.transposeToNumpyOrder() 264 265 # execute the algorithm 266 for y in xrange(height): 267 for x in xrange(width): 268 numpy_image[y, x] = ... # note the index order 269 270When we want to execute a VIGRA algorithm which expects the [x, y] ordering, we do:: 271 272 # adjust the axis order 273 vigra_image = image.transposeToVigraOrder() 274 275 # execute the algorithm 276 for y in xrange(height): 277 for x in xrange(width): 278 vigra_image[x, y] = ... # note the index order 279 280Notice that the order of the loops (the inner loop runs over x) is the same in both cases: To maximize cache locality and therefore speed, the inner loop should operate on consecutive memory cells. Since image memory order derives from file memory order (where the x-axis is consecutive), and array views can never change the memory order, this loop ordering is always preferable, regardless of the index order. 281 282Vigranumpy Conventions 283^^^^^^^^^^^^^^^^^^^^^^ 284 285To handle axis meaning in a well-defined way, vigranumpy adopts the following conventions, which are designed such that The Right Thing (TM) should happen automatically, at least most of the time: 286 2871. When the array represents a matrix, no axistags are allowed because the index order has a fixed semantic meaning and must not be messed around with. In vigranumpy, this requirement is enforced by an assertion:: 288 289 vigra_precondition( !matrix.axistags(), "matrix must not have axistags"); 290 291 in the C++ gluecode functions. This applies, for example, to the feature matrices passed to a random forest and to unsupervised learning algorithms. If desired, we can introduce additional axistags for features and samples in the future because this is a common use case. 292 2932. When arrays represent image data with up to five dimensions, axistags should be used. To sort indices according to the requirements of the next algorithm to be executed, the appropriate convenience function should be called (many more convenience functions are documented in :py:class:`vigra.VigraArray`):: 294 295 numpy_array = array.transposeToNumpyOrder() # gives 'yx', 'zyx' etc. 296 vigra_array = array.transposeToVigraOrder() # gives 'xy', 'xyz' etc. 297 ilastik_array = array.view5D() # gives 'txyzc' (inserts singleton axes if necessary) 298 user_defined = array.withAxes('y', 'x', 't') # specify order explicitly (inserts singleton axes if necessary) 299 300 Algorithms with special order requirements can then check for the correct order in an assertion. 301 3023. The function ``vigra.taggedView()`` allows to attach axistags to an array very conveniently. For example, when you know from the context that the axes of a given array are to be interpreted as 'xyzt' in that order, you can make this knowledge explicit by calling:: 303 304 tagged_array = vigra.taggedView(array, 'xyzt') 305 3064. When you call a vigranumpy function that executes a C++ VIGRA function, ``image.transposeToVigraOrder()`` will be invoked automatically on the input arrays, and the original axis order will be restored in the output arrays. 307 3085. When you call a vigranumpy function that is forwarded to a numpy function (in particular, a ufunc like ``+``, ``-``, ``sqrt`` etc.), ``image.transposeToNumpyOrder()`` will be invoked automatically on the input arrays, and the original axis order will be restored in the output arrays. 309 3106. When vigranumpy writes arrays to a file, it will always order the axes such that the memory order conforms to the established file conventions (e.g. values along the x-axis are consecutive). In particular, when you use ``vigra.impex.writeHDF5()`` to create HDF5 datasets, ``array.transposeToNumpyOrder()`` will be called before writing the data (this is a consequence of item 5, because ``writeHDF5()`` eventually forwards the actual work to h5py). In addition, the axistags (in numpy order) will be stored in a dataset attribute ``axistags``. 311 3127. When vigranumpy reads data from a file, it preserves the file's memory order and attaches the appropriate axistags. In case of images, the axis order follows from the usual file conventions. If you call ``vigra.impex.readHDF5()`` to read HDF5, the axistags will be read from the attribute ``axistags`` (if present). Upon return, the read functions automatically call ``array.transposeToVigraOrder()``, but this only changes the index order, not the memory layout. This latter convention was adopted to ensure that the default index order is the same in the Python and C++ versions of VIGRA. 313 3148. When you display an image via ``image.imshow()`` or ``image.show()``, the axes are re-ordered automatically such that the image is displayed upright (i.e. x goes to the right, y goes down). If you want to override this (i.e. want to enforce transposed display), you can remove the axistags by calling ``image.view(numpy.ndarray)``. 315 316Item 4. has two important consequences one should be aware of: 317 318* When a function needs parameters that depend on the axis order (such as the new shape in ``vigra.sampling.resize()`` or axis-dependent sigmas in ``vigra.filters.gaussianSmoothing()``), these parameters must be re-ordered on the C++ side in the same way as the axes. This is achieved by a call to ``NumpyArray::permuteLikewise()`` in the C++ gluecode functions. 319 320* When a vigranumpy function computes a gradient image, the gradient vector elements will always be stored in the order (dx, dy, dz), regardless of the array's original axis ordering. The same applies to any function producing vector-valued elements whose interpretation depends on the axis meaning (e.g. the Hessian matrix and the structure tensor). For example, the output of the Hessian is ordered as (dxx, dxy, dxz, dyy, dyz, dzz). 321 322Axistag Reference 323----------------- 324 325.. autoclass:: vigra.AxisType 326 327---------------- 328 329.. autoclass:: vigra.AxisInfo 330 :members: key, typeFlags, resolution, description, isSpatial, isTemporal, isChannel, isFrequency, isAngular, isType, compatible 331 332---------------- 333 334.. autoclass:: vigra.AxisTags 335 :members: index, channelIndex, innerNonchannelIndex, axisTypeCount, setChannelDescription, toJSON, fromJSON 336 337VigraArray Reference 338-------------------- 339 340.. autoclass:: vigra.VigraArray 341 :show-inheritance: 342 :members: defaultAxistags, channelIndex, innerNonchannelIndex, channels, spatialDimensions, width, height, depth, duration, dropChannelAxis, insertChannelAxis, withAxes, view5D, asRGB, __getitem__, subarray, bindAxis, channelIter, sliceIter, spaceIter, timeIter, copyValues, swapaxes, transpose, T, transposeToOrder, transposeToDefaultOrder, transposeToNormalOrder, transposeToNumpyOrder, transposeToVigraOrder, permutationToOrder, permutationToNormalOrder, permutationFromNormalOrder, permutationToNumpyOrder, permutationFromNumpyOrder, permutationToVigraOrder, permutationFromVigraOrder, writeHDF5, writeImage, writeSlices, receiveSocket, sendSocket, qimage, show 343 344 .. attribute:: VigraArray.axistags 345 346 The :class:`~vigra.AxisTags` object of this array. 347 348 .. attribute:: VigraArray.defaultOrder 349 350 Get the default axis ordering, currently 'V' (:ref:`VIGRA order <array-order-parameter>`). 351 352------------- 353 354.. autofunction:: vigra.newaxis(axisinfo=vigra.AxisInfo()) 355.. autofunction:: vigra.taggedView 356.. autofunction:: vigra.dropChannelAxis 357 358------------- 359 360.. _subsec-array-factories: 361 362.. autofunction:: vigra.Image 363.. autofunction:: vigra.ScalarImage 364.. autofunction:: vigra.Vector2Image 365.. autofunction:: vigra.Vector3Image 366.. autofunction:: vigra.Vector4Image 367.. autofunction:: vigra.RGBImage 368 369------------- 370 371.. autofunction:: vigra.Volume 372.. autofunction:: vigra.ScalarVolume 373.. autofunction:: vigra.Vector2Volume 374.. autofunction:: vigra.Vector3Volume 375.. autofunction:: vigra.Vector4Volume 376.. autofunction:: vigra.Vector6Volume 377.. autofunction:: vigra.RGBVolume 378 379 380Chunked Arrays and Data Bigger than RAM 381--------------------------------------- 382 383Chunked arrays allow to allocate big data lazily, i.e. one chunk (rectangular block) 384at a time. Chunks which are currently not needed can be compressed or written 385to disk in order to free memory. This effectively allows VIGRA to work on data bigger 386than RAM. 387 388Classes 389^^^^^^^ 390 391.. autoclass:: vigra.vigranumpycore.ChunkedArrayBase 392 :special-members: 393 :members: 394 395------------- 396 397.. autoclass:: vigra.vigranumpycore.ChunkedArrayHDF5Base 398 :show-inheritance: 399 :members: 400 401------------- 402 403.. autoclass:: vigra.Compression 404 :members: 405.. autoclass:: vigra.HDF5Mode 406 :members: 407 408Factory Functions 409^^^^^^^^^^^^^^^^^ 410 411.. autofunction:: vigra.ChunkedArrayHDF5 412.. autofunction:: vigra.ChunkedArrayLazy 413.. autofunction:: vigra.ChunkedArrayCompressed 414.. autofunction:: vigra.ChunkedArrayTmpFile 415.. autofunction:: vigra.ChunkedArrayFull 416 417 418Import and Export Functions 419--------------------------- 420 421The module vigra.impex defines read and write functions for image and volume data. Note 422that the contents of this module are automatically imported into the vigra module, so 423you may call 'vigra.readImage(...)' instead of 'vigra.impex.readImage(...)' etc. 424 425.. automodule:: vigra.impex 426 :members: 427 428 429.. _sec-dtype-coercion: 430 431Mathematical Functions and Type Coercion 432---------------------------------------- 433 434vigranumpy supports all arithmetic and algebraic functions defined in 435`numpy.ufunc <http://docs.scipy.org/doc/numpy/reference/ufuncs.html#available-ufuncs>`_, but re-implements them in module `vigra.ufunc` to take full advantage of axistags. 436 437.. automodule:: vigra.ufunc 438 439 440Color and Intensity Manipulation 441-------------------------------- 442 443The module vigra.colors provides functions to adjust image brightness and contrast, 444and to transform between different color spaces. 445See `Color Conversions <../vigra/group__ColorConversions.html>`_ in the C++ documentation 446for more information. 447 448.. automodule:: vigra.colors 449 :members: 450 451 452Filters 453------- 454 455The module vigra.filters provides operators that consider a window around each pixel, compute 456one or several numbers from the values in the window, and store the results in the 457corresponding pixel of the output image. This includes convolution, non-linear diffusion, 458morphological operators, feature detectors (such as the structure tensor) etc. 459 460.. automodule:: vigra.filters 461 :members: 462 463 464Sampling: Image Resizing and Image Pyramids 465------------------------------------------- 466 467The module vigra.sampling contains methods to change the number and/or location of 468the image sampling points, such as resizing, rotation, and interpolation. 469 470.. automodule:: vigra.sampling 471 :members: 472 473--------------------------------------------- 474 475Spline image views implement an interpolated view for an image which can be accessed 476at real-valued coordinates (in contrast to the plain image, which can only be 477accessed at integer coordinates). Module vigra.sampling defines:: 478 479 SplineImageView0 480 SplineImageView1 481 SplineImageView2 482 SplineImageView3 483 SplineImageView4 484 SplineImageView5 485 486The number denotes the spline interpolation order of the respective classes. 487Below, we describe SplineImageView3 in detail, but the other classes work 488analogously. See SplineImageView_ in the C++ documentation for more detailed information. 489 490.. autoclass:: vigra.sampling.SplineImageView3 491 :members: 492 493------------- 494 495.. autoclass:: vigra.sampling.ImagePyramid 496 :show-inheritance: 497 :members: 498 499 500Fourier Transforms 501------------------ 502 503The module vigra.fourier contains functions for Fourier transforms, Cosine/Sine 504transforms, and Fourier-domain filters. 505 506.. automodule:: vigra.fourier 507 :members: 508 509 510Image Analysis 511-------------- 512 513The module vigra.analysis contains segmentation algorithms (e.g. watershed), edge and 514corner detection, localization of maxima and minima etc. 515 516.. automodule:: vigra.analysis 517 :members: 518 519 520Geometry 521-------- 522 523The module vigra.geometry contains geometric primitives (such as polygons) and related algorithms. 524 525.. automodule:: vigra.geometry 526 :members: 527 528 529Optimization 530------------ 531 532The module vigra.optimization provides functions for constrained and unconstrained linear regression. 533 534.. automodule:: vigra.optimization 535 :members: 536 537 538Machine Learning 539---------------- 540 541The module vigra.learning will eventually provide a wide range of machine learning 542tools. Right now, it only contains an implementation of the random forest classifier 543and probabilistic latent semantic analysis (pLSA) as an example for unsupervised learning. 544 545.. automodule:: vigra.learning 546 :members: 547 548.. autoclass:: vigra.learning.RandomForest 549 :members: 550 551For more information, refer to RandomForest_ in the C++ documentation. 552 553.. autoclass:: vigra.learning.RandomForestOld 554 :members: 555 556 557Noise Estimation and Normalization 558---------------------------------- 559 560The module vigra.noise provides noise estimation and normalization according to a 561method proposed by Foerstner. 562 563.. automodule:: vigra.noise 564 :members: 565 566 567Histogram and Channel Representation 568------------------------------------ 569 570The module vigra.histogram provides histograms and channel representation 571 572.. automodule:: vigra.histogram 573 :members: 574 575 576.. _sec-graph-algorithms: 577 578Graphs and Algorithms on Graphs 579------------------------------- 580 581The module vigra.graphs provides graphs and graph algorithms 582 583.. automodule:: vigra.graphs 584 :members: 585 586.. autoclass:: vigra.graphs.GridGraphUndirected2d 587 :members: 588 589.. autoclass:: vigra.graphs.GridGraphUndirected3d 590 :members: 591 592.. autoclass:: vigra.graphs.AdjacencyListGraph 593 :members: 594 595.. autoclass:: vigra.graphs.RegionAdjacencyGraph 596 :members: 597 598.. autoclass:: vigra.graphs.GridRegionAdjacencyGraph 599 :members: 600 601.. autoclass:: vigra.graphs.ShortestPathPathDijkstra 602 :members: 603 604 605Utilities 606---------------------------------- 607 608The module vigra.utilities provides utilities and tools 609like priority queues with changeable priorities 610 611.. automodule:: vigra.utilities 612 :members: 613 614 615.. _sec-own-modules: 616 617Writing Your Own C++ Modules 618---------------------------- 619 620When you want to write your own vigranumpy extension modules, first make sure that you compile and link with the same versions of numpy and boost_python that your current vigranumpy installation uses. Otherwise, communication between new and existing modules will not work (and even crash). Then follow these steps: 621 6221. Create the main module source file. This file contains the module's 'init' function. Let's assume that the module will be called 'my_module', and the file is 'my_module.cxx'. A stub for 'my_module.cxx' typically looks like this:: 623 624 // define PY_ARRAY_UNIQUE_SYMBOL (required by the numpy C-API) 625 #define PY_ARRAY_UNIQUE_SYMBOL my_module_PyArray_API 626 627 // include the vigranumpy C++ API 628 #include <Python.h> 629 #include <boost/python.hpp> 630 #include <vigra/numpy_array.hxx> 631 #include <vigra/numpy_array_converters.hxx> 632 633 ... // your includes 634 635 ... // implementation of your wrapper functions and classes 636 637 using namespace boost::python; 638 639 // the argument of the init macro must be the module name 640 BOOST_PYTHON_MODULE_INIT(my_module) 641 { 642 // initialize numpy and vigranumpy 643 vigra::import_vigranumpy(); 644 645 // export a function 646 def("my_function", &my_function, 647 (arg("arg1"), arg("arg2"), ...), 648 "Documentation"); 649 650 // export a class and its member functions 651 class_<MyClass>("MyClass", 652 "Documentation") 653 .def("foo", &MyClass::foo, 654 (arg("arg1"), arg("arg2"), ...), 655 "Documentation") 656 ; 657 658 ... // more module functionality (refer to boost_python documentation) 659 } 660 6612. When your module uses additional C++ source files, they should start with the following defines:: 662 663 // this must define the same symbol as the main module file (numpy requirement) 664 #define PY_ARRAY_UNIQUE_SYMBOL my_module_PyArray_API 665 #define NO_IMPORT_ARRAY 666 6673. Implement your wrapper functions. Numpy ndarrays are passed to C++ via the wrapper classes NumpyArray_ and NumpyAnyArray_. You can influence the conversion from Python to C++ by using different instantiations of NumpyArray, as long as the Python array supports the axistags attribute (refer to :ref:`axis order definitions <array-order-parameter>` for the meaning of the term 'ascending order'):: 668 669 // We add a 'using' declaration for brevity of our examples. 670 // In actual code, you should probably prefer explicit namespace qualification. 671 using namespace vigra; 672 673 // Accept any array type and return an arbitrary array type. 674 // Returning NumpyAnyArray is always safe, because at that point 675 // C++ no longer cares about the particular type of the array. 676 NumpyAnyArray foo(NumpyAnyArray array); 677 678 // Accept a 3-dimensional float32 array and transpose it 679 // into ascending axis order ('F' order). 680 void foo(NumpyArray<3, float> array); 681 682 // Accept a 2-dimensional float32 array with an arbitrary number of channels and 683 // transpose the axes into VIGRA ('V') order (channels are last, other axes ascending). 684 // Note that the NumpyArray dimension is 3 to account for the channel dimension. 685 // If the original numpy array has no channel axis, vigranumpy will automatically 686 // insert a singleton axis. 687 void foo(NumpyArray<3, Multiband<float> > array); 688 689 // Accept a 2-dimensional float32 array that has only a single channel 690 // (that is, 'array.channels == 1' must hold on the Python side). 691 // Non-channel axes are transposed into ascending order. 692 // Note that the NumpyArray dimension is now 2. 693 void foo(NumpyArray<2, Singleband<float> > array); 694 695 // Accept a float32 array that has 2 non-channel dimensions and 696 // exactly 3 channels (i.e. 'array.channels == 3' on the Python side). 697 // Non-channel axes are transposed into ascending order. 698 // Note that the NumpyArray dimension is again 2, but the pixel type is 699 // now a vector. 700 // The conversion will only succeed if the channel axis is unstrided on 701 // the Python side (that is, the following expression is True: 702 // array.strides[array.channelIndex] == array.dtype.itemsize). 703 void foo(NumpyArray<2, TinyVector<float, 3> > array); 704 void foo(NumpyArray<2, RGBValue<float> > array); 705 706 Or course, these functions can also be templated. 707 708 When your functions return newly allocated arrays, it is usually desirable to transfer the input's axistags to the output (otherwise, vigranumpy will use :meth:`~vigra.VigraArray.defaultAxistags` as a fallback). There is a standard vigranumpy idiom for this task which assumes that the wrapped function has an optional parameter 'output' for a possibly pre-allocated output array. The axistags are then transferred by reshaping the output array with a ``taggedShape()`` (which is a combination of a shape and axistags):: 709 710 NumpyAnyArray 711 foo(NumpyArray<3, Multiband<float32> > input, 712 NumpyArray<3, Multiband<float32> > output = boost::python::object()) 713 { 714 // Reshape only if the output array was not explicitly passed in. 715 // Otherwise, use the output array as is. 716 output.reshapeIfEmpty(input.taggedShape(), 717 "error message when shape is unsuitable."); 718 719 ... // your algorithm 720 } 721 722 It is also possible to modify the tagged shape before it is applied to the output array:: 723 724 input.taggedShape() 725 .resize(Shape2(new_width, new_height)) 726 .setChannelCount(new_channel_count) 727 .setChannelDescription("a description") 728 729 The C++ code can be multi-threaded when you unlock Python's global interpreter lock. After unlocking, your wrapper code must not call any Python functions, so the unlock statement should go after ``output.reshapeIfEmpty()``:: 730 731 NumpyAnyArray 732 foo(NumpyArray<3, Multiband<float32> > input, 733 NumpyArray<3, Multiband<float32> > output = boost::python::object()) 734 { 735 output.reshapeIfEmpty(input.taggedShape(), "Message."); 736 737 // Allow parallelization from here on. The destructor of 738 // _pythread will automatically regain the global interpreter lock 739 // just before this function returns to Python. 740 PyAllowThreads _pythread; 741 742 ... // your algorithm 743 } 744 7454. Export your wrapped functions. ``boost::python::def`` is called in its usual way, with one simple extension: Since vigranumpy does not know which NumpyArray variants you are going to use, appropriate converter functions between Python and C++ must be registered on demand. You do this by enclosing your function pointer into a call to the 'registerConverters()' function:: 746 747 // in the module's init function 748 def("my_function", vigra::registerConverters(&my_function), 749 (arg("arg1"), ...), 750 "Documentation"); 751 752If you need more information, it is always a good idea to look at the source code of the existing vigranumpy modules. 753 754 755Indices and tables 756================== 757 758* :ref:`genindex` 759* :ref:`modindex` 760* :ref:`search` 761