File: index.rst

package info (click to toggle)
libvigraimpex 1.10.0%2Bgit20160211.167be93%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 48,024 kB
  • ctags: 25,337
  • sloc: cpp: 55,572; python: 8,495; ansic: 1,267; makefile: 150; sh: 38
file content (760 lines) | stat: -rw-r--r-- 37,991 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
.. vigranumpy documentation master file, created by
   sphinx-quickstart on Thu Dec 03 15:51:41 2009.
   You can adapt this file completely to your liking, but it should at least
   contain the root `toctree` directive.


Vigranumpy Reference
====================

.. contents::

.. toctree::
   :maxdepth: 2

Introduction
------------

Vigranumpy exports the functionality of the C++ image processing library `VIGRA <usr/share/doc/libvigraimpex-doc/html/index.html>`_ to Python. It can be invoked by importing the vigra module::

    import vigra

Vigranumpy 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.

Basic 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::

    # allocate new result image
    >>> smoothImage = vigra.gaussianSmoothing(inputImage, scale)

    # reuse and overwrite existing result image
    >>> smoothImage = vigra.gaussianSmoothing(inputImage, scale, out=smoothImage)

Unless otherwise noted, all functions expect and create arrays with dtype=numpy.float32.

Another 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?

To 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:

* When the Python array has **no** ``array.axistags`` property, it is mapped to the C++ NumpyArray
  **without** any change in axis ordering. Since most VIGRA functions can work on arbitrarily
  transposed arrays, you will get correct results, but execution may be slower because the
  processor cache is poorly utilized in certain axis orders.

  Moreover, this may lead to overload resolution ambiguities. For example, when the array has shape
  ``(3, 60, 40)``, vigranumpy has no way to decide if this is a 2-dimensional RGB image or
  a 3-dimensional array that happens to have only 3 slices. Thus, vigranumpy may not always
  execute the function you actually intended to call.

* When the Python array **has** the ``array.axistags`` property, it is transposed into a
  **canonical** axis ordering before vigranumpy executes a function, and the results are
  transposed back into the original ordering. Likewise, functions that change axis ordering
  (such as ``array.swapaxes(0,1)``) or reduce the number of axes (such as ``array.max(axis=1)``)
  as well as array arithmetic operations preserve axistags (see section :ref:`sec-dtype-coercion`).
  Thus, you can work in any desired axis order without loosing control. Overload ambiguities
  can no longer occur because a function cannot be called when the axistags are unsuitable.

Detailed 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.

.. _sec-vigraarray:

Axistags and the VigraArray Data Structure
------------------------------------------

While 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::

    >>> width, height, depth = 300, 200, 3

    # create a 2-dimensional RGB image
    >>> rgb = vigra.RGBImage((width, height))
    >>> rgb.shape
    (300, 200, 3)
    >>> rgb.axistags             # short output: only axis keys
    x y c
    >>> print(rgb.axistags)      # long output
    AxisInfo: 'x' (type: Space)
    AxisInfo: 'y' (type: Space)
    AxisInfo: 'c' (type: Channels) RGB

    # create a 3-dimensional scalar volume
    >>> volume = vigra.ScalarVolume((width, height, depth))
    >>> volume.shape
    (300, 200, 3)        # same shape as before
    >>> volume.axistags
    x y z                # but different semantic interpretation
    >>> print(volume.axistags)
    AxisInfo: 'x' (type: Space)
    AxisInfo: 'y' (type: Space)
    AxisInfo: 'z' (type: Space)

It 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::

    >>> rgb.axistags['x'].resolution = 1.2  # in some unit of length
    >>> rgb.axistags['y'].resolution = 1.4  # in some unit of length
    >>> rgb.axistags['c'].description = 'fluorescence microscopy, DAPI and GFP staining'
    >>> print(rgb.axistags)
    AxisInfo: 'x' (type: Space, resolution=1.2)
    AxisInfo: 'y' (type: Space, resolution=1.4)
    AxisInfo: 'c' (type: Channels) fluorescence microscopy, DAPI and GFP staining

    # interpolate the image to twice its original size
    >>> rgb2 = vigra.sampling.resize(rgb, shape=(2*width-1, 2*height-1))
    >>> print(rgb2.axistags)
    AxisInfo: 'x' (type: Space, resolution=0.6)
    AxisInfo: 'y' (type: Space, resolution=0.7)
    AxisInfo: 'c' (type: Channels) fluorescence microscopy, DAPI and GFP staining

When 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::

    # transpose the volume into reverse axis order
    >>> transposed_volume = volume.transpose()
    >>> transposed_volume.shape
    (3, 200, 300)
    >>> transposed_volume.axistags
    z y x

    # get a view to the first slice (z == 0)
    >>> first_slice = volume[..., 0]
    >>> first_slice.shape
    (300, 200)
    >>> first_slice.axistags
    x y

    # get the maximum of each slice
    >>> volume.max(axis=0).max(axis=0)
    VigraArray(shape=(3,), axistags=z, dtype=float32, data=
    [ 0.  0.  0.])

    # likewise, but specify axes by their keys
    >>> volume.max(axis='x').max(axis='y')
    VigraArray(shape=(3,), axistags=z, dtype=float32, data=
    [ 0.  0.  0.])

The 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:

.. _array-order-parameter:

    'C' order:
        Both strides and axes are arranged in descending order, as in a
        plain numpy.ndarray. For example, axistags will be 'y x c' or
        'z y x c'. array.flags['C_CONTIGUOUS'] will be true.

    'F' order:
        Both strides and axes are arranged in ascending order, i.e.
        opposite to 'C' order. For example, axistags will be 'c x y'
        or 'c x y z'. array.flags['F_CONTIGUOUS'] will be true.

    'V' order:
        VIGRA-order is an interleaved memory layout that simulates
        vector-valued pixels or voxels: Channels will be the last axis
        and have the smallest stride, whereas all other axes are arranged
        in ascending order. For example, axistags will be 'x y c' or
        'x y z c'.

    'A' order:
        Defaults to 'V' when a new array is created, and means
        'preserve order' when an existing array is copied.

The 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::

    >>> rgbv = vigra.RGBImage((width, height), order='V')
    >>> rgbv.shape
    (300, 200, 3)
    >>> rgbv.axistags
    x y c

    >>> rgbc = vigra.RGBImage((width, height), order='C')
    >>> rgbc.shape
    (200, 300, 3)
    >>> rgbc.axistags
    y x c

    >>> rgbf = vigra.RGBImage((width, height), order='F')
    >>> rgbf.shape
    (3, 300, 200)
    >>> rgbf.axistags
    c x y

Functions that reduce the array to a one-dimensional shape (``flatten()``, ``flat``, ``ravel()``, ``take()``) always transpose the array into 'C' order before flattening.

Axistags 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`.

More On the Motivation and Use of Axistags
------------------------------------------

History of the problem
^^^^^^^^^^^^^^^^^^^^^^

A Fortran array declaration::

    real f(20,10)

is compiled such that the elements of the first index are consecutive in memory. In contrast, a C array declaration::

    float c[20][10];

places 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.

Arrays as Matrices
^^^^^^^^^^^^^^^^^^

When 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).

In short: When the array is a matrix, the syntax is the same, but the memory layouts differ.

Arrays as Images
^^^^^^^^^^^^^^^^

When 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]``.

In short: When the array is an image, the memory layout is the same, but the syntax differs.

Thus, 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).

Multi-Dimensional Arrays
^^^^^^^^^^^^^^^^^^^^^^^^

When 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"::

    RGB RGB RGB ...
    RGB RGB RGB ...
    :
    :

where the color values of each pixel are consecutive in memory, or in "banded format"::

    R R R ...
    R R R ...
    :
    G G G ...
    G G G ...
    :
    B B B ...
    B B B ...
    :

where 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]``.

VIGRA and numpy
^^^^^^^^^^^^^^^

From 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).

In contrast, numpy adopted C conventions, i.e. its default behavior is CM and CI.

In 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.

However, 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).

But 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.

The 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').

Vigranumpy Axistags
^^^^^^^^^^^^^^^^^^^

This 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::

    width  = image.width    # this works for any axis order!
    height = image.height

Now 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::

    # adjust the axis order
    numpy_image = image.transposeToNumpyOrder()

    # execute the algorithm
    for y in xrange(height):
        for x in xrange(width):
            numpy_image[y, x] = ...   # note the index order

When we want to execute a VIGRA algorithm which expects the [x, y] ordering, we do::

    # adjust the axis order
    vigra_image = image.transposeToVigraOrder()

    # execute the algorithm
    for y in xrange(height):
        for x in xrange(width):
            vigra_image[x, y] = ...   # note the index order

Notice 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.

Vigranumpy Conventions
^^^^^^^^^^^^^^^^^^^^^^

To 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:

1. 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::

    vigra_precondition( !matrix.axistags(), "matrix must not have axistags");

   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.

2. 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`)::

    numpy_array   = array.transposeToNumpyOrder()    # gives 'yx', 'zyx' etc.
    vigra_array   = array.transposeToVigraOrder()    # gives 'xy', 'xyz' etc.
    ilastik_array = array.view5D()                   # gives 'txyzc' (inserts singleton axes if necessary)
    user_defined  = array.withAxes('y', 'x', 't')    # specify order explicitly (inserts singleton axes if necessary)

   Algorithms with special order requirements can then check for the correct order in an assertion.

3. 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::

    tagged_array = vigra.taggedView(array, 'xyzt')

4. 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.

5. 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.

6. 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``.

7. 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.

8. 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)``.

Item 4. has two important consequences one should be aware of:

* 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.

* 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).

Axistag Reference
-----------------

.. autoclass:: vigra.AxisType

----------------

.. autoclass:: vigra.AxisInfo
    :members: key, typeFlags, resolution, description, isSpatial, isTemporal, isChannel, isFrequency, isAngular, isType, compatible

----------------

.. autoclass:: vigra.AxisTags
    :members: index, channelIndex, innerNonchannelIndex, axisTypeCount, setChannelDescription, toJSON, fromJSON

VigraArray Reference
--------------------

.. autoclass:: vigra.VigraArray
    :show-inheritance:
    :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

    .. attribute:: VigraArray.axistags

      The :class:`~vigra.AxisTags` object of this array.

    .. attribute:: VigraArray.defaultOrder

      Get the default axis ordering, currently 'V' (:ref:`VIGRA order <array-order-parameter>`).

-------------

.. autofunction:: vigra.newaxis(axisinfo=vigra.AxisInfo())
.. autofunction:: vigra.taggedView
.. autofunction:: vigra.dropChannelAxis

-------------

.. _subsec-array-factories:

.. autofunction:: vigra.Image
.. autofunction:: vigra.ScalarImage
.. autofunction:: vigra.Vector2Image
.. autofunction:: vigra.Vector3Image
.. autofunction:: vigra.Vector4Image
.. autofunction:: vigra.RGBImage

-------------

.. autofunction:: vigra.Volume
.. autofunction:: vigra.ScalarVolume
.. autofunction:: vigra.Vector2Volume
.. autofunction:: vigra.Vector3Volume
.. autofunction:: vigra.Vector4Volume
.. autofunction:: vigra.Vector6Volume
.. autofunction:: vigra.RGBVolume


Chunked Arrays and Data Bigger than RAM
---------------------------------------

Chunked arrays allow to allocate big data lazily, i.e. one chunk (rectangular block)
at a time. Chunks which are currently not needed can be compressed or written
to disk in order to free memory. This effectively allows VIGRA to work on data bigger
than RAM.

Classes
^^^^^^^

.. autoclass:: vigra.vigranumpycore.ChunkedArrayBase
   :special-members:
   :members:

-------------

.. autoclass:: vigra.vigranumpycore.ChunkedArrayHDF5Base
   :show-inheritance:
   :members:

-------------

.. autoclass:: vigra.Compression
   :members:
.. autoclass:: vigra.HDF5Mode
   :members:

Factory Functions
^^^^^^^^^^^^^^^^^

.. autofunction:: vigra.ChunkedArrayHDF5
.. autofunction:: vigra.ChunkedArrayLazy
.. autofunction:: vigra.ChunkedArrayCompressed
.. autofunction:: vigra.ChunkedArrayTmpFile
.. autofunction:: vigra.ChunkedArrayFull


Import and Export Functions
---------------------------

The module vigra.impex defines read and write functions for image and volume data. Note
that the contents of this module are automatically imported into the vigra module, so
you may call 'vigra.readImage(...)' instead of 'vigra.impex.readImage(...)' etc.

.. automodule:: vigra.impex
   :members:


.. _sec-dtype-coercion:

Mathematical Functions and Type Coercion
----------------------------------------

vigranumpy supports all arithmetic and algebraic functions defined in
`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.

.. automodule:: vigra.ufunc


Color and Intensity Manipulation
--------------------------------

The module vigra.colors provides functions to adjust image brightness and contrast,
and to transform between different color spaces.
See `Color Conversions <usr/share/doc/libvigraimpex-doc/html/group__ColorConversions.html>`_ in the C++ documentation
for more information.

.. automodule:: vigra.colors
   :members:


Filters
-------

The module vigra.filters provides operators that consider a window around each pixel, compute
one or several numbers from the values in the window, and store the results in the
corresponding pixel of the output image. This includes convolution, non-linear diffusion,
morphological operators, feature detectors (such as the structure tensor) etc.

.. automodule:: vigra.filters
   :members:


Sampling: Image Resizing and Image Pyramids
-------------------------------------------

The module vigra.sampling contains methods to change the number and/or location of
the image sampling points, such as resizing, rotation, and interpolation.

.. automodule:: vigra.sampling
   :members:

---------------------------------------------

Spline image views implement an interpolated view for an image which can be accessed
at real-valued coordinates (in contrast to the plain image, which can only be
accessed at integer coordinates). Module vigra.sampling defines::

    SplineImageView0
    SplineImageView1
    SplineImageView2
    SplineImageView3
    SplineImageView4
    SplineImageView5

The number denotes the spline interpolation order of the respective classes.
Below, we describe SplineImageView3 in detail, but the other classes work
analogously. See SplineImageView_ in the C++ documentation for more detailed information.

.. autoclass:: vigra.sampling.SplineImageView3
   :members:

-------------

.. autoclass:: vigra.sampling.ImagePyramid
   :show-inheritance:
   :members:


Fourier Transforms
------------------

The module vigra.fourier contains functions for Fourier transforms, Cosine/Sine
transforms, and Fourier-domain filters.

.. automodule:: vigra.fourier
   :members:


Image Analysis
--------------

The module vigra.analysis contains segmentation algorithms (e.g. watershed), edge and
corner detection, localization of maxima and minima etc.

.. automodule:: vigra.analysis
   :members:


Geometry
--------

The module vigra.geometry contains geometric primitives (such as polygons) and related algorithms.

.. automodule:: vigra.geometry
   :members:


Optimization
------------

The module vigra.optimization provides functions for constrained and unconstrained linear regression.

.. automodule:: vigra.optimization
   :members:


Machine Learning
----------------

The module vigra.learning will eventually provide a wide range of machine learning
tools. Right now, it only contains an implementation of the random forest classifier
and probabilistic latent semantic analysis (pLSA) as an example for unsupervised learning.

.. automodule:: vigra.learning
   :members:

.. autoclass:: vigra.learning.RandomForest
   :members:

For more information, refer to RandomForest_ in the C++ documentation.

.. autoclass:: vigra.learning.RandomForestOld
   :members:


Noise Estimation and Normalization
----------------------------------

The module vigra.noise provides noise estimation and normalization according to a
method proposed by Foerstner.

.. automodule:: vigra.noise
   :members:


Histogram and Channel Representation
------------------------------------

The module vigra.histogram provides histograms and channel representation

.. automodule:: vigra.histogram
   :members:


.. _sec-graph-algorithms:

Graphs and Algorithms on Graphs
-------------------------------

The module vigra.graphs provides graphs and graph algorithms

.. automodule:: vigra.graphs
   :members:

.. autoclass:: vigra.graphs.GridGraphUndirected2d
   :members:

.. autoclass:: vigra.graphs.GridGraphUndirected3d
   :members:

.. autoclass:: vigra.graphs.AdjacencyListGraph
   :members:

.. autoclass:: vigra.graphs.RegionAdjacencyGraph
   :members:

.. autoclass:: vigra.graphs.GridRegionAdjacencyGraph
   :members:

.. autoclass:: vigra.graphs.ShortestPathPathDijkstra
   :members:


Utilities
----------------------------------

The module vigra.utilities provides  utilities and tools
like priority queues with changeable priorities

.. automodule:: vigra.utilities
   :members:


.. _sec-own-modules:

Writing Your Own C++ Modules
----------------------------

When 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:

1. 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::

        // define PY_ARRAY_UNIQUE_SYMBOL (required by the numpy C-API)
        #define PY_ARRAY_UNIQUE_SYMBOL my_module_PyArray_API

        // include the vigranumpy C++ API
        #include <Python.h>
        #include <boost/python.hpp>
        #include <vigra/numpy_array.hxx>
        #include <vigra/numpy_array_converters.hxx>

        ... // your includes

        ... // implementation of your wrapper functions and classes

        using namespace boost::python;

        // the argument of the init macro must be the module name
        BOOST_PYTHON_MODULE_INIT(my_module)
        {
            // initialize numpy and vigranumpy
            vigra::import_vigranumpy();

            // export a function
            def("my_function", &my_function,
                (arg("arg1"), arg("arg2"), ...),
                "Documentation");

            // export a class and its member functions
            class_<MyClass>("MyClass",
                "Documentation")
                .def("foo", &MyClass::foo,
                     (arg("arg1"), arg("arg2"), ...),
                     "Documentation")
            ;

            ... // more module functionality (refer to boost_python documentation)
        }

2. When your module uses additional C++ source files, they should start with the following defines::

        // this must define the same symbol as the main module file (numpy requirement)
        #define PY_ARRAY_UNIQUE_SYMBOL my_module_PyArray_API
        #define NO_IMPORT_ARRAY

3. 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')::

            // We add a 'using' declaration for brevity of our examples.
            // In actual code, you should probably prefer explicit namespace qualification.
        using namespace vigra;

            // Accept any array type and return an arbitrary array type.
            // Returning NumpyAnyArray is always safe, because at that point
            // C++ no longer cares about the particular type of the array.
        NumpyAnyArray foo(NumpyAnyArray array);

            // Accept a 3-dimensional float32 array and transpose it
            // into ascending axis order ('F' order).
        void foo(NumpyArray<3, float> array);

            // Accept a 2-dimensional float32 array with an arbitrary number of channels and
            // transpose the axes into VIGRA ('V') order (channels are last, other axes ascending).
            // Note that the NumpyArray dimension is 3 to account for the channel dimension.
            // If the original numpy array has no channel axis, vigranumpy will automatically
            // insert a singleton axis.
        void foo(NumpyArray<3, Multiband<float> > array);

            // Accept a 2-dimensional float32 array that has only a single channel
            // (that is, 'array.channels == 1' must hold on the Python side).
            // Non-channel axes are transposed into ascending order.
            // Note that the NumpyArray dimension is now 2.
        void foo(NumpyArray<2, Singleband<float> > array);

            // Accept a float32 array that has 2 non-channel dimensions and
            // exactly 3 channels (i.e. 'array.channels == 3' on the Python side).
            // Non-channel axes are transposed into ascending order.
            // Note that the NumpyArray dimension is again 2, but the pixel type is
            // now a vector.
            // The conversion will only succeed if the channel axis is unstrided on
            // the Python side (that is, the following expression is True:
            //      array.strides[array.channelIndex] == array.dtype.itemsize).
        void foo(NumpyArray<2, TinyVector<float, 3> > array);
        void foo(NumpyArray<2, RGBValue<float> > array);

   Or course, these functions can also be templated.

   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)::

        NumpyAnyArray
        foo(NumpyArray<3, Multiband<float32> > input,
            NumpyArray<3, Multiband<float32> > output = boost::python::object())
        {
            // Reshape only if the output array was not explicitly passed in.
            // Otherwise, use the output array as is.
            output.reshapeIfEmpty(input.taggedShape(),
                      "error message when shape is unsuitable.");

            ... // your algorithm
        }

   It is also possible to modify the tagged shape before it is applied to the output array::

        input.taggedShape()
             .resize(Shape2(new_width, new_height))
             .setChannelCount(new_channel_count)
             .setChannelDescription("a description")

   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()``::

        NumpyAnyArray
        foo(NumpyArray<3, Multiband<float32> > input,
            NumpyArray<3, Multiband<float32> > output = boost::python::object())
        {
            output.reshapeIfEmpty(input.taggedShape(), "Message.");

                // Allow parallelization from here on. The destructor of
                // _pythread will automatically regain the global interpreter lock
                // just before this function returns to Python.
            PyAllowThreads _pythread;

            ... // your algorithm
        }

4. 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::

        // in the module's init function
        def("my_function", vigra::registerConverters(&my_function),
           (arg("arg1"), ...),
           "Documentation");

If you need more information, it is always a good idea to look at the source code of the existing vigranumpy modules.


Indices and tables
==================

* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`