[Scipy-svn] r4634 - in trunk/scipy/ndimage/src: . register segment

scipy-svn@scip... scipy-svn@scip...
Sat Aug 9 14:29:49 CDT 2008


Author: cdavid
Date: 2008-08-09 14:29:36 -0500 (Sat, 09 Aug 2008)
New Revision: 4634

Modified:
   trunk/scipy/ndimage/src/nd_image.c
   trunk/scipy/ndimage/src/nd_image.h
   trunk/scipy/ndimage/src/ni_filters.c
   trunk/scipy/ndimage/src/ni_filters.h
   trunk/scipy/ndimage/src/ni_fourier.c
   trunk/scipy/ndimage/src/ni_fourier.h
   trunk/scipy/ndimage/src/ni_interpolation.c
   trunk/scipy/ndimage/src/ni_interpolation.h
   trunk/scipy/ndimage/src/ni_measure.c
   trunk/scipy/ndimage/src/ni_measure.h
   trunk/scipy/ndimage/src/ni_morphology.c
   trunk/scipy/ndimage/src/ni_morphology.h
   trunk/scipy/ndimage/src/ni_support.c
   trunk/scipy/ndimage/src/ni_support.h
   trunk/scipy/ndimage/src/register/Register_EXT.c
   trunk/scipy/ndimage/src/register/Register_IMPL.c
   trunk/scipy/ndimage/src/segment/Segmenter_EXT.c
   trunk/scipy/ndimage/src/segment/Segmenter_IMPL.c
   trunk/scipy/ndimage/src/segment/ndImage_Segmenter_structs.h
Log:
Use unix endline in ndimage (windows EOL break some unix compilers.).

Modified: trunk/scipy/ndimage/src/nd_image.c
===================================================================
--- trunk/scipy/ndimage/src/nd_image.c	2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/nd_image.c	2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,1320 +1,1320 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define ND_IMPORT_ARRAY
-#include "nd_image.h"
-#undef ND_IMPORT_ARRAY
-#include "ni_support.h"
-#include "ni_filters.h"
-#include "ni_fourier.h"
-#include "ni_morphology.h"
-#include "ni_interpolation.h"
-#include "ni_measure.h"
-
-typedef struct {
-    PyObject *function;
-    PyObject *extra_arguments;
-    PyObject *extra_keywords;
-} NI_PythonCallbackData;
-
-/* Convert an input array of any type, not necessarily contiguous */
-static int
-NI_ObjectToInputArray(PyObject *object, PyArrayObject **array)
-{
-    *array = NA_InputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
-    return *array ? 1 : 0;
-}
-
-/* Convert an input array of any type, not necessarily contiguous */
-static int
-NI_ObjectToOptionalInputArray(PyObject *object, PyArrayObject **array)
-{
-    if (object == Py_None) {
-        *array = NULL;
-        return 1;
-    } else {
-        *array = NA_InputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
-        return *array ? 1 : 0;
-    }
-}
-
-/* Convert an output array of any type, not necessarily contiguous */
-static int
-NI_ObjectToOutputArray(PyObject *object, PyArrayObject **array)
-{
-    *array = NA_OutputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
-    return *array ? 1 : 0;
-}
-
-/* Convert an output array of any type, not necessarily contiguous */
-static int
-NI_ObjectToOptionalOutputArray(PyObject *object, PyArrayObject **array)
-{
-    if (object == Py_None) {
-        *array = NULL;
-        return 1;
-    } else {
-        *array = NA_OutputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
-        return *array ? 1 : 0;
-    }
-}
-
-/* Convert an input/output array of any type, not necessarily contiguous */
-static int
-NI_ObjectToIoArray(PyObject *object, PyArrayObject **array)
-{
-    *array = NA_IoArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
-    return *array ? 1 : 0;
-}
-
-/* Convert an Long sequence */
-static maybelong
-NI_ObjectToLongSequenceAndLength(PyObject *object, maybelong **sequence)
-{
-    long *pa, ii;
-    PyArrayObject *array = NA_InputArray(object, PyArray_LONG, NPY_CARRAY);
-    maybelong length = PyArray_SIZE(array);
-
-    *sequence = (maybelong*)malloc(length * sizeof(maybelong));
-    if (!*sequence) {
-        PyErr_NoMemory();
-        Py_XDECREF(array);
-        return -1;
-    }
-    pa = (long*)PyArray_DATA(array);
-    for(ii = 0; ii < length; ii++)
-        (*sequence)[ii] = pa[ii];
-    Py_XDECREF(array);
-    return length;
-}
-
-static int
-NI_ObjectToLongSequence(PyObject *object, maybelong **sequence)
-{
-    return NI_ObjectToLongSequenceAndLength(object, sequence) >= 0;
-}
-
-/*********************************************************************/
-/* wrapper functions: */
-/*********************************************************************/
-
-static PyObject *Py_Correlate1D(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL, *weights = NULL;
-    int axis, mode;
-    long origin;
-    double cval;
-
-    if (!PyArg_ParseTuple(args, "O&O&iO&idl", NI_ObjectToInputArray, &input,
-                                    NI_ObjectToInputArray, &weights, &axis,
-                                    NI_ObjectToOutputArray, &output, &mode, &cval, &origin))
-        goto exit;
-    if (!NI_Correlate1D(input, weights, axis, output,
-                                            (NI_ExtendMode)mode, cval, origin))
-        goto exit;
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(weights);
-    Py_XDECREF(output);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_Correlate(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL, *weights = NULL;
-    maybelong *origin = NULL;
-    int mode;
-    double cval;
-
-    if (!PyArg_ParseTuple(args, "O&O&O&idO&", NI_ObjectToInputArray, &input,
-                    NI_ObjectToInputArray, &weights, NI_ObjectToOutputArray, &output,
-                    &mode, &cval, NI_ObjectToLongSequence, &origin))
-        goto exit;
-    if (!NI_Correlate(input, weights, output, (NI_ExtendMode)mode, cval,
-                                        origin))
-        goto exit;
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(weights);
-    Py_XDECREF(output);
-    if (origin)
-        free(origin);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_UniformFilter1D(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL;
-    int axis, mode;
-    long filter_size, origin;
-    double cval;
-
-    if (!PyArg_ParseTuple(args, "O&liO&idl", NI_ObjectToInputArray, &input,
-                                        &filter_size, &axis, NI_ObjectToOutputArray, &output,
-                                        &mode, &cval, &origin))
-        goto exit;
-    if (!NI_UniformFilter1D(input, filter_size, axis, output,
-                                                                             (NI_ExtendMode)mode, cval, origin))
-        goto exit;
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(output);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_MinOrMaxFilter1D(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL;
-    int axis, mode, minimum;
-    long filter_size, origin;
-    double cval;
-
-    if (!PyArg_ParseTuple(args, "O&liO&idli", NI_ObjectToInputArray, &input,
-                                        &filter_size, &axis, NI_ObjectToOutputArray, &output,
-                                        &mode, &cval, &origin, &minimum))
-        goto exit;
-    if (!NI_MinOrMaxFilter1D(input, filter_size, axis, output,
-                                                            (NI_ExtendMode)mode, cval, origin, minimum))
-        goto exit;
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(output);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_MinOrMaxFilter(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
-    PyArrayObject *structure = NULL;
-    maybelong *origin = NULL;
-    int mode, minimum;
-    double cval;
-
-    if (!PyArg_ParseTuple(args, "O&O&O&O&idO&i", NI_ObjectToInputArray,
-                                        &input, NI_ObjectToInputArray, &footprint,
-                                        NI_ObjectToOptionalInputArray, &structure,
-                                        NI_ObjectToOutputArray, &output, &mode, &cval,
-                                        NI_ObjectToLongSequence, &origin, &minimum))
-        goto exit;
-    if (!NI_MinOrMaxFilter(input, footprint, structure, output,
-                                                (NI_ExtendMode)mode, cval, origin, minimum))
-        goto exit;
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(footprint);
-    Py_XDECREF(structure);
-    Py_XDECREF(output);
-    if (origin)
-        free(origin);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_RankFilter(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
-    maybelong *origin = NULL;
-    int mode, rank;
-    double cval;
-
-    if (!PyArg_ParseTuple(args, "O&iO&O&idO&", NI_ObjectToInputArray,
-                                        &input, &rank, NI_ObjectToInputArray, &footprint,
-                                        NI_ObjectToOutputArray, &output, &mode, &cval,
-                                        NI_ObjectToLongSequence, &origin))
-        goto exit;
-    if (!NI_RankFilter(input, rank, footprint, output, (NI_ExtendMode)mode,
-                                         cval, origin))
-        goto exit;
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(footprint);
-    Py_XDECREF(output);
-    if (origin)
-        free(origin);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static int Py_Filter1DFunc(double *iline, maybelong ilen,
-                                                     double *oline, maybelong olen, void *data)
-{
-    PyArrayObject *py_ibuffer = NULL, *py_obuffer = NULL;
-    PyObject *rv = NULL, *args = NULL, *tmp = NULL;
-    maybelong ii;
-    double *po = NULL;
-    NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
-
-    py_ibuffer = NA_NewArray(iline, PyArray_DOUBLE, 1, &ilen);
-    py_obuffer = NA_NewArray(NULL, PyArray_DOUBLE, 1, &olen);
-    if (!py_ibuffer || !py_obuffer)
-        goto exit;
-    tmp = Py_BuildValue("(OO)", py_ibuffer, py_obuffer);
-    if (!tmp)
-        goto exit;
-    args = PySequence_Concat(tmp, cbdata->extra_arguments);
-    if (!args)
-        goto exit;
-    rv = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
-    if (!rv)
-        goto exit;
-    po = (double*)PyArray_DATA(py_obuffer);
-    for(ii = 0; ii < olen; ii++)
-        oline[ii] = po[ii];
-exit:
-    Py_XDECREF(py_ibuffer);
-    Py_XDECREF(py_obuffer);
-    Py_XDECREF(rv);
-    Py_XDECREF(args);
-    Py_XDECREF(tmp);
-    return PyErr_Occurred() ? 0 : 1;
-}
-
-static PyObject *Py_GenericFilter1D(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL;
-    PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
-    void *func = Py_Filter1DFunc, *data = NULL;
-    NI_PythonCallbackData cbdata;
-    int axis, mode;
-    long origin, filter_size;
-    double cval;
-
-    if (!PyArg_ParseTuple(args, "O&OliO&idlOO", NI_ObjectToInputArray,
-                &input, &fnc, &filter_size, &axis, NI_ObjectToOutputArray,
-                &output, &mode, &cval, &origin, &extra_arguments, &extra_keywords))
-        goto exit;
-    if (!PyTuple_Check(extra_arguments)) {
-        PyErr_SetString(PyExc_RuntimeError,
-                                        "extra_arguments must be a tuple");
-        goto exit;
-    }
-    if (!PyDict_Check(extra_keywords)) {
-        PyErr_SetString(PyExc_RuntimeError,
-                                        "extra_keywords must be a dictionary");
-        goto exit;
-    }
-    if (PyCObject_Check(fnc)) {
-        func = PyCObject_AsVoidPtr(fnc);
-        data = PyCObject_GetDesc(fnc);
-    } else if (PyCallable_Check(fnc)) {
-        cbdata.function = fnc;
-        cbdata.extra_arguments = extra_arguments;
-        cbdata.extra_keywords = extra_keywords;
-        data = (void*)&cbdata;
-    } else {
-        PyErr_SetString(PyExc_RuntimeError,
-                                        "function parameter is not callable");
-        goto exit;
-    }
-    if (!NI_GenericFilter1D(input, func, data, filter_size, axis, output,
-                                                                                (NI_ExtendMode)mode, cval, origin))
-        goto exit;
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(output);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static int Py_FilterFunc(double *buffer, maybelong filter_size,
-                                                 double *output, void *data)
-{
-    PyArrayObject *py_buffer = NULL;
-    PyObject *rv = NULL, *args = NULL, *tmp = NULL;
-    NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
-
-    py_buffer = NA_NewArray(buffer, PyArray_DOUBLE, 1, &filter_size);
-    if (!py_buffer)
-        goto exit;
-    tmp = Py_BuildValue("(O)", py_buffer);
-    if (!tmp)
-        goto exit;
-    args = PySequence_Concat(tmp, cbdata->extra_arguments);
-    if (!args)
-        goto exit;
-    rv = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
-    if (!rv)
-        goto exit;
-    *output = PyFloat_AsDouble(rv);
-exit:
-    Py_XDECREF(py_buffer);
-    Py_XDECREF(rv);
-    Py_XDECREF(args);
-    Py_XDECREF(tmp);
-    return PyErr_Occurred() ? 0 : 1;
-}
-
-static PyObject *Py_GenericFilter(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
-    PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
-    void *func = Py_FilterFunc, *data = NULL;
-    NI_PythonCallbackData cbdata;
-    int mode;
-    maybelong *origin = NULL;
-    double cval;
-
-    if (!PyArg_ParseTuple(args, "O&OO&O&idO&OO", NI_ObjectToInputArray,
-                                                &input, &fnc, NI_ObjectToInputArray, &footprint,
-                                                NI_ObjectToOutputArray, &output, &mode, &cval,
-                                                NI_ObjectToLongSequence, &origin,
-                                                &extra_arguments, &extra_keywords))
-        goto exit;
-    if (!PyTuple_Check(extra_arguments)) {
-        PyErr_SetString(PyExc_RuntimeError,
-                                        "extra_arguments must be a tuple");
-        goto exit;
-    }
-    if (!PyDict_Check(extra_keywords)) {
-        PyErr_SetString(PyExc_RuntimeError,
-                                        "extra_keywords must be a dictionary");
-        goto exit;
-    }
-    if (PyCObject_Check(fnc)) {
-        func = PyCObject_AsVoidPtr(fnc);
-        data = PyCObject_GetDesc(fnc);
-    } else if (PyCallable_Check(fnc)) {
-        cbdata.function = fnc;
-        cbdata.extra_arguments = extra_arguments;
-        cbdata.extra_keywords = extra_keywords;
-        data = (void*)&cbdata;
-    } else {
-        PyErr_SetString(PyExc_RuntimeError,
-                                        "function parameter is not callable");
-        goto exit;
-    }
-    if (!NI_GenericFilter(input, func, data, footprint, output,
-                                                (NI_ExtendMode)mode, cval, origin))
-        goto exit;
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(output);
-    Py_XDECREF(footprint);
-    if (origin)
-        free(origin);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_FourierFilter(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL, *parameters = NULL;
-    int axis, filter_type;
-    long n;
-
-    if (!PyArg_ParseTuple(args, "O&O&liO&i", NI_ObjectToInputArray, &input,
-                                        NI_ObjectToInputArray, &parameters, &n, &axis,
-                                        NI_ObjectToOutputArray, &output, &filter_type))
-        goto exit;
-
-    if (!NI_FourierFilter(input, parameters, n, axis, output, filter_type))
-        goto exit;
-
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(parameters);
-    Py_XDECREF(output);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_FourierShift(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL, *shifts = NULL;
-    int axis;
-    long n;
-
-    if (!PyArg_ParseTuple(args, "O&O&liO&", NI_ObjectToInputArray, &input,
-                                        NI_ObjectToInputArray, &shifts, &n, &axis,
-                                        NI_ObjectToOutputArray, &output))
-        goto exit;
-
-    if (!NI_FourierShift(input, shifts, n, axis, output))
-        goto exit;
-
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(shifts);
-    Py_XDECREF(output);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_SplineFilter1D(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL;
-    int axis, order;
-
-    if (!PyArg_ParseTuple(args, "O&iiO&", NI_ObjectToInputArray, &input,
-                    &order, &axis, NI_ObjectToOutputArray, &output))
-        goto exit;
-
-    if (!NI_SplineFilter1D(input, order, axis, output))
-        goto exit;
-
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(output);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static int Py_Map(maybelong *ocoor, double* icoor, int orank, int irank,
-                                    void *data)
-{
-    PyObject *coors = NULL, *rets = NULL, *args = NULL, *tmp = NULL;
-    maybelong ii;
-    NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
-
-    coors = PyTuple_New(orank);
-    if (!coors)
-        goto exit;
-    for(ii = 0; ii < orank; ii++) {
-        PyTuple_SetItem(coors, ii, PyInt_FromLong(ocoor[ii]));
-        if (PyErr_Occurred())
-            goto exit;
-    }
-    tmp = Py_BuildValue("(O)", coors);
-    if (!tmp)
-        goto exit;
-    args = PySequence_Concat(tmp, cbdata->extra_arguments);
-    if (!args)
-        goto exit;
-    rets = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
-    if (!rets)
-        goto exit;
-    for(ii = 0; ii < irank; ii++) {
-        icoor[ii] = PyFloat_AsDouble(PyTuple_GetItem(rets, ii));
-        if (PyErr_Occurred())
-            goto exit;
-    }
-exit:
-    Py_XDECREF(coors);
-    Py_XDECREF(tmp);
-    Py_XDECREF(rets);
-    Py_XDECREF(args);
-    return PyErr_Occurred() ? 0 : 1;
-}
-
-
-static PyObject *Py_GeometricTransform(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL;
-    PyArrayObject *coordinates = NULL, *matrix = NULL, *shift = NULL;
-    PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
-    int mode, order;
-    double cval;
-    void *func = NULL, *data = NULL;
-    NI_PythonCallbackData cbdata;
-
-    if (!PyArg_ParseTuple(args, "O&OO&O&O&O&iidOO", NI_ObjectToInputArray,
-                                                &input, &fnc, NI_ObjectToOptionalInputArray,
-                                                &coordinates, NI_ObjectToOptionalInputArray,
-                                                &matrix, NI_ObjectToOptionalInputArray, &shift,
-                                                NI_ObjectToOutputArray, &output, &order, &mode,
-                                                &cval, &extra_arguments, &extra_keywords))
-        goto exit;
-
-    if (fnc != Py_None) {
-        if (!PyTuple_Check(extra_arguments)) {
-            PyErr_SetString(PyExc_RuntimeError,
-                                            "extra_arguments must be a tuple");
-            goto exit;
-        }
-        if (!PyDict_Check(extra_keywords)) {
-            PyErr_SetString(PyExc_RuntimeError,
-                                            "extra_keywords must be a dictionary");
-            goto exit;
-        }
-        if (PyCObject_Check(fnc)) {
-            func = PyCObject_AsVoidPtr(fnc);
-            data = PyCObject_GetDesc(fnc);
-        } else if (PyCallable_Check(fnc)) {
-            func = Py_Map;
-            cbdata.function = fnc;
-            cbdata.extra_arguments = extra_arguments;
-            cbdata.extra_keywords = extra_keywords;
-            data = (void*)&cbdata;
-        } else {
-            PyErr_SetString(PyExc_RuntimeError,
-                                            "function parameter is not callable");
-            goto exit;
-        }
-    }
-
-    if (!NI_GeometricTransform(input, func, data, matrix, shift, coordinates,
-                                                    output, order, (NI_ExtendMode)mode, cval))
-        goto exit;
-
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(output);
-    Py_XDECREF(coordinates);
-    Py_XDECREF(matrix);
-    Py_XDECREF(shift);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_ZoomShift(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL, *shift = NULL;
-    PyArrayObject *zoom = NULL;
-    int mode, order;
-    double cval;
-
-    if (!PyArg_ParseTuple(args, "O&O&O&O&iid", NI_ObjectToInputArray,
-                    &input, NI_ObjectToOptionalInputArray, &zoom,
-                    NI_ObjectToOptionalInputArray, &shift, NI_ObjectToOutputArray,
-                    &output, &order, &mode, &cval))
-        goto exit;
-
-    if (!NI_ZoomShift(input, zoom, shift, output, order, (NI_ExtendMode)mode,
-                                        cval))
-        goto exit;
-
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(shift);
-    Py_XDECREF(zoom);
-    Py_XDECREF(output);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_Label(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL, *strct = NULL;
-    maybelong max_label;
-
-    if (!PyArg_ParseTuple(args, "O&O&O&", NI_ObjectToInputArray, &input,
-                    NI_ObjectToInputArray, &strct, NI_ObjectToOutputArray, &output))
-        goto exit;
-
-    if (!NI_Label(input, strct, &max_label, output))
-        goto exit;
-
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(strct);
-    Py_XDECREF(output);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("l", (long)max_label);
-}
-
-static PyObject *Py_FindObjects(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL;
-    PyObject *result = NULL, *tuple = NULL, *start = NULL, *end = NULL;
-    PyObject *slc = NULL;
-    int jj;
-    long max_label;
-    maybelong ii, *regions = NULL;
-
-    if (!PyArg_ParseTuple(args, "O&l", NI_ObjectToInputArray, &input,
-                                                &max_label))
-        goto exit;
-
-    if (max_label < 0)
-        max_label = 0;
-    if (max_label > 0) {
-        if (input->nd > 0) {
-            regions = (maybelong*)malloc(2 * max_label * input->nd *
-                                                                                                        sizeof(maybelong));
-        } else {
-            regions = (maybelong*)malloc(max_label * sizeof(maybelong));
-        }
-        if (!regions) {
-            PyErr_NoMemory();
-            goto exit;
-        }
-    }
-
-    if (!NI_FindObjects(input, max_label, regions))
-        goto exit;
-
-    result = PyList_New(max_label);
-    if (!result) {
-        PyErr_NoMemory();
-        goto exit;
-    }
-
-    for(ii = 0; ii < max_label; ii++) {
-        maybelong idx = input->nd > 0 ? 2 * input->nd * ii : ii;
-        if (regions[idx] >= 0) {
-            PyObject *tuple = PyTuple_New(input->nd);
-            if (!tuple) {
-                PyErr_NoMemory();
-                goto exit;
-            }
-            for(jj = 0; jj < input->nd; jj++) {
-                start = PyInt_FromLong(regions[idx + jj]);
-                end = PyInt_FromLong(regions[idx + jj + input->nd]);
-                if (!start || !end) {
-                    PyErr_NoMemory();
-                    goto exit;
-                }
-                slc = PySlice_New(start, end, NULL);
-                if (!slc) {
-                    PyErr_NoMemory();
-                    goto exit;
-                }
-                Py_XDECREF(start);
-                Py_XDECREF(end);
-                start = end = NULL;
-                PyTuple_SetItem(tuple, jj, slc);
-                slc = NULL;
-            }
-            PyList_SetItem(result, ii, tuple);
-            tuple = NULL;
-        } else {
-            Py_INCREF(Py_None);
-            PyList_SetItem(result, ii, Py_None);
-        }
-    }
-
-    Py_INCREF(result);
-
- exit:
-    Py_XDECREF(input);
-    Py_XDECREF(result);
-    Py_XDECREF(tuple);
-    Py_XDECREF(start);
-    Py_XDECREF(end);
-    Py_XDECREF(slc);
-    if (regions)
-        free(regions);
-    if (PyErr_Occurred()) {
-        Py_XDECREF(result);
-        return NULL;
-    } else {
-        return result;
-    }
-}
-
-static PyObject *Py_WatershedIFT(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL, *markers = NULL;
-    PyArrayObject *strct = NULL;
-
-    if (!PyArg_ParseTuple(args, "O&O&O&O&", NI_ObjectToInputArray, &input,
-                    NI_ObjectToInputArray, &markers, NI_ObjectToInputArray,
-                    &strct, NI_ObjectToOutputArray, &output))
-        goto exit;
-
-    if (!NI_WatershedIFT(input, markers, strct, output))
-        goto exit;
-
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(markers);
-    Py_XDECREF(strct);
-    Py_XDECREF(output);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static int _NI_GetIndices(PyObject* indices_object,
-                                                    maybelong** result_indices, maybelong* min_label,
-                                                    maybelong* max_label, maybelong* n_results)
-{
-    maybelong *indices = NULL, n_indices, ii;
-
-    if (indices_object == Py_None) {
-        *min_label = -1;
-        *n_results = 1;
-    } else {
-        n_indices = NI_ObjectToLongSequenceAndLength(indices_object, &indices);
-        if (n_indices < 0)
-            goto exit;
-        if (n_indices < 1) {
-            PyErr_SetString(PyExc_RuntimeError, "no correct indices provided");
-            goto exit;
-        } else {
-            *min_label = *max_label = indices[0];
-            if (*min_label < 0) {
-                PyErr_SetString(PyExc_RuntimeError,
-                                                "negative indices not allowed");
-                goto exit;
-            }
-            for(ii = 1; ii < n_indices; ii++) {
-                if (indices[ii] < 0) {
-                    PyErr_SetString(PyExc_RuntimeError,
-                                                    "negative indices not allowed");
-                    goto exit;
-                }
-                if (indices[ii] < *min_label)
-                    *min_label = indices[ii];
-                if (indices[ii] > *max_label)
-                    *max_label = indices[ii];
-            }
-            *result_indices = (maybelong*)malloc((*max_label - *min_label + 1) *
-                                                                                     sizeof(maybelong));
-            if (!*result_indices) {
-                PyErr_NoMemory();
-                goto exit;
-            }
-            for(ii = 0; ii < *max_label - *min_label + 1; ii++)
-                (*result_indices)[ii] = -1;
-            *n_results = 0;
-            for(ii = 0; ii < n_indices; ii++) {
-                if ((*result_indices)[indices[ii] - *min_label] >= 0) {
-                    PyErr_SetString(PyExc_RuntimeError, "duplicate index");
-                    goto exit;
-                }
-                (*result_indices)[indices[ii] - *min_label] = ii;
-                ++(*n_results);
-            }
-        }
-    }
- exit:
-    if (indices)
-        free(indices);
-    return PyErr_Occurred() == NULL;
-}
-
-
-PyObject* _NI_BuildMeasurementResultArrayObject(maybelong n_results,
-                                                                                                PyArrayObject** values)
-{
-    PyObject *result = NULL;
-    if (n_results > 1) {
-        result = PyList_New(n_results);
-        if (result) {
-            maybelong ii;
-            for(ii = 0; ii < n_results; ii++) {
-                PyList_SET_ITEM(result, ii, (PyObject*)values[ii]);
-                Py_XINCREF(values[ii]);
-            }
-        }
-    } else {
-        result = (PyObject*)values[0];
-        Py_XINCREF(values[0]);
-    }
-    return result;
-}
-
-
-PyObject* _NI_BuildMeasurementResultDouble(maybelong n_results,
-                                                                                     double* values)
-{
-    PyObject *result = NULL;
-    if (n_results > 1) {
-        result = PyList_New(n_results);
-        if (result) {
-            int ii;
-            for(ii = 0; ii < n_results; ii++) {
-                PyObject* val = PyFloat_FromDouble(values[ii]);
-                if (!val) {
-                    Py_XDECREF(result);
-                    return NULL;
-                }
-                PyList_SET_ITEM(result, ii, val);
-            }
-        }
-    } else {
-        result = Py_BuildValue("d", values[0]);
-    }
-    return result;
-}
-
-
-PyObject* _NI_BuildMeasurementResultDoubleTuple(maybelong n_results,
-                                                                                        int tuple_size, double* values)
-{
-    PyObject *result = NULL;
-    maybelong ii;
-    int jj;
-
-    if (n_results > 1) {
-        result = PyList_New(n_results);
-        if (result) {
-            for(ii = 0; ii < n_results; ii++) {
-                PyObject* val = PyTuple_New(tuple_size);
-                if (!val) {
-                    Py_XDECREF(result);
-                    return NULL;
-                }
-                for(jj = 0; jj < tuple_size; jj++) {
-                    maybelong idx = jj + ii * tuple_size;
-                    PyTuple_SetItem(val, jj, PyFloat_FromDouble(values[idx]));
-                    if (PyErr_Occurred()) {
-                        Py_XDECREF(result);
-                        return NULL;
-                    }
-                }
-                PyList_SET_ITEM(result, ii, val);
-            }
-        }
-    } else {
-        result = PyTuple_New(tuple_size);
-        if (result) {
-            for(ii = 0; ii < tuple_size; ii++) {
-                PyTuple_SetItem(result, ii, PyFloat_FromDouble(values[ii]));
-                if (PyErr_Occurred()) {
-                    Py_XDECREF(result);
-                    return NULL;
-                }
-            }
-        }
-    }
-    return result;
-}
-
-
-PyObject* _NI_BuildMeasurementResultInt(maybelong n_results,
-                                                                                maybelong* values)
-{
-    PyObject *result = NULL;
-    if (n_results > 1) {
-        result = PyList_New(n_results);
-        if (result) {
-            maybelong ii;
-            for(ii = 0; ii < n_results; ii++) {
-                PyObject* val = PyInt_FromLong(values[ii]);
-                if (!val) {
-                    Py_XDECREF(result);
-                    return NULL;
-                }
-                PyList_SET_ITEM(result, ii, val);
-            }
-        }
-    } else {
-        result = Py_BuildValue("l", values[0]);
-    }
-    return result;
-}
-
-
-static PyObject *Py_Statistics(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *labels = NULL;
-    PyObject *indices_object, *result = NULL;
-    PyObject *res1 = NULL, *res2 = NULL, *res3 = NULL, *res4 = NULL;
-    double *dresult1 = NULL, *dresult2 = NULL;
-    maybelong *lresult1 = NULL, *lresult2 = NULL;
-    maybelong min_label, max_label, *result_indices = NULL, n_results, ii;
-    int type;
-
-    if (!PyArg_ParseTuple(args, "O&O&Oi", NI_ObjectToInputArray, &input,
-                    NI_ObjectToOptionalInputArray, &labels, &indices_object, &type))
-        goto exit;
-
-    if (!_NI_GetIndices(indices_object, &result_indices, &min_label,
-                                            &max_label, &n_results))
-        goto exit;
-
-    if (type >= 0 && type <= 7) {
-        dresult1 = (double*)malloc(n_results * sizeof(double));
-        if (!dresult1) {
-            PyErr_NoMemory();
-            goto exit;
-        }
-    }
-    if (type == 2 || type == 7) {
-        dresult2 = (double*)malloc(n_results * sizeof(double));
-        if (!dresult2) {
-            PyErr_NoMemory();
-            goto exit;
-        }
-    }
-    if (type == 1 || type == 2 || (type >= 5 && type <= 7)) {
-        lresult1 = (maybelong*)malloc(n_results * sizeof(maybelong));
-        if (!lresult1) {
-            PyErr_NoMemory();
-            goto exit;
-        }
-    }
-    if (type == 7) {
-        lresult2 = (maybelong*)malloc(n_results * sizeof(maybelong));
-        if (!lresult2) {
-            PyErr_NoMemory();
-            goto exit;
-        }
-    }
-    switch(type) {
-    case 0:
-        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-                                    n_results, dresult1, NULL, NULL, NULL, NULL, NULL, NULL))
-            goto exit;
-        result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
-        break;
-    case 1:
-        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-                            n_results, dresult1, lresult1, NULL, NULL, NULL, NULL, NULL))
-            goto exit;
-        for(ii = 0; ii < n_results; ii++)
-            dresult1[ii] = lresult1[ii] > 0 ? dresult1[ii] / lresult1[ii] : 0.0;
-
-        result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
-        break;
-    case 2:
-        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-                    n_results, dresult1, lresult1, dresult2, NULL, NULL, NULL, NULL))
-            goto exit;
-        result = _NI_BuildMeasurementResultDouble(n_results, dresult2);
-        break;
-    case 3:
-        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-                                    n_results, NULL, NULL, NULL, dresult1, NULL, NULL, NULL))
-            goto exit;
-        result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
-        break;
-    case 4:
-        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-                                    n_results, NULL, NULL, NULL, NULL, dresult1, NULL, NULL))
-            goto exit;
-        result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
-        break;
-    case 5:
-        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-                            n_results, NULL, NULL, NULL, dresult1, NULL, lresult1, NULL))
-            goto exit;
-        result = _NI_BuildMeasurementResultInt(n_results, lresult1);
-        break;
-    case 6:
-        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-                            n_results, NULL, NULL, NULL, NULL, dresult1, NULL, lresult1))
-            goto exit;
-        result = _NI_BuildMeasurementResultInt(n_results, lresult1);
-        break;
-    case 7:
-        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
-                                             n_results, NULL, NULL, NULL, dresult1, dresult2,
-                                             lresult1, lresult2))
-            goto exit;
-        res1 = _NI_BuildMeasurementResultDouble(n_results, dresult1);
-        res2 = _NI_BuildMeasurementResultDouble(n_results, dresult2);
-        res3 = _NI_BuildMeasurementResultInt(n_results, lresult1);
-        res4 = _NI_BuildMeasurementResultInt(n_results, lresult2);
-        if (!res1 || !res2 || !res3 || !res4)
-            goto exit;
-        result = Py_BuildValue("OOOO", res1, res2, res3, res4);
-        break;
-    default:
-        PyErr_SetString(PyExc_RuntimeError, "operation not supported");
-        goto exit;
-    }
-
- exit:
-    Py_XDECREF(input);
-    Py_XDECREF(labels);
-    if (result_indices)
-        free(result_indices);
-    if (dresult1)
-        free(dresult1);
-    if (dresult2)
-        free(dresult2);
-    if (lresult1)
-        free(lresult1);
-    if (lresult2)
-        free(lresult2);
-    return result;
-}
-
-
-static PyObject *Py_CenterOfMass(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *labels = NULL;
-    PyObject *indices_object, *result = NULL;
-    double *center_of_mass = NULL;
-    maybelong min_label, max_label, *result_indices = NULL, n_results;
-
-    if (!PyArg_ParseTuple(args, "O&O&O", NI_ObjectToInputArray, &input,
-                                    NI_ObjectToOptionalInputArray, &labels, &indices_object))
-        goto exit;
-
-    if (!_NI_GetIndices(indices_object, &result_indices, &min_label,
-                                            &max_label, &n_results))
-        goto exit;
-
-    center_of_mass = (double*)malloc(input->nd * n_results *
-                                                                     sizeof(double));
-    if (!center_of_mass) {
-        PyErr_NoMemory();
-        goto exit;
-    }
-
-    if (!NI_CenterOfMass(input, labels, min_label, max_label,
-                                             result_indices, n_results, center_of_mass))
-        goto exit;
-
-    result = _NI_BuildMeasurementResultDoubleTuple(n_results, input->nd,
-                                                                                                 center_of_mass);
-
- exit:
-    Py_XDECREF(input);
-    Py_XDECREF(labels);
-    if (result_indices)
-        free(result_indices);
-    if (center_of_mass)
-        free(center_of_mass);
-    return result;
-}
-
-static PyObject *Py_Histogram(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *labels = NULL, **histograms = NULL;
-    PyObject *indices_object, *result = NULL;
-    maybelong min_label, max_label, *result_indices = NULL, n_results;
-    maybelong jj, nbins;
-    long nbins_in;
-    double min, max;
-
-    if (!PyArg_ParseTuple(args, "O&ddlO&O", NI_ObjectToInputArray, &input,
-                                                &min, &max, &nbins_in, NI_ObjectToOptionalInputArray,
-                                                &labels, &indices_object))
-        goto exit;
-    nbins = nbins_in;
-
-    if (!_NI_GetIndices(indices_object, &result_indices, &min_label,
-                                            &max_label, &n_results))
-        goto exit;
-
-    /* Set all pointers to NULL, so that freeing the memory */
-    /* doesn't cause problems. */
-    histograms = (PyArrayObject**)calloc(input->nd * n_results,
-                                                                             sizeof(PyArrayObject*));
-    if (!histograms) {
-        PyErr_NoMemory();
-        goto exit;
-    }
-    for(jj = 0; jj < n_results; jj++) {
-        histograms[jj] = NA_NewArray(NULL, tInt32, 1, &nbins);
-        if (!histograms[jj]) {
-            PyErr_NoMemory();
-            goto exit;
-        }
-    }
-
-    if (!NI_Histogram(input, labels, min_label, max_label, result_indices,
-                                        n_results, histograms, min, max, nbins))
-        goto exit;
-
-    result = _NI_BuildMeasurementResultArrayObject(n_results, histograms);
-
- exit:
-    Py_XDECREF(input);
-    Py_XDECREF(labels);
-    if (result_indices)
-        free(result_indices);
-    if (histograms) {
-        for(jj = 0; jj < n_results; jj++) {
-            Py_XDECREF(histograms[jj]);
-        }
-        free(histograms);
-    }
-    return result;
-}
-
-static PyObject *Py_DistanceTransformBruteForce(PyObject *obj,
-                                                                                                PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL, *features = NULL;
-    PyArrayObject *sampling = NULL;
-    int metric;
-
-    if (!PyArg_ParseTuple(args, "O&iO&O&O&", NI_ObjectToInputArray, &input,
-                                                &metric, NI_ObjectToOptionalInputArray, &sampling,
-                                                NI_ObjectToOptionalOutputArray, &output,
-                                                NI_ObjectToOptionalOutputArray, &features))
-        goto exit;
-    if (!NI_DistanceTransformBruteForce(input, metric, sampling,
-                                                                            output, features))
-        goto exit;
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(sampling);
-    Py_XDECREF(output);
-    Py_XDECREF(features);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_DistanceTransformOnePass(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *strct = NULL, *distances = NULL, *features = NULL;
-
-    if (!PyArg_ParseTuple(args, "O&O&O&", NI_ObjectToInputArray, &strct,
-                                                NI_ObjectToIoArray, &distances,
-                                                NI_ObjectToOptionalOutputArray, &features))
-        goto exit;
-    if (!NI_DistanceTransformOnePass(strct, distances, features))
-        goto exit;
-exit:
-    Py_XDECREF(strct);
-    Py_XDECREF(distances);
-    Py_XDECREF(features);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_EuclideanFeatureTransform(PyObject *obj,
-                                                                                            PyObject *args)
-{
-    PyArrayObject *input = NULL, *features = NULL, *sampling = NULL;
-
-    if (!PyArg_ParseTuple(args, "O&O&O&", NI_ObjectToInputArray, &input,
-                                                NI_ObjectToOptionalInputArray, &sampling,
-                                                NI_ObjectToOutputArray, &features))
-        goto exit;
-    if (!NI_EuclideanFeatureTransform(input, sampling, features))
-        goto exit;
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(sampling);
-    Py_XDECREF(features);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static void _FreeCoordinateList(void* ptr)
-{
-    NI_FreeCoordinateList((NI_CoordinateList*)ptr);
-}
-
-static PyObject *Py_BinaryErosion(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *input = NULL, *output = NULL, *strct = NULL;
-    PyArrayObject *mask = NULL;
-    PyObject *cobj = NULL;
-    int border_value, invert, center_is_true;
-    int changed = 0, return_coordinates;
-    NI_CoordinateList *coordinate_list = NULL;
-    maybelong *origins = NULL;
-
-    if (!PyArg_ParseTuple(args, "O&O&O&O&iO&iii", NI_ObjectToInputArray,
-                                                &input, NI_ObjectToInputArray, &strct,
-                                                NI_ObjectToOptionalInputArray, &mask,
-                                                NI_ObjectToOutputArray, &output, &border_value,
-                                                NI_ObjectToLongSequence, &origins,  &invert,
-                                                &center_is_true, &return_coordinates))
-        goto exit;
-    if (!NI_BinaryErosion(input, strct, mask, output, border_value,
-                                                origins, invert, center_is_true, &changed,
-                                                return_coordinates ? &coordinate_list : NULL))
-        goto exit;
-    if (return_coordinates) {
-        cobj = PyCObject_FromVoidPtr(coordinate_list, _FreeCoordinateList);
-    }
-exit:
-    Py_XDECREF(input);
-    Py_XDECREF(strct);
-    Py_XDECREF(mask);
-    Py_XDECREF(output);
-    if (origins)
-        free(origins);
-    if (PyErr_Occurred()) {
-        Py_XDECREF(cobj);
-        return NULL;
-    } else {
-        if (return_coordinates) {
-            return Py_BuildValue("iN", changed, cobj);
-        } else {
-            return Py_BuildValue("i", changed);
-        }
-    }
-}
-
-static PyObject *Py_BinaryErosion2(PyObject *obj, PyObject *args)
-{
-    PyArrayObject *array = NULL, *strct = NULL, *mask = NULL;
-    PyObject *cobj = NULL;
-    int invert, niter;
-    maybelong *origins = NULL;
-
-    if (!PyArg_ParseTuple(args, "O&O&O&iO&iO", NI_ObjectToIoArray, &array,
-                    NI_ObjectToInputArray, &strct, NI_ObjectToOptionalInputArray,
-                    &mask, &niter, NI_ObjectToLongSequence, &origins, &invert,
-                    &cobj))
-        goto exit;
-
-    if (PyCObject_Check(cobj)) {
-        NI_CoordinateList *cobj_data = PyCObject_AsVoidPtr(cobj);
-        if (!NI_BinaryErosion2(array, strct, mask, niter, origins, invert,
-                                                     &cobj_data))
-            goto exit;
-    } else {
-        PyErr_SetString(PyExc_RuntimeError, "cannot convert CObject");
-        goto exit;
-    }
-exit:
-    Py_XDECREF(array);
-    Py_XDECREF(strct);
-    Py_XDECREF(mask);
-    if (origins) free(origins);
-    return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyMethodDef methods[] = {
-    {"correlate1d",           (PyCFunction)Py_Correlate1D,
-     METH_VARARGS, NULL},
-    {"correlate",             (PyCFunction)Py_Correlate,
-     METH_VARARGS, NULL},
-    {"uniform_filter1d",      (PyCFunction)Py_UniformFilter1D,
-     METH_VARARGS, NULL},
-    {"min_or_max_filter1d",   (PyCFunction)Py_MinOrMaxFilter1D,
-        METH_VARARGS, NULL},
-    {"min_or_max_filter",     (PyCFunction)Py_MinOrMaxFilter,
-        METH_VARARGS, NULL},
-    {"rank_filter",           (PyCFunction)Py_RankFilter,
-     METH_VARARGS, NULL},
-    {"generic_filter",        (PyCFunction)Py_GenericFilter,
-     METH_VARARGS, NULL},
-    {"generic_filter1d",      (PyCFunction)Py_GenericFilter1D,
-     METH_VARARGS, NULL},
-    {"fourier_filter",        (PyCFunction)Py_FourierFilter,
-     METH_VARARGS, NULL},
-    {"fourier_shift",         (PyCFunction)Py_FourierShift,
-     METH_VARARGS, NULL},
-    {"spline_filter1d",       (PyCFunction)Py_SplineFilter1D,
-     METH_VARARGS, NULL},
-    {"geometric_transform",   (PyCFunction)Py_GeometricTransform,
-        METH_VARARGS, NULL},
-    {"zoom_shift",            (PyCFunction)Py_ZoomShift,
-     METH_VARARGS, NULL},
-    {"label",                 (PyCFunction)Py_Label,
-     METH_VARARGS, NULL},
-    {"find_objects",          (PyCFunction)Py_FindObjects,
-     METH_VARARGS, NULL},
-    {"watershed_ift",         (PyCFunction)Py_WatershedIFT,
-     METH_VARARGS, NULL},
-    {"statistics",            (PyCFunction)Py_Statistics,
-     METH_VARARGS, NULL},
-    {"center_of_mass",        (PyCFunction)Py_CenterOfMass,
-     METH_VARARGS, NULL},
-    {"histogram",             (PyCFunction)Py_Histogram,
-     METH_VARARGS, NULL},
-    {"distance_transform_bf", (PyCFunction)Py_DistanceTransformBruteForce,
-     METH_VARARGS, NULL},
-    {"distance_transform_op", (PyCFunction)Py_DistanceTransformOnePass,
-     METH_VARARGS, NULL},
-    {"euclidean_feature_transform",
-     (PyCFunction)Py_EuclideanFeatureTransform, 
-     METH_VARARGS, NULL},
-    {"binary_erosion",        (PyCFunction)Py_BinaryErosion,
-     METH_VARARGS, NULL},
-    {"binary_erosion2",       (PyCFunction)Py_BinaryErosion2,
-     METH_VARARGS, NULL},
-    {NULL, NULL, 0, NULL}
-};
-
-PyMODINIT_FUNC init_nd_image(void)
-{
-    Py_InitModule("_nd_image", methods);
-    import_array();
-}
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define ND_IMPORT_ARRAY
+#include "nd_image.h"
+#undef ND_IMPORT_ARRAY
+#include "ni_support.h"
+#include "ni_filters.h"
+#include "ni_fourier.h"
+#include "ni_morphology.h"
+#include "ni_interpolation.h"
+#include "ni_measure.h"
+
+typedef struct {
+    PyObject *function;
+    PyObject *extra_arguments;
+    PyObject *extra_keywords;
+} NI_PythonCallbackData;
+
+/* Convert an input array of any type, not necessarily contiguous */
+static int
+NI_ObjectToInputArray(PyObject *object, PyArrayObject **array)
+{
+    *array = NA_InputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
+    return *array ? 1 : 0;
+}
+
+/* Convert an input array of any type, not necessarily contiguous */
+static int
+NI_ObjectToOptionalInputArray(PyObject *object, PyArrayObject **array)
+{
+    if (object == Py_None) {
+        *array = NULL;
+        return 1;
+    } else {
+        *array = NA_InputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
+        return *array ? 1 : 0;
+    }
+}
+
+/* Convert an output array of any type, not necessarily contiguous */
+static int
+NI_ObjectToOutputArray(PyObject *object, PyArrayObject **array)
+{
+    *array = NA_OutputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
+    return *array ? 1 : 0;
+}
+
+/* Convert an output array of any type, not necessarily contiguous */
+static int
+NI_ObjectToOptionalOutputArray(PyObject *object, PyArrayObject **array)
+{
+    if (object == Py_None) {
+        *array = NULL;
+        return 1;
+    } else {
+        *array = NA_OutputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
+        return *array ? 1 : 0;
+    }
+}
+
+/* Convert an input/output array of any type, not necessarily contiguous */
+static int
+NI_ObjectToIoArray(PyObject *object, PyArrayObject **array)
+{
+    *array = NA_IoArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
+    return *array ? 1 : 0;
+}
+
+/* Convert an Long sequence */
+static maybelong
+NI_ObjectToLongSequenceAndLength(PyObject *object, maybelong **sequence)
+{
+    long *pa, ii;
+    PyArrayObject *array = NA_InputArray(object, PyArray_LONG, NPY_CARRAY);
+    maybelong length = PyArray_SIZE(array);
+
+    *sequence = (maybelong*)malloc(length * sizeof(maybelong));
+    if (!*sequence) {
+        PyErr_NoMemory();
+        Py_XDECREF(array);
+        return -1;
+    }
+    pa = (long*)PyArray_DATA(array);
+    for(ii = 0; ii < length; ii++)
+        (*sequence)[ii] = pa[ii];
+    Py_XDECREF(array);
+    return length;
+}
+
+static int
+NI_ObjectToLongSequence(PyObject *object, maybelong **sequence)
+{
+    return NI_ObjectToLongSequenceAndLength(object, sequence) >= 0;
+}
+
+/*********************************************************************/
+/* wrapper functions: */
+/*********************************************************************/
+
+static PyObject *Py_Correlate1D(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *weights = NULL;
+    int axis, mode;
+    long origin;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&O&iO&idl", NI_ObjectToInputArray, &input,
+                                    NI_ObjectToInputArray, &weights, &axis,
+                                    NI_ObjectToOutputArray, &output, &mode, &cval, &origin))
+        goto exit;
+    if (!NI_Correlate1D(input, weights, axis, output,
+                                            (NI_ExtendMode)mode, cval, origin))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(weights);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_Correlate(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *weights = NULL;
+    maybelong *origin = NULL;
+    int mode;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&idO&", NI_ObjectToInputArray, &input,
+                    NI_ObjectToInputArray, &weights, NI_ObjectToOutputArray, &output,
+                    &mode, &cval, NI_ObjectToLongSequence, &origin))
+        goto exit;
+    if (!NI_Correlate(input, weights, output, (NI_ExtendMode)mode, cval,
+                                        origin))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(weights);
+    Py_XDECREF(output);
+    if (origin)
+        free(origin);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_UniformFilter1D(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL;
+    int axis, mode;
+    long filter_size, origin;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&liO&idl", NI_ObjectToInputArray, &input,
+                                        &filter_size, &axis, NI_ObjectToOutputArray, &output,
+                                        &mode, &cval, &origin))
+        goto exit;
+    if (!NI_UniformFilter1D(input, filter_size, axis, output,
+                                                                             (NI_ExtendMode)mode, cval, origin))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_MinOrMaxFilter1D(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL;
+    int axis, mode, minimum;
+    long filter_size, origin;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&liO&idli", NI_ObjectToInputArray, &input,
+                                        &filter_size, &axis, NI_ObjectToOutputArray, &output,
+                                        &mode, &cval, &origin, &minimum))
+        goto exit;
+    if (!NI_MinOrMaxFilter1D(input, filter_size, axis, output,
+                                                            (NI_ExtendMode)mode, cval, origin, minimum))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_MinOrMaxFilter(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
+    PyArrayObject *structure = NULL;
+    maybelong *origin = NULL;
+    int mode, minimum;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&O&idO&i", NI_ObjectToInputArray,
+                                        &input, NI_ObjectToInputArray, &footprint,
+                                        NI_ObjectToOptionalInputArray, &structure,
+                                        NI_ObjectToOutputArray, &output, &mode, &cval,
+                                        NI_ObjectToLongSequence, &origin, &minimum))
+        goto exit;
+    if (!NI_MinOrMaxFilter(input, footprint, structure, output,
+                                                (NI_ExtendMode)mode, cval, origin, minimum))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(footprint);
+    Py_XDECREF(structure);
+    Py_XDECREF(output);
+    if (origin)
+        free(origin);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_RankFilter(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
+    maybelong *origin = NULL;
+    int mode, rank;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&iO&O&idO&", NI_ObjectToInputArray,
+                                        &input, &rank, NI_ObjectToInputArray, &footprint,
+                                        NI_ObjectToOutputArray, &output, &mode, &cval,
+                                        NI_ObjectToLongSequence, &origin))
+        goto exit;
+    if (!NI_RankFilter(input, rank, footprint, output, (NI_ExtendMode)mode,
+                                         cval, origin))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(footprint);
+    Py_XDECREF(output);
+    if (origin)
+        free(origin);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static int Py_Filter1DFunc(double *iline, maybelong ilen,
+                                                     double *oline, maybelong olen, void *data)
+{
+    PyArrayObject *py_ibuffer = NULL, *py_obuffer = NULL;
+    PyObject *rv = NULL, *args = NULL, *tmp = NULL;
+    maybelong ii;
+    double *po = NULL;
+    NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
+
+    py_ibuffer = NA_NewArray(iline, PyArray_DOUBLE, 1, &ilen);
+    py_obuffer = NA_NewArray(NULL, PyArray_DOUBLE, 1, &olen);
+    if (!py_ibuffer || !py_obuffer)
+        goto exit;
+    tmp = Py_BuildValue("(OO)", py_ibuffer, py_obuffer);
+    if (!tmp)
+        goto exit;
+    args = PySequence_Concat(tmp, cbdata->extra_arguments);
+    if (!args)
+        goto exit;
+    rv = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
+    if (!rv)
+        goto exit;
+    po = (double*)PyArray_DATA(py_obuffer);
+    for(ii = 0; ii < olen; ii++)
+        oline[ii] = po[ii];
+exit:
+    Py_XDECREF(py_ibuffer);
+    Py_XDECREF(py_obuffer);
+    Py_XDECREF(rv);
+    Py_XDECREF(args);
+    Py_XDECREF(tmp);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+static PyObject *Py_GenericFilter1D(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL;
+    PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
+    void *func = Py_Filter1DFunc, *data = NULL;
+    NI_PythonCallbackData cbdata;
+    int axis, mode;
+    long origin, filter_size;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&OliO&idlOO", NI_ObjectToInputArray,
+                &input, &fnc, &filter_size, &axis, NI_ObjectToOutputArray,
+                &output, &mode, &cval, &origin, &extra_arguments, &extra_keywords))
+        goto exit;
+    if (!PyTuple_Check(extra_arguments)) {
+        PyErr_SetString(PyExc_RuntimeError,
+                                        "extra_arguments must be a tuple");
+        goto exit;
+    }
+    if (!PyDict_Check(extra_keywords)) {
+        PyErr_SetString(PyExc_RuntimeError,
+                                        "extra_keywords must be a dictionary");
+        goto exit;
+    }
+    if (PyCObject_Check(fnc)) {
+        func = PyCObject_AsVoidPtr(fnc);
+        data = PyCObject_GetDesc(fnc);
+    } else if (PyCallable_Check(fnc)) {
+        cbdata.function = fnc;
+        cbdata.extra_arguments = extra_arguments;
+        cbdata.extra_keywords = extra_keywords;
+        data = (void*)&cbdata;
+    } else {
+        PyErr_SetString(PyExc_RuntimeError,
+                                        "function parameter is not callable");
+        goto exit;
+    }
+    if (!NI_GenericFilter1D(input, func, data, filter_size, axis, output,
+                                                                                (NI_ExtendMode)mode, cval, origin))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static int Py_FilterFunc(double *buffer, maybelong filter_size,
+                                                 double *output, void *data)
+{
+    PyArrayObject *py_buffer = NULL;
+    PyObject *rv = NULL, *args = NULL, *tmp = NULL;
+    NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
+
+    py_buffer = NA_NewArray(buffer, PyArray_DOUBLE, 1, &filter_size);
+    if (!py_buffer)
+        goto exit;
+    tmp = Py_BuildValue("(O)", py_buffer);
+    if (!tmp)
+        goto exit;
+    args = PySequence_Concat(tmp, cbdata->extra_arguments);
+    if (!args)
+        goto exit;
+    rv = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
+    if (!rv)
+        goto exit;
+    *output = PyFloat_AsDouble(rv);
+exit:
+    Py_XDECREF(py_buffer);
+    Py_XDECREF(rv);
+    Py_XDECREF(args);
+    Py_XDECREF(tmp);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+static PyObject *Py_GenericFilter(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
+    PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
+    void *func = Py_FilterFunc, *data = NULL;
+    NI_PythonCallbackData cbdata;
+    int mode;
+    maybelong *origin = NULL;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&OO&O&idO&OO", NI_ObjectToInputArray,
+                                                &input, &fnc, NI_ObjectToInputArray, &footprint,
+                                                NI_ObjectToOutputArray, &output, &mode, &cval,
+                                                NI_ObjectToLongSequence, &origin,
+                                                &extra_arguments, &extra_keywords))
+        goto exit;
+    if (!PyTuple_Check(extra_arguments)) {
+        PyErr_SetString(PyExc_RuntimeError,
+                                        "extra_arguments must be a tuple");
+        goto exit;
+    }
+    if (!PyDict_Check(extra_keywords)) {
+        PyErr_SetString(PyExc_RuntimeError,
+                                        "extra_keywords must be a dictionary");
+        goto exit;
+    }
+    if (PyCObject_Check(fnc)) {
+        func = PyCObject_AsVoidPtr(fnc);
+        data = PyCObject_GetDesc(fnc);
+    } else if (PyCallable_Check(fnc)) {
+        cbdata.function = fnc;
+        cbdata.extra_arguments = extra_arguments;
+        cbdata.extra_keywords = extra_keywords;
+        data = (void*)&cbdata;
+    } else {
+        PyErr_SetString(PyExc_RuntimeError,
+                                        "function parameter is not callable");
+        goto exit;
+    }
+    if (!NI_GenericFilter(input, func, data, footprint, output,
+                                                (NI_ExtendMode)mode, cval, origin))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(output);
+    Py_XDECREF(footprint);
+    if (origin)
+        free(origin);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_FourierFilter(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *parameters = NULL;
+    int axis, filter_type;
+    long n;
+
+    if (!PyArg_ParseTuple(args, "O&O&liO&i", NI_ObjectToInputArray, &input,
+                                        NI_ObjectToInputArray, &parameters, &n, &axis,
+                                        NI_ObjectToOutputArray, &output, &filter_type))
+        goto exit;
+
+    if (!NI_FourierFilter(input, parameters, n, axis, output, filter_type))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(parameters);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_FourierShift(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *shifts = NULL;
+    int axis;
+    long n;
+
+    if (!PyArg_ParseTuple(args, "O&O&liO&", NI_ObjectToInputArray, &input,
+                                        NI_ObjectToInputArray, &shifts, &n, &axis,
+                                        NI_ObjectToOutputArray, &output))
+        goto exit;
+
+    if (!NI_FourierShift(input, shifts, n, axis, output))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(shifts);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_SplineFilter1D(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL;
+    int axis, order;
+
+    if (!PyArg_ParseTuple(args, "O&iiO&", NI_ObjectToInputArray, &input,
+                    &order, &axis, NI_ObjectToOutputArray, &output))
+        goto exit;
+
+    if (!NI_SplineFilter1D(input, order, axis, output))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static int Py_Map(maybelong *ocoor, double* icoor, int orank, int irank,
+                                    void *data)
+{
+    PyObject *coors = NULL, *rets = NULL, *args = NULL, *tmp = NULL;
+    maybelong ii;
+    NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
+
+    coors = PyTuple_New(orank);
+    if (!coors)
+        goto exit;
+    for(ii = 0; ii < orank; ii++) {
+        PyTuple_SetItem(coors, ii, PyInt_FromLong(ocoor[ii]));
+        if (PyErr_Occurred())
+            goto exit;
+    }
+    tmp = Py_BuildValue("(O)", coors);
+    if (!tmp)
+        goto exit;
+    args = PySequence_Concat(tmp, cbdata->extra_arguments);
+    if (!args)
+        goto exit;
+    rets = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
+    if (!rets)
+        goto exit;
+    for(ii = 0; ii < irank; ii++) {
+        icoor[ii] = PyFloat_AsDouble(PyTuple_GetItem(rets, ii));
+        if (PyErr_Occurred())
+            goto exit;
+    }
+exit:
+    Py_XDECREF(coors);
+    Py_XDECREF(tmp);
+    Py_XDECREF(rets);
+    Py_XDECREF(args);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+
+static PyObject *Py_GeometricTransform(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL;
+    PyArrayObject *coordinates = NULL, *matrix = NULL, *shift = NULL;
+    PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
+    int mode, order;
+    double cval;
+    void *func = NULL, *data = NULL;
+    NI_PythonCallbackData cbdata;
+
+    if (!PyArg_ParseTuple(args, "O&OO&O&O&O&iidOO", NI_ObjectToInputArray,
+                                                &input, &fnc, NI_ObjectToOptionalInputArray,
+                                                &coordinates, NI_ObjectToOptionalInputArray,
+                                                &matrix, NI_ObjectToOptionalInputArray, &shift,
+                                                NI_ObjectToOutputArray, &output, &order, &mode,
+                                                &cval, &extra_arguments, &extra_keywords))
+        goto exit;
+
+    if (fnc != Py_None) {
+        if (!PyTuple_Check(extra_arguments)) {
+            PyErr_SetString(PyExc_RuntimeError,
+                                            "extra_arguments must be a tuple");
+            goto exit;
+        }
+        if (!PyDict_Check(extra_keywords)) {
+            PyErr_SetString(PyExc_RuntimeError,
+                                            "extra_keywords must be a dictionary");
+            goto exit;
+        }
+        if (PyCObject_Check(fnc)) {
+            func = PyCObject_AsVoidPtr(fnc);
+            data = PyCObject_GetDesc(fnc);
+        } else if (PyCallable_Check(fnc)) {
+            func = Py_Map;
+            cbdata.function = fnc;
+            cbdata.extra_arguments = extra_arguments;
+            cbdata.extra_keywords = extra_keywords;
+            data = (void*)&cbdata;
+        } else {
+            PyErr_SetString(PyExc_RuntimeError,
+                                            "function parameter is not callable");
+            goto exit;
+        }
+    }
+
+    if (!NI_GeometricTransform(input, func, data, matrix, shift, coordinates,
+                                                    output, order, (NI_ExtendMode)mode, cval))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(output);
+    Py_XDECREF(coordinates);
+    Py_XDECREF(matrix);
+    Py_XDECREF(shift);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_ZoomShift(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *shift = NULL;
+    PyArrayObject *zoom = NULL;
+    int mode, order;
+    double cval;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&O&iid", NI_ObjectToInputArray,
+                    &input, NI_ObjectToOptionalInputArray, &zoom,
+                    NI_ObjectToOptionalInputArray, &shift, NI_ObjectToOutputArray,
+                    &output, &order, &mode, &cval))
+        goto exit;
+
+    if (!NI_ZoomShift(input, zoom, shift, output, order, (NI_ExtendMode)mode,
+                                        cval))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(shift);
+    Py_XDECREF(zoom);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_Label(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *strct = NULL;
+    maybelong max_label;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&", NI_ObjectToInputArray, &input,
+                    NI_ObjectToInputArray, &strct, NI_ObjectToOutputArray, &output))
+        goto exit;
+
+    if (!NI_Label(input, strct, &max_label, output))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(strct);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("l", (long)max_label);
+}
+
+static PyObject *Py_FindObjects(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL;
+    PyObject *result = NULL, *tuple = NULL, *start = NULL, *end = NULL;
+    PyObject *slc = NULL;
+    int jj;
+    long max_label;
+    maybelong ii, *regions = NULL;
+
+    if (!PyArg_ParseTuple(args, "O&l", NI_ObjectToInputArray, &input,
+                                                &max_label))
+        goto exit;
+
+    if (max_label < 0)
+        max_label = 0;
+    if (max_label > 0) {
+        if (input->nd > 0) {
+            regions = (maybelong*)malloc(2 * max_label * input->nd *
+                                                                                                        sizeof(maybelong));
+        } else {
+            regions = (maybelong*)malloc(max_label * sizeof(maybelong));
+        }
+        if (!regions) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+
+    if (!NI_FindObjects(input, max_label, regions))
+        goto exit;
+
+    result = PyList_New(max_label);
+    if (!result) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+
+    for(ii = 0; ii < max_label; ii++) {
+        maybelong idx = input->nd > 0 ? 2 * input->nd * ii : ii;
+        if (regions[idx] >= 0) {
+            PyObject *tuple = PyTuple_New(input->nd);
+            if (!tuple) {
+                PyErr_NoMemory();
+                goto exit;
+            }
+            for(jj = 0; jj < input->nd; jj++) {
+                start = PyInt_FromLong(regions[idx + jj]);
+                end = PyInt_FromLong(regions[idx + jj + input->nd]);
+                if (!start || !end) {
+                    PyErr_NoMemory();
+                    goto exit;
+                }
+                slc = PySlice_New(start, end, NULL);
+                if (!slc) {
+                    PyErr_NoMemory();
+                    goto exit;
+                }
+                Py_XDECREF(start);
+                Py_XDECREF(end);
+                start = end = NULL;
+                PyTuple_SetItem(tuple, jj, slc);
+                slc = NULL;
+            }
+            PyList_SetItem(result, ii, tuple);
+            tuple = NULL;
+        } else {
+            Py_INCREF(Py_None);
+            PyList_SetItem(result, ii, Py_None);
+        }
+    }
+
+    Py_INCREF(result);
+
+ exit:
+    Py_XDECREF(input);
+    Py_XDECREF(result);
+    Py_XDECREF(tuple);
+    Py_XDECREF(start);
+    Py_XDECREF(end);
+    Py_XDECREF(slc);
+    if (regions)
+        free(regions);
+    if (PyErr_Occurred()) {
+        Py_XDECREF(result);
+        return NULL;
+    } else {
+        return result;
+    }
+}
+
+static PyObject *Py_WatershedIFT(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *markers = NULL;
+    PyArrayObject *strct = NULL;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&O&", NI_ObjectToInputArray, &input,
+                    NI_ObjectToInputArray, &markers, NI_ObjectToInputArray,
+                    &strct, NI_ObjectToOutputArray, &output))
+        goto exit;
+
+    if (!NI_WatershedIFT(input, markers, strct, output))
+        goto exit;
+
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(markers);
+    Py_XDECREF(strct);
+    Py_XDECREF(output);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static int _NI_GetIndices(PyObject* indices_object,
+                                                    maybelong** result_indices, maybelong* min_label,
+                                                    maybelong* max_label, maybelong* n_results)
+{
+    maybelong *indices = NULL, n_indices, ii;
+
+    if (indices_object == Py_None) {
+        *min_label = -1;
+        *n_results = 1;
+    } else {
+        n_indices = NI_ObjectToLongSequenceAndLength(indices_object, &indices);
+        if (n_indices < 0)
+            goto exit;
+        if (n_indices < 1) {
+            PyErr_SetString(PyExc_RuntimeError, "no correct indices provided");
+            goto exit;
+        } else {
+            *min_label = *max_label = indices[0];
+            if (*min_label < 0) {
+                PyErr_SetString(PyExc_RuntimeError,
+                                                "negative indices not allowed");
+                goto exit;
+            }
+            for(ii = 1; ii < n_indices; ii++) {
+                if (indices[ii] < 0) {
+                    PyErr_SetString(PyExc_RuntimeError,
+                                                    "negative indices not allowed");
+                    goto exit;
+                }
+                if (indices[ii] < *min_label)
+                    *min_label = indices[ii];
+                if (indices[ii] > *max_label)
+                    *max_label = indices[ii];
+            }
+            *result_indices = (maybelong*)malloc((*max_label - *min_label + 1) *
+                                                                                     sizeof(maybelong));
+            if (!*result_indices) {
+                PyErr_NoMemory();
+                goto exit;
+            }
+            for(ii = 0; ii < *max_label - *min_label + 1; ii++)
+                (*result_indices)[ii] = -1;
+            *n_results = 0;
+            for(ii = 0; ii < n_indices; ii++) {
+                if ((*result_indices)[indices[ii] - *min_label] >= 0) {
+                    PyErr_SetString(PyExc_RuntimeError, "duplicate index");
+                    goto exit;
+                }
+                (*result_indices)[indices[ii] - *min_label] = ii;
+                ++(*n_results);
+            }
+        }
+    }
+ exit:
+    if (indices)
+        free(indices);
+    return PyErr_Occurred() == NULL;
+}
+
+
+PyObject* _NI_BuildMeasurementResultArrayObject(maybelong n_results,
+                                                                                                PyArrayObject** values)
+{
+    PyObject *result = NULL;
+    if (n_results > 1) {
+        result = PyList_New(n_results);
+        if (result) {
+            maybelong ii;
+            for(ii = 0; ii < n_results; ii++) {
+                PyList_SET_ITEM(result, ii, (PyObject*)values[ii]);
+                Py_XINCREF(values[ii]);
+            }
+        }
+    } else {
+        result = (PyObject*)values[0];
+        Py_XINCREF(values[0]);
+    }
+    return result;
+}
+
+
+PyObject* _NI_BuildMeasurementResultDouble(maybelong n_results,
+                                                                                     double* values)
+{
+    PyObject *result = NULL;
+    if (n_results > 1) {
+        result = PyList_New(n_results);
+        if (result) {
+            int ii;
+            for(ii = 0; ii < n_results; ii++) {
+                PyObject* val = PyFloat_FromDouble(values[ii]);
+                if (!val) {
+                    Py_XDECREF(result);
+                    return NULL;
+                }
+                PyList_SET_ITEM(result, ii, val);
+            }
+        }
+    } else {
+        result = Py_BuildValue("d", values[0]);
+    }
+    return result;
+}
+
+
+PyObject* _NI_BuildMeasurementResultDoubleTuple(maybelong n_results,
+                                                                                        int tuple_size, double* values)
+{
+    PyObject *result = NULL;
+    maybelong ii;
+    int jj;
+
+    if (n_results > 1) {
+        result = PyList_New(n_results);
+        if (result) {
+            for(ii = 0; ii < n_results; ii++) {
+                PyObject* val = PyTuple_New(tuple_size);
+                if (!val) {
+                    Py_XDECREF(result);
+                    return NULL;
+                }
+                for(jj = 0; jj < tuple_size; jj++) {
+                    maybelong idx = jj + ii * tuple_size;
+                    PyTuple_SetItem(val, jj, PyFloat_FromDouble(values[idx]));
+                    if (PyErr_Occurred()) {
+                        Py_XDECREF(result);
+                        return NULL;
+                    }
+                }
+                PyList_SET_ITEM(result, ii, val);
+            }
+        }
+    } else {
+        result = PyTuple_New(tuple_size);
+        if (result) {
+            for(ii = 0; ii < tuple_size; ii++) {
+                PyTuple_SetItem(result, ii, PyFloat_FromDouble(values[ii]));
+                if (PyErr_Occurred()) {
+                    Py_XDECREF(result);
+                    return NULL;
+                }
+            }
+        }
+    }
+    return result;
+}
+
+
+PyObject* _NI_BuildMeasurementResultInt(maybelong n_results,
+                                                                                maybelong* values)
+{
+    PyObject *result = NULL;
+    if (n_results > 1) {
+        result = PyList_New(n_results);
+        if (result) {
+            maybelong ii;
+            for(ii = 0; ii < n_results; ii++) {
+                PyObject* val = PyInt_FromLong(values[ii]);
+                if (!val) {
+                    Py_XDECREF(result);
+                    return NULL;
+                }
+                PyList_SET_ITEM(result, ii, val);
+            }
+        }
+    } else {
+        result = Py_BuildValue("l", values[0]);
+    }
+    return result;
+}
+
+
+static PyObject *Py_Statistics(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *labels = NULL;
+    PyObject *indices_object, *result = NULL;
+    PyObject *res1 = NULL, *res2 = NULL, *res3 = NULL, *res4 = NULL;
+    double *dresult1 = NULL, *dresult2 = NULL;
+    maybelong *lresult1 = NULL, *lresult2 = NULL;
+    maybelong min_label, max_label, *result_indices = NULL, n_results, ii;
+    int type;
+
+    if (!PyArg_ParseTuple(args, "O&O&Oi", NI_ObjectToInputArray, &input,
+                    NI_ObjectToOptionalInputArray, &labels, &indices_object, &type))
+        goto exit;
+
+    if (!_NI_GetIndices(indices_object, &result_indices, &min_label,
+                                            &max_label, &n_results))
+        goto exit;
+
+    if (type >= 0 && type <= 7) {
+        dresult1 = (double*)malloc(n_results * sizeof(double));
+        if (!dresult1) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+    if (type == 2 || type == 7) {
+        dresult2 = (double*)malloc(n_results * sizeof(double));
+        if (!dresult2) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+    if (type == 1 || type == 2 || (type >= 5 && type <= 7)) {
+        lresult1 = (maybelong*)malloc(n_results * sizeof(maybelong));
+        if (!lresult1) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+    if (type == 7) {
+        lresult2 = (maybelong*)malloc(n_results * sizeof(maybelong));
+        if (!lresult2) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+    switch(type) {
+    case 0:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                                    n_results, dresult1, NULL, NULL, NULL, NULL, NULL, NULL))
+            goto exit;
+        result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
+        break;
+    case 1:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                            n_results, dresult1, lresult1, NULL, NULL, NULL, NULL, NULL))
+            goto exit;
+        for(ii = 0; ii < n_results; ii++)
+            dresult1[ii] = lresult1[ii] > 0 ? dresult1[ii] / lresult1[ii] : 0.0;
+
+        result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
+        break;
+    case 2:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                    n_results, dresult1, lresult1, dresult2, NULL, NULL, NULL, NULL))
+            goto exit;
+        result = _NI_BuildMeasurementResultDouble(n_results, dresult2);
+        break;
+    case 3:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                                    n_results, NULL, NULL, NULL, dresult1, NULL, NULL, NULL))
+            goto exit;
+        result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
+        break;
+    case 4:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                                    n_results, NULL, NULL, NULL, NULL, dresult1, NULL, NULL))
+            goto exit;
+        result = _NI_BuildMeasurementResultDouble(n_results, dresult1);
+        break;
+    case 5:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                            n_results, NULL, NULL, NULL, dresult1, NULL, lresult1, NULL))
+            goto exit;
+        result = _NI_BuildMeasurementResultInt(n_results, lresult1);
+        break;
+    case 6:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                            n_results, NULL, NULL, NULL, NULL, dresult1, NULL, lresult1))
+            goto exit;
+        result = _NI_BuildMeasurementResultInt(n_results, lresult1);
+        break;
+    case 7:
+        if (!NI_Statistics(input, labels, min_label, max_label, result_indices,
+                                             n_results, NULL, NULL, NULL, dresult1, dresult2,
+                                             lresult1, lresult2))
+            goto exit;
+        res1 = _NI_BuildMeasurementResultDouble(n_results, dresult1);
+        res2 = _NI_BuildMeasurementResultDouble(n_results, dresult2);
+        res3 = _NI_BuildMeasurementResultInt(n_results, lresult1);
+        res4 = _NI_BuildMeasurementResultInt(n_results, lresult2);
+        if (!res1 || !res2 || !res3 || !res4)
+            goto exit;
+        result = Py_BuildValue("OOOO", res1, res2, res3, res4);
+        break;
+    default:
+        PyErr_SetString(PyExc_RuntimeError, "operation not supported");
+        goto exit;
+    }
+
+ exit:
+    Py_XDECREF(input);
+    Py_XDECREF(labels);
+    if (result_indices)
+        free(result_indices);
+    if (dresult1)
+        free(dresult1);
+    if (dresult2)
+        free(dresult2);
+    if (lresult1)
+        free(lresult1);
+    if (lresult2)
+        free(lresult2);
+    return result;
+}
+
+
+static PyObject *Py_CenterOfMass(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *labels = NULL;
+    PyObject *indices_object, *result = NULL;
+    double *center_of_mass = NULL;
+    maybelong min_label, max_label, *result_indices = NULL, n_results;
+
+    if (!PyArg_ParseTuple(args, "O&O&O", NI_ObjectToInputArray, &input,
+                                    NI_ObjectToOptionalInputArray, &labels, &indices_object))
+        goto exit;
+
+    if (!_NI_GetIndices(indices_object, &result_indices, &min_label,
+                                            &max_label, &n_results))
+        goto exit;
+
+    center_of_mass = (double*)malloc(input->nd * n_results *
+                                                                     sizeof(double));
+    if (!center_of_mass) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+
+    if (!NI_CenterOfMass(input, labels, min_label, max_label,
+                                             result_indices, n_results, center_of_mass))
+        goto exit;
+
+    result = _NI_BuildMeasurementResultDoubleTuple(n_results, input->nd,
+                                                                                                 center_of_mass);
+
+ exit:
+    Py_XDECREF(input);
+    Py_XDECREF(labels);
+    if (result_indices)
+        free(result_indices);
+    if (center_of_mass)
+        free(center_of_mass);
+    return result;
+}
+
+static PyObject *Py_Histogram(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *labels = NULL, **histograms = NULL;
+    PyObject *indices_object, *result = NULL;
+    maybelong min_label, max_label, *result_indices = NULL, n_results;
+    maybelong jj, nbins;
+    long nbins_in;
+    double min, max;
+
+    if (!PyArg_ParseTuple(args, "O&ddlO&O", NI_ObjectToInputArray, &input,
+                                                &min, &max, &nbins_in, NI_ObjectToOptionalInputArray,
+                                                &labels, &indices_object))
+        goto exit;
+    nbins = nbins_in;
+
+    if (!_NI_GetIndices(indices_object, &result_indices, &min_label,
+                                            &max_label, &n_results))
+        goto exit;
+
+    /* Set all pointers to NULL, so that freeing the memory */
+    /* doesn't cause problems. */
+    histograms = (PyArrayObject**)calloc(input->nd * n_results,
+                                                                             sizeof(PyArrayObject*));
+    if (!histograms) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < n_results; jj++) {
+        histograms[jj] = NA_NewArray(NULL, tInt32, 1, &nbins);
+        if (!histograms[jj]) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+
+    if (!NI_Histogram(input, labels, min_label, max_label, result_indices,
+                                        n_results, histograms, min, max, nbins))
+        goto exit;
+
+    result = _NI_BuildMeasurementResultArrayObject(n_results, histograms);
+
+ exit:
+    Py_XDECREF(input);
+    Py_XDECREF(labels);
+    if (result_indices)
+        free(result_indices);
+    if (histograms) {
+        for(jj = 0; jj < n_results; jj++) {
+            Py_XDECREF(histograms[jj]);
+        }
+        free(histograms);
+    }
+    return result;
+}
+
+static PyObject *Py_DistanceTransformBruteForce(PyObject *obj,
+                                                                                                PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *features = NULL;
+    PyArrayObject *sampling = NULL;
+    int metric;
+
+    if (!PyArg_ParseTuple(args, "O&iO&O&O&", NI_ObjectToInputArray, &input,
+                                                &metric, NI_ObjectToOptionalInputArray, &sampling,
+                                                NI_ObjectToOptionalOutputArray, &output,
+                                                NI_ObjectToOptionalOutputArray, &features))
+        goto exit;
+    if (!NI_DistanceTransformBruteForce(input, metric, sampling,
+                                                                            output, features))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(sampling);
+    Py_XDECREF(output);
+    Py_XDECREF(features);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_DistanceTransformOnePass(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *strct = NULL, *distances = NULL, *features = NULL;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&", NI_ObjectToInputArray, &strct,
+                                                NI_ObjectToIoArray, &distances,
+                                                NI_ObjectToOptionalOutputArray, &features))
+        goto exit;
+    if (!NI_DistanceTransformOnePass(strct, distances, features))
+        goto exit;
+exit:
+    Py_XDECREF(strct);
+    Py_XDECREF(distances);
+    Py_XDECREF(features);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyObject *Py_EuclideanFeatureTransform(PyObject *obj,
+                                                                                            PyObject *args)
+{
+    PyArrayObject *input = NULL, *features = NULL, *sampling = NULL;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&", NI_ObjectToInputArray, &input,
+                                                NI_ObjectToOptionalInputArray, &sampling,
+                                                NI_ObjectToOutputArray, &features))
+        goto exit;
+    if (!NI_EuclideanFeatureTransform(input, sampling, features))
+        goto exit;
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(sampling);
+    Py_XDECREF(features);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static void _FreeCoordinateList(void* ptr)
+{
+    NI_FreeCoordinateList((NI_CoordinateList*)ptr);
+}
+
+static PyObject *Py_BinaryErosion(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *input = NULL, *output = NULL, *strct = NULL;
+    PyArrayObject *mask = NULL;
+    PyObject *cobj = NULL;
+    int border_value, invert, center_is_true;
+    int changed = 0, return_coordinates;
+    NI_CoordinateList *coordinate_list = NULL;
+    maybelong *origins = NULL;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&O&iO&iii", NI_ObjectToInputArray,
+                                                &input, NI_ObjectToInputArray, &strct,
+                                                NI_ObjectToOptionalInputArray, &mask,
+                                                NI_ObjectToOutputArray, &output, &border_value,
+                                                NI_ObjectToLongSequence, &origins,  &invert,
+                                                &center_is_true, &return_coordinates))
+        goto exit;
+    if (!NI_BinaryErosion(input, strct, mask, output, border_value,
+                                                origins, invert, center_is_true, &changed,
+                                                return_coordinates ? &coordinate_list : NULL))
+        goto exit;
+    if (return_coordinates) {
+        cobj = PyCObject_FromVoidPtr(coordinate_list, _FreeCoordinateList);
+    }
+exit:
+    Py_XDECREF(input);
+    Py_XDECREF(strct);
+    Py_XDECREF(mask);
+    Py_XDECREF(output);
+    if (origins)
+        free(origins);
+    if (PyErr_Occurred()) {
+        Py_XDECREF(cobj);
+        return NULL;
+    } else {
+        if (return_coordinates) {
+            return Py_BuildValue("iN", changed, cobj);
+        } else {
+            return Py_BuildValue("i", changed);
+        }
+    }
+}
+
+static PyObject *Py_BinaryErosion2(PyObject *obj, PyObject *args)
+{
+    PyArrayObject *array = NULL, *strct = NULL, *mask = NULL;
+    PyObject *cobj = NULL;
+    int invert, niter;
+    maybelong *origins = NULL;
+
+    if (!PyArg_ParseTuple(args, "O&O&O&iO&iO", NI_ObjectToIoArray, &array,
+                    NI_ObjectToInputArray, &strct, NI_ObjectToOptionalInputArray,
+                    &mask, &niter, NI_ObjectToLongSequence, &origins, &invert,
+                    &cobj))
+        goto exit;
+
+    if (PyCObject_Check(cobj)) {
+        NI_CoordinateList *cobj_data = PyCObject_AsVoidPtr(cobj);
+        if (!NI_BinaryErosion2(array, strct, mask, niter, origins, invert,
+                                                     &cobj_data))
+            goto exit;
+    } else {
+        PyErr_SetString(PyExc_RuntimeError, "cannot convert CObject");
+        goto exit;
+    }
+exit:
+    Py_XDECREF(array);
+    Py_XDECREF(strct);
+    Py_XDECREF(mask);
+    if (origins) free(origins);
+    return PyErr_Occurred() ? NULL : Py_BuildValue("");
+}
+
+static PyMethodDef methods[] = {
+    {"correlate1d",           (PyCFunction)Py_Correlate1D,
+     METH_VARARGS, NULL},
+    {"correlate",             (PyCFunction)Py_Correlate,
+     METH_VARARGS, NULL},
+    {"uniform_filter1d",      (PyCFunction)Py_UniformFilter1D,
+     METH_VARARGS, NULL},
+    {"min_or_max_filter1d",   (PyCFunction)Py_MinOrMaxFilter1D,
+        METH_VARARGS, NULL},
+    {"min_or_max_filter",     (PyCFunction)Py_MinOrMaxFilter,
+        METH_VARARGS, NULL},
+    {"rank_filter",           (PyCFunction)Py_RankFilter,
+     METH_VARARGS, NULL},
+    {"generic_filter",        (PyCFunction)Py_GenericFilter,
+     METH_VARARGS, NULL},
+    {"generic_filter1d",      (PyCFunction)Py_GenericFilter1D,
+     METH_VARARGS, NULL},
+    {"fourier_filter",        (PyCFunction)Py_FourierFilter,
+     METH_VARARGS, NULL},
+    {"fourier_shift",         (PyCFunction)Py_FourierShift,
+     METH_VARARGS, NULL},
+    {"spline_filter1d",       (PyCFunction)Py_SplineFilter1D,
+     METH_VARARGS, NULL},
+    {"geometric_transform",   (PyCFunction)Py_GeometricTransform,
+        METH_VARARGS, NULL},
+    {"zoom_shift",            (PyCFunction)Py_ZoomShift,
+     METH_VARARGS, NULL},
+    {"label",                 (PyCFunction)Py_Label,
+     METH_VARARGS, NULL},
+    {"find_objects",          (PyCFunction)Py_FindObjects,
+     METH_VARARGS, NULL},
+    {"watershed_ift",         (PyCFunction)Py_WatershedIFT,
+     METH_VARARGS, NULL},
+    {"statistics",            (PyCFunction)Py_Statistics,
+     METH_VARARGS, NULL},
+    {"center_of_mass",        (PyCFunction)Py_CenterOfMass,
+     METH_VARARGS, NULL},
+    {"histogram",             (PyCFunction)Py_Histogram,
+     METH_VARARGS, NULL},
+    {"distance_transform_bf", (PyCFunction)Py_DistanceTransformBruteForce,
+     METH_VARARGS, NULL},
+    {"distance_transform_op", (PyCFunction)Py_DistanceTransformOnePass,
+     METH_VARARGS, NULL},
+    {"euclidean_feature_transform",
+     (PyCFunction)Py_EuclideanFeatureTransform, 
+     METH_VARARGS, NULL},
+    {"binary_erosion",        (PyCFunction)Py_BinaryErosion,
+     METH_VARARGS, NULL},
+    {"binary_erosion2",       (PyCFunction)Py_BinaryErosion2,
+     METH_VARARGS, NULL},
+    {NULL, NULL, 0, NULL}
+};
+
+PyMODINIT_FUNC init_nd_image(void)
+{
+    Py_InitModule("_nd_image", methods);
+    import_array();
+}

Modified: trunk/scipy/ndimage/src/nd_image.h
===================================================================
--- trunk/scipy/ndimage/src/nd_image.h	2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/nd_image.h	2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,278 +1,278 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ND_IMAGE_H
-#define ND_IMAGE_H
-
-#include "Python.h"
-
-#ifndef ND_IMPORT_ARRAY
-#define NO_IMPORT_ARRAY
-#endif
-
-#include <numpy/noprefix.h>
-#undef NO_IMPORT_ARRAY
-
-/* Eventually get rid of everything below this line */
-
-typedef enum
-{
-         tAny=-1,
-         tBool=PyArray_BOOL,
-         tInt8=PyArray_INT8,
-         tUInt8=PyArray_UINT8,
-         tInt16=PyArray_INT16,
-         tUInt16=PyArray_UINT16,
-         tInt32=PyArray_INT32,
-         tUInt32=PyArray_UINT32,
-         tInt64=PyArray_INT64,
-         tUInt64=PyArray_UINT64,
-         tFloat32=PyArray_FLOAT32,
-         tFloat64=PyArray_FLOAT64,
-         tComplex64=PyArray_COMPLEX64,
-         tComplex128=PyArray_COMPLEX128,
-         tObject=PyArray_OBJECT,        /* placeholder... does nothing */
-         tMaxType=PyArray_NTYPES,
-         tDefault=PyArray_FLOAT64,
-         tLong=PyArray_LONG,
-} NumarrayType;
-
-#define NI_MAXDIM NPY_MAXDIMS
-
-typedef npy_intp maybelong;
-#define MAXDIM NPY_MAXDIMS
-
-#define HAS_UINT64 1
-
-
-
-#ifdef ND_IMPORT_ARRAY
-
-/* Numarray Helper Functions */
-
-static PyArrayObject*
-NA_InputArray(PyObject *a, NumarrayType t, int requires)
-{
-        PyArray_Descr *descr;
-        if (t == tAny) descr = NULL;
-        else descr = PyArray_DescrFromType(t);
-        return (PyArrayObject *)                                            \
-                PyArray_CheckFromAny(a, descr, 0, 0, requires, NULL);
-}
-
-/* satisfies ensures that 'a' meets a set of requirements and matches
-the specified type.
-*/
-static int
-satisfies(PyArrayObject *a, int requirements, NumarrayType t)
-{
-        int type_ok = (a->descr->type_num == t) || (t == tAny);
-
-        if (PyArray_ISCARRAY(a))
-                return type_ok;
-        if (PyArray_ISBYTESWAPPED(a) && (requirements & NPY_NOTSWAPPED))
-                return 0;
-        if (!PyArray_ISALIGNED(a) && (requirements & NPY_ALIGNED))
-                return 0;
-        if (!PyArray_ISCONTIGUOUS(a) && (requirements & NPY_CONTIGUOUS))
-                return 0;
-        if (!PyArray_ISWRITEABLE(a) && (requirements & NPY_WRITEABLE))
-                return 0;
-        if (requirements & NPY_ENSURECOPY)
-                return 0;
-        return type_ok;
-}
-
-static PyArrayObject *
-NA_OutputArray(PyObject *a, NumarrayType t, int requires)
-{
-        PyArray_Descr *dtype;
-        PyArrayObject *ret;
-
-        if (!PyArray_Check(a) || !PyArray_ISWRITEABLE(a)) {
-                PyErr_Format(PyExc_TypeError,
-                                         "NA_OutputArray: only writeable arrays work for output.");
-                return NULL;
-        }
-
-        if (satisfies((PyArrayObject *)a, requires, t)) {
-                Py_INCREF(a);
-                return (PyArrayObject *)a;
-        }
-        if (t == tAny) {
-                dtype = PyArray_DESCR(a);
-                Py_INCREF(dtype);
-        }
-        else {
-                dtype = PyArray_DescrFromType(t);
-        }
-        ret = (PyArrayObject *)PyArray_Empty(PyArray_NDIM(a), PyArray_DIMS(a),
-                                                                                 dtype, 0);
-        ret->flags |= NPY_UPDATEIFCOPY;
-        ret->base = a;
-        PyArray_FLAGS(a) &= ~NPY_WRITEABLE;
-        Py_INCREF(a);
-        return ret;
-}
-
-/* NA_IoArray is a combination of NA_InputArray and NA_OutputArray.
-
-Unlike NA_OutputArray, if a temporary is required it is initialized to a copy
-of the input array.
-
-Unlike NA_InputArray, deallocating any resulting temporary array results in a
-copy from the temporary back to the original.
-*/
-static PyArrayObject *
-NA_IoArray(PyObject *a, NumarrayType t, int requires)
-{
-        PyArrayObject *shadow = NA_InputArray(a, t, requires | NPY_UPDATEIFCOPY );
-
-        if (!shadow) return NULL;
-
-        /* Guard against non-writable, but otherwise satisfying requires.
-             In this case,  shadow == a.
-        */
-        if (!PyArray_ISWRITEABLE(shadow)) {
-                PyErr_Format(PyExc_TypeError,
-                                         "NA_IoArray: I/O array must be writable array");
-                PyArray_XDECREF_ERR(shadow);
-                return NULL;
-        }
-
-        return shadow;
-}
-
-#define NUM_LITTLE_ENDIAN 0
-#define NUM_BIG_ENDIAN 1
-
-static int
-NA_ByteOrder(void)
-{
-        unsigned long byteorder_test;
-        byteorder_test = 1;
-        if (*((char *) &byteorder_test))
-                return NUM_LITTLE_ENDIAN;
-        else
-                return NUM_BIG_ENDIAN;
-}
-
-/* ignores bytestride */
-static PyArrayObject *
-NA_NewAllFromBuffer(int ndim, maybelong *shape, NumarrayType type,
-                                        PyObject *bufferObject, maybelong byteoffset, maybelong bytestride,
-                                        int byteorder, int aligned, int writeable)
-{
-        PyArrayObject *self = NULL;
-        PyArray_Descr *dtype;
-
-        if (type == tAny)
-                type = tDefault;
-
-        dtype = PyArray_DescrFromType(type);
-        if (dtype == NULL) return NULL;
-
-        if (byteorder != NA_ByteOrder()) {
-                PyArray_Descr *temp;
-                temp = PyArray_DescrNewByteorder(dtype, PyArray_SWAP);
-                Py_DECREF(dtype);
-                if (temp == NULL) return NULL;
-                dtype = temp;
-        }
-
-        if (bufferObject == Py_None || bufferObject == NULL) {
-                self = (PyArrayObject *)                                        \
-                        PyArray_NewFromDescr(&PyArray_Type, dtype,
-                                                                 ndim, shape, NULL, NULL,
-                                                                 0, NULL);
-        }
-        else {
-                npy_intp size = 1;
-                int i;
-                PyArrayObject *newself;
-                PyArray_Dims newdims;
-                for(i=0; i<ndim; i++) {
-                        size *= shape[i];
-                }
-                self = (PyArrayObject *)                                \
-                        PyArray_FromBuffer(bufferObject, dtype,
-                                                             size, byteoffset);
-                if (self == NULL) return self;
-                newdims.len = ndim;
-                newdims.ptr = shape;
-                newself = (PyArrayObject *)                                     \
-                        PyArray_Newshape(self, &newdims, PyArray_CORDER);
-                Py_DECREF(self);
-                self = newself;
-        }
-
-        return self;
-}
-
-static PyArrayObject *
-NA_NewAll(int ndim, maybelong *shape, NumarrayType type,
-                    void *buffer, maybelong byteoffset, maybelong bytestride,
-                    int byteorder, int aligned, int writeable)
-{
-        PyArrayObject *result = NA_NewAllFromBuffer(
-                                                                                                ndim, shape, type, Py_None,
-                                                                                                byteoffset, bytestride,
-                                                                                                byteorder, aligned, writeable);
-        if (result) {
-                if (!PyArray_Check((PyObject *) result)) {
-                        PyErr_Format( PyExc_TypeError,
-                                                    "NA_NewAll: non-NumArray result");
-                        result = NULL;
-                } else {
-                        if (buffer) {
-                                memcpy(result->data, buffer, PyArray_NBYTES(result));
-                        } else {
-                                memset(result->data, 0, PyArray_NBYTES(result));
-                        }
-                }
-        }
-        return  result;
-}
-
-/* Create a new numarray which is initially a C_array, or which
-references a C_array: aligned, !byteswapped, contiguous, ...
-Call with buffer==NULL to allocate storage.
-*/
-static PyArrayObject *
-NA_NewArray(void *buffer, NumarrayType type, int ndim, maybelong *shape)
-{
-        return (PyArrayObject *) NA_NewAll(ndim, shape, type, buffer, 0, 0,
-                                                                             NA_ByteOrder(), 1, 1);
-}
-
-#endif /* ND_IMPORT_ARRAY */
-
-#endif /* ND_IMAGE_H */
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials provided
+ *    with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ND_IMAGE_H
+#define ND_IMAGE_H
+
+#include "Python.h"
+
+#ifndef ND_IMPORT_ARRAY
+#define NO_IMPORT_ARRAY
+#endif
+
+#include <numpy/noprefix.h>
+#undef NO_IMPORT_ARRAY
+
+/* Eventually get rid of everything below this line */
+
+typedef enum
+{
+         tAny=-1,
+         tBool=PyArray_BOOL,
+         tInt8=PyArray_INT8,
+         tUInt8=PyArray_UINT8,
+         tInt16=PyArray_INT16,
+         tUInt16=PyArray_UINT16,
+         tInt32=PyArray_INT32,
+         tUInt32=PyArray_UINT32,
+         tInt64=PyArray_INT64,
+         tUInt64=PyArray_UINT64,
+         tFloat32=PyArray_FLOAT32,
+         tFloat64=PyArray_FLOAT64,
+         tComplex64=PyArray_COMPLEX64,
+         tComplex128=PyArray_COMPLEX128,
+         tObject=PyArray_OBJECT,        /* placeholder... does nothing */
+         tMaxType=PyArray_NTYPES,
+         tDefault=PyArray_FLOAT64,
+         tLong=PyArray_LONG,
+} NumarrayType;
+
+#define NI_MAXDIM NPY_MAXDIMS
+
+typedef npy_intp maybelong;
+#define MAXDIM NPY_MAXDIMS
+
+#define HAS_UINT64 1
+
+
+
+#ifdef ND_IMPORT_ARRAY
+
+/* Numarray Helper Functions */
+
+static PyArrayObject*
+NA_InputArray(PyObject *a, NumarrayType t, int requires)
+{
+        PyArray_Descr *descr;
+        if (t == tAny) descr = NULL;
+        else descr = PyArray_DescrFromType(t);
+        return (PyArrayObject *)                                            \
+                PyArray_CheckFromAny(a, descr, 0, 0, requires, NULL);
+}
+
+/* satisfies ensures that 'a' meets a set of requirements and matches
+the specified type.
+*/
+static int
+satisfies(PyArrayObject *a, int requirements, NumarrayType t)
+{
+        int type_ok = (a->descr->type_num == t) || (t == tAny);
+
+        if (PyArray_ISCARRAY(a))
+                return type_ok;
+        if (PyArray_ISBYTESWAPPED(a) && (requirements & NPY_NOTSWAPPED))
+                return 0;
+        if (!PyArray_ISALIGNED(a) && (requirements & NPY_ALIGNED))
+                return 0;
+        if (!PyArray_ISCONTIGUOUS(a) && (requirements & NPY_CONTIGUOUS))
+                return 0;
+        if (!PyArray_ISWRITEABLE(a) && (requirements & NPY_WRITEABLE))
+                return 0;
+        if (requirements & NPY_ENSURECOPY)
+                return 0;
+        return type_ok;
+}
+
+static PyArrayObject *
+NA_OutputArray(PyObject *a, NumarrayType t, int requires)
+{
+        PyArray_Descr *dtype;
+        PyArrayObject *ret;
+
+        if (!PyArray_Check(a) || !PyArray_ISWRITEABLE(a)) {
+                PyErr_Format(PyExc_TypeError,
+                                         "NA_OutputArray: only writeable arrays work for output.");
+                return NULL;
+        }
+
+        if (satisfies((PyArrayObject *)a, requires, t)) {
+                Py_INCREF(a);
+                return (PyArrayObject *)a;
+        }
+        if (t == tAny) {
+                dtype = PyArray_DESCR(a);
+                Py_INCREF(dtype);
+        }
+        else {
+                dtype = PyArray_DescrFromType(t);
+        }
+        ret = (PyArrayObject *)PyArray_Empty(PyArray_NDIM(a), PyArray_DIMS(a),
+                                                                                 dtype, 0);
+        ret->flags |= NPY_UPDATEIFCOPY;
+        ret->base = a;
+        PyArray_FLAGS(a) &= ~NPY_WRITEABLE;
+        Py_INCREF(a);
+        return ret;
+}
+
+/* NA_IoArray is a combination of NA_InputArray and NA_OutputArray.
+
+Unlike NA_OutputArray, if a temporary is required it is initialized to a copy
+of the input array.
+
+Unlike NA_InputArray, deallocating any resulting temporary array results in a
+copy from the temporary back to the original.
+*/
+static PyArrayObject *
+NA_IoArray(PyObject *a, NumarrayType t, int requires)
+{
+        PyArrayObject *shadow = NA_InputArray(a, t, requires | NPY_UPDATEIFCOPY );
+
+        if (!shadow) return NULL;
+
+        /* Guard against non-writable, but otherwise satisfying requires.
+             In this case,  shadow == a.
+        */
+        if (!PyArray_ISWRITEABLE(shadow)) {
+                PyErr_Format(PyExc_TypeError,
+                                         "NA_IoArray: I/O array must be writable array");
+                PyArray_XDECREF_ERR(shadow);
+                return NULL;
+        }
+
+        return shadow;
+}
+
+#define NUM_LITTLE_ENDIAN 0
+#define NUM_BIG_ENDIAN 1
+
+static int
+NA_ByteOrder(void)
+{
+        unsigned long byteorder_test;
+        byteorder_test = 1;
+        if (*((char *) &byteorder_test))
+                return NUM_LITTLE_ENDIAN;
+        else
+                return NUM_BIG_ENDIAN;
+}
+
+/* ignores bytestride */
+static PyArrayObject *
+NA_NewAllFromBuffer(int ndim, maybelong *shape, NumarrayType type,
+                                        PyObject *bufferObject, maybelong byteoffset, maybelong bytestride,
+                                        int byteorder, int aligned, int writeable)
+{
+        PyArrayObject *self = NULL;
+        PyArray_Descr *dtype;
+
+        if (type == tAny)
+                type = tDefault;
+
+        dtype = PyArray_DescrFromType(type);
+        if (dtype == NULL) return NULL;
+
+        if (byteorder != NA_ByteOrder()) {
+                PyArray_Descr *temp;
+                temp = PyArray_DescrNewByteorder(dtype, PyArray_SWAP);
+                Py_DECREF(dtype);
+                if (temp == NULL) return NULL;
+                dtype = temp;
+        }
+
+        if (bufferObject == Py_None || bufferObject == NULL) {
+                self = (PyArrayObject *)                                        \
+                        PyArray_NewFromDescr(&PyArray_Type, dtype,
+                                                                 ndim, shape, NULL, NULL,
+                                                                 0, NULL);
+        }
+        else {
+                npy_intp size = 1;
+                int i;
+                PyArrayObject *newself;
+                PyArray_Dims newdims;
+                for(i=0; i<ndim; i++) {
+                        size *= shape[i];
+                }
+                self = (PyArrayObject *)                                \
+                        PyArray_FromBuffer(bufferObject, dtype,
+                                                             size, byteoffset);
+                if (self == NULL) return self;
+                newdims.len = ndim;
+                newdims.ptr = shape;
+                newself = (PyArrayObject *)                                     \
+                        PyArray_Newshape(self, &newdims, PyArray_CORDER);
+                Py_DECREF(self);
+                self = newself;
+        }
+
+        return self;
+}
+
+static PyArrayObject *
+NA_NewAll(int ndim, maybelong *shape, NumarrayType type,
+                    void *buffer, maybelong byteoffset, maybelong bytestride,
+                    int byteorder, int aligned, int writeable)
+{
+        PyArrayObject *result = NA_NewAllFromBuffer(
+                                                                                                ndim, shape, type, Py_None,
+                                                                                                byteoffset, bytestride,
+                                                                                                byteorder, aligned, writeable);
+        if (result) {
+                if (!PyArray_Check((PyObject *) result)) {
+                        PyErr_Format( PyExc_TypeError,
+                                                    "NA_NewAll: non-NumArray result");
+                        result = NULL;
+                } else {
+                        if (buffer) {
+                                memcpy(result->data, buffer, PyArray_NBYTES(result));
+                        } else {
+                                memset(result->data, 0, PyArray_NBYTES(result));
+                        }
+                }
+        }
+        return  result;
+}
+
+/* Create a new numarray which is initially a C_array, or which
+references a C_array: aligned, !byteswapped, contiguous, ...
+Call with buffer==NULL to allocate storage.
+*/
+static PyArrayObject *
+NA_NewArray(void *buffer, NumarrayType type, int ndim, maybelong *shape)
+{
+        return (PyArrayObject *) NA_NewAll(ndim, shape, type, buffer, 0, 0,
+                                                                             NA_ByteOrder(), 1, 1);
+}
+
+#endif /* ND_IMPORT_ARRAY */
+
+#endif /* ND_IMAGE_H */

Modified: trunk/scipy/ndimage/src/ni_filters.c
===================================================================
--- trunk/scipy/ndimage/src/ni_filters.c	2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/ni_filters.c	2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,888 +1,888 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials provided
- *    with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- *    products derived from this software without specific prior
- *    written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ni_support.h"
-#include "ni_filters.h"
-#include <stdlib.h>
-#include <math.h>
-
-#define BUFFER_SIZE 256000
-
-int NI_Correlate1D(PyArrayObject *input, PyArrayObject *weights,
-                                     int axis, PyArrayObject *output, NI_ExtendMode mode,
-                                     double cval, maybelong origin)
-{
-    int symmetric = 0, ii, jj, more;
-    maybelong ll, lines, length, size1, size2, filter_size;
-    double *ibuffer = NULL, *obuffer = NULL;
-    Float64 *fw;
-    NI_LineBuffer iline_buffer, oline_buffer;
-
-    /* test for symmetry or anti-symmetry: */
-    filter_size = weights->dimensions[0];
-    size1 = filter_size / 2;
-    size2 = filter_size - size1 - 1;
-    fw = (void *)PyArray_DATA(weights);
-    if (filter_size & 0x1) {
-        symmetric = 1;
-        for(ii = 1; ii <= filter_size / 2; ii++) {
-            if (fabs(fw[ii + size1] - fw[size1 - ii]) > DBL_EPSILON) {
-                symmetric = 0;
-                break;
-            }
-        }
-        if (symmetric == 0) {
-            symmetric = -1;
-            for(ii = 1; ii <= filter_size / 2; ii++) {
-                if (fabs(fw[size1 + ii] + fw[size1 - ii]) > DBL_EPSILON) {
-                    symmetric = 0;
-                    break;
-                }
-            }
-        }
-    }
-    /* allocate and initialize the line buffers: */
-    lines = -1;
-    if (!NI_AllocateLineBuffer(input, axis, size1 + origin, size2 - origin,
-                                                         &lines, BUFFER_SIZE, &ibuffer))
-        goto exit;
-    if (!NI_AllocateLineBuffer(output, axis, 0, 0, &lines, BUFFER_SIZE,
-                                                         &obuffer))
-        goto exit;
-    if (!NI_InitLineBuffer(input, axis, size1 + origin, size2 - origin,
-                                                            lines, ibuffer, mode, cval, &iline_buffer))
-        goto exit;
-    if (!NI_InitLineBuffer(output, axis, 0, 0, lines, obuffer, mode, 0.0,
-                                                 &oline_buffer))
-        goto exit;
-    length = input->nd > 0 ? input->dimensions[axis] : 1;
-    fw += size1;
-    /* iterate over all the array lines: */
-    do {
-        /* copy lines from array to buffer: */
-        if (!NI_ArrayToLineBuffer(&iline_buffer, &lines, &more))
-            goto exit;
-        /* iterate over the lines in the buffers: */
-        for(ii = 0; ii < lines; ii++) {
-            /* get lines: */
-            double *iline = NI_GET_LINE(iline_buffer, ii) + size1;
-            double *oline = NI_GET_LINE(oline_buffer, ii);
-            /* the correlation calculation: */
-            if (symmetric > 0) {
-                for(ll = 0; ll < length; ll++) {
-                    oline[ll] = iline[0] * fw[0];
-                    for(jj = -size1 ; jj < 0; jj++)
-                        oline[ll] += (iline[jj] + iline[-jj]) * fw[jj];
-                    ++iline;
-                }
-            } else if (symmetric < 0) {
-                for(ll = 0; ll < length; ll++) {
-                    oline[ll] = iline[0] * fw[0];
-                    for(jj = -size1 ; jj < 0; jj++)
-                        oline[ll] += (iline[jj] - iline[-jj]) * fw[jj];
-                    ++iline;
-                }
-            } else {
-                for(ll = 0; ll < length; ll++) {
-                    oline[ll] = iline[size2] * fw[size2];
-                    for(jj = -size1; jj < size2; jj++)
-                        oline[ll] += iline[jj] * fw[jj];
-                    ++iline;
-                }
-            }
-        }
-        /* copy lines from buffer to array: */
-        if (!NI_LineBufferToArray(&oline_buffer))
-            goto exit;
-    } while(more);
-exit:
-    if (ibuffer) free(ibuffer);
-    if (obuffer) free(obuffer);
-    return PyErr_Occurred() ? 0 : 1;
-}
-
-#define CASE_CORRELATE_POINT(_pi, _weights, _offsets, _filter_size, \
-                                                         _cvalue, _type, _res, _mv)             \
-case t ## _type:                                                    \
-{                                                                   \
-    maybelong _ii, _offset;                                           \
-    for(_ii = 0; _ii < _filter_size; _ii++) {                         \
-        _offset = _offsets[_ii];                                        \
-        if (_offset == _mv)                                             \
-            _res += _weights[_ii] * _cvalue;                              \
-        else                                                            \
-            _res += _weights[_ii] * (double)*(_type*)(_pi + _offset);     \
-    }                                                                 \
-}                                                                   \
-break
-
-#define CASE_FILTER_OUT(_po, _tmp, _type) \
-case t ## _type:                          \
-    *(_type*)_po = (_type)_tmp;             \
-    break
-
-int NI_Correlate(PyArrayObject* input, PyArrayObject* weights,
-                                                PyArrayObject* output, NI_ExtendMode mode,
-                                                double cvalue, maybelong *origins)
-{
-    Bool *pf = NULL;
-    maybelong fsize, jj, kk, filter_size = 0, border_flag_value;
-    maybelong *offsets = NULL, *oo, size;
-    NI_FilterIterator fi;
-    NI_Iterator ii, io;
-    char *pi, *po;
-    Float64 *pw;
-    Float64 *ww = NULL;
-    int ll;
-
-    /* get the the footprint: */
-    fsize = 1;
-    for(ll = 0; ll < weights->nd; ll++)
-        fsize *= weights->dimensions[ll];
-    pw = (Float64*)PyArray_DATA(weights);
-    pf = (Bool*)malloc(fsize * sizeof(Bool));
-    if (!pf) {
-        PyErr_NoMemory();
-        goto exit;
-    }
-    for(jj = 0; jj < fsize; jj++) {
-        if (fabs(pw[jj]) > DBL_EPSILON) {
-            pf[jj] = 1;
-            ++filter_size;
-        } else {
-            pf[jj] = 0;
-        }
-    }
-    /* copy the weights to contiguous memory: */
-    ww = (Float64*)malloc(filter_size * sizeof(Float64));
-    if (!ww) {
-        PyErr_NoMemory();
-        goto exit;
-    }
-    jj = 0;
-    for(kk = 0; kk < fsize; kk++) {
-        if (pf[kk]) {
-            ww[jj++] = pw[kk];
-        }
-    }
-    /* initialize filter offsets: */
-    if (!NI_InitFilterOffsets(input, pf, weights->dimensions, origins,
-                                                        mode, &offsets, &border_flag_value, NULL))
-        goto exit;
-    /* initialize filter iterator: */
-    if (!NI_InitFilterIterator(input->nd, weights->dimensions, filter_size,
-                                                         input->dimensions, origins, &fi))
-        goto exit;
-    /* initialize input element iterator: */
-    if (!NI_InitPointIterator(input, &ii))
-        goto exit;
-    /* initialize output element iterator: */
-    if (!NI_InitPointIterator(output, &io))
-        goto ex