[Scipy-svn] r4601 - in branches/Interpolate1D: . ndimage ndimage/register ndimage/segment tests

scipy-svn at scipy.org scipy-svn at scipy.org
Tue Aug 5 15:07:54 EDT 2008


Author: fcady
Date: 2008-08-05 14:07:52 -0500 (Tue, 05 Aug 2008)
New Revision: 4601

Added:
   branches/Interpolate1D/ndimage/
   branches/Interpolate1D/ndimage/nd_image.c
   branches/Interpolate1D/ndimage/nd_image.h
   branches/Interpolate1D/ndimage/ni_filters.c
   branches/Interpolate1D/ndimage/ni_filters.h
   branches/Interpolate1D/ndimage/ni_fourier.c
   branches/Interpolate1D/ndimage/ni_fourier.h
   branches/Interpolate1D/ndimage/ni_interpolation.c
   branches/Interpolate1D/ndimage/ni_interpolation.h
   branches/Interpolate1D/ndimage/ni_measure.c
   branches/Interpolate1D/ndimage/ni_measure.h
   branches/Interpolate1D/ndimage/ni_morphology.c
   branches/Interpolate1D/ndimage/ni_morphology.h
   branches/Interpolate1D/ndimage/ni_support.c
   branches/Interpolate1D/ndimage/ni_support.h
   branches/Interpolate1D/ndimage/register/
   branches/Interpolate1D/ndimage/register/Register_EXT.c
   branches/Interpolate1D/ndimage/register/Register_IMPL.c
   branches/Interpolate1D/ndimage/segment/
   branches/Interpolate1D/ndimage/segment/Segmenter_EXT.c
   branches/Interpolate1D/ndimage/segment/Segmenter_IMPL.c
   branches/Interpolate1D/ndimage/segment/ndImage_Segmenter_structs.h
   branches/Interpolate1D/ndimage_wrapper.py
   branches/Interpolate1D/tests/test_ndimage.py
Modified:
   branches/Interpolate1D/setup.py
Log:
more ND work, including unit tests.  They're all failing right now, though, so I need to work on that.

Added: branches/Interpolate1D/ndimage/nd_image.c
===================================================================
--- branches/Interpolate1D/ndimage/nd_image.c	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/nd_image.c	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +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();
+}

Added: branches/Interpolate1D/ndimage/nd_image.h
===================================================================
--- branches/Interpolate1D/ndimage/nd_image.h	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/nd_image.h	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +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 */

Added: branches/Interpolate1D/ndimage/ni_filters.c
===================================================================
--- branches/Interpolate1D/ndimage/ni_filters.c	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/ni_filters.c	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +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 exit;
+    /* get data pointers an array size: */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* iterator over the elements: */
+    oo = offsets;
+    for(jj = 0; jj < size; jj++) {
+        double tmp = 0.0;
+        switch (input->descr->type_num) {
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Bool,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, UInt8,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, UInt16,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, UInt32,
+                                                     tmp, border_flag_value);
+#if HAS_UINT64
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, UInt64,
+                                                     tmp, border_flag_value);
+#endif
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Int8,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Int16,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Int32,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Int64,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Float32,
+                                                     tmp, border_flag_value);
+            CASE_CORRELATE_POINT(pi, ww, oo, filter_size, cvalue, Float64,
+                                                     tmp, border_flag_value);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        switch (output->descr->type_num) {
+            CASE_FILTER_OUT(po, tmp, Bool);
+            CASE_FILTER_OUT(po, tmp, UInt8);
+            CASE_FILTER_OUT(po, tmp, UInt16);
+            CASE_FILTER_OUT(po, tmp, UInt32);
+#if HAS_UINT64
+            CASE_FILTER_OUT(po, tmp, UInt64);
+#endif
+            CASE_FILTER_OUT(po, tmp, Int8);
+            CASE_FILTER_OUT(po, tmp, Int16);
+            CASE_FILTER_OUT(po, tmp, Int32);
+            CASE_FILTER_OUT(po, tmp, Int64);
+            CASE_FILTER_OUT(po, tmp, Float32);
+            CASE_FILTER_OUT(po, tmp, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
+    }
+exit:
+    if (offsets) free(offsets);
+    if (ww) free(ww);
+    if (pf) free(pf);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+int
+NI_UniformFilter1D(PyArrayObject *input, long filter_size,
+                                     int axis, PyArrayObject *output, NI_ExtendMode mode,
+                                     double cval, long origin)
+{
+    maybelong lines, kk, ll, length, size1, size2;
+    int more;
+    double *ibuffer = NULL, *obuffer = NULL;
+    NI_LineBuffer iline_buffer, oline_buffer;
+
+    size1 = filter_size / 2;
+    size2 = filter_size - size1 - 1;
+    /* 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;
+
+    /* 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(kk = 0; kk < lines; kk++) {
+            /* get lines: */
+            double *iline = NI_GET_LINE(iline_buffer, kk);
+            double *oline = NI_GET_LINE(oline_buffer, kk);
+            /* do the uniform filter: */
+            double tmp = 0.0;
+            double *l1 = iline;
+            double *l2 = iline + filter_size;
+            for(ll = 0; ll < filter_size; ll++)
+                tmp += iline[ll];
+            tmp /= (double)filter_size;
+            oline[0] = tmp;
+            for(ll = 1; ll < length; ll++) {
+                tmp += (*l2++ - *l1++) / (double)filter_size;
+                oline[ll] = tmp;
+            }
+        }
+        /* 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;
+}
+
+int
+NI_MinOrMaxFilter1D(PyArrayObject *input, long filter_size,
+                                        int axis, PyArrayObject *output, NI_ExtendMode mode,
+                                        double cval, long origin, int minimum)
+{
+    maybelong lines, kk, jj, ll, length, size1, size2;
+    int more;
+    double *ibuffer = NULL, *obuffer = NULL;
+    NI_LineBuffer iline_buffer, oline_buffer;
+
+    size1 = filter_size / 2;
+    size2 = filter_size - size1 - 1;
+    /* 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;
+
+    /* 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(kk = 0; kk < lines; kk++) {
+            /* get lines: */
+            double *iline = NI_GET_LINE(iline_buffer, kk) + size1;
+            double *oline = NI_GET_LINE(oline_buffer, kk);
+            for(ll = 0; ll < length; ll++) {
+            /* find minimum or maximum filter: */
+                double val = iline[ll - size1];
+                for(jj = -size1 + 1; jj <= size2; jj++) {
+                    double tmp = iline[ll + jj];
+                    if (minimum) {
+                        if (tmp < val)
+                            val = tmp;
+                    } else {
+                        if (tmp > val)
+                            val = tmp;
+                    }
+                }
+                oline[ll] = val;
+            }
+        }
+        /* 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_MIN_OR_MAX_POINT(_pi, _offsets, _filter_size, _cval, \
+                                                            _type, _minimum, _res, _mv, _ss)    \
+case t ## _type:                                                  \
+{                                                                 \
+    maybelong _ii, _oo = *_offsets;                                 \
+    _type _cv = (_type)_cval, _tmp;                                 \
+    _res = _oo == _mv ? _cv : *(_type*)(_pi + _oo);                 \
+    if (_ss)                                                        \
+        _res += *_ss;                                                 \
+    for(_ii = 1; _ii < _filter_size; _ii++) {                       \
+        _oo = _offsets[_ii];                                          \
+        _tmp = _oo == _mv ? _cv : *(_type*)(_pi + _oo);               \
+        if (_ss)                                                      \
+            _tmp += _ss[_ii];                                           \
+        if (_minimum) {                                               \
+            if (_tmp < _res)                                            \
+                _res = (_type)_tmp;                                       \
+        } else {                                                      \
+            if (_tmp > _res)                                            \
+                _res = (_type)_tmp;                                       \
+        }                                                             \
+    }                                                               \
+}                                                                 \
+break
+
+int NI_MinOrMaxFilter(PyArrayObject* input, PyArrayObject* footprint,
+                PyArrayObject* structure, PyArrayObject* output,
+                NI_ExtendMode mode, double cvalue, maybelong *origins, int minimum)
+{
+    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;
+    int ll;
+    double *ss = NULL;
+    Float64 *ps;
+
+    /* get the the footprint: */
+    fsize = 1;
+    for(ll = 0; ll < footprint->nd; ll++)
+        fsize *= footprint->dimensions[ll];
+    pf = (Bool*)PyArray_DATA(footprint);
+    for(jj = 0; jj < fsize; jj++) {
+        if (pf[jj]) {
+            ++filter_size;
+        }
+    }
+    /* get the structure: */
+    if (structure) {
+        ss = (double*)malloc(filter_size * sizeof(double));
+        if (!ss) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+        /* copy the weights to contiguous memory: */
+        ps = (Float64*)PyArray_DATA(structure);
+        jj = 0;
+        for(kk = 0; kk < fsize; kk++)
+            if (pf[kk])
+                ss[jj++] = minimum ? -ps[kk] : ps[kk];
+    }
+    /* initialize filter offsets: */
+    if (!NI_InitFilterOffsets(input, pf, footprint->dimensions, origins,
+                                                        mode, &offsets, &border_flag_value, NULL))
+        goto exit;
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(input->nd, footprint->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 exit;
+    /* get data pointers an array size: */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* iterator over the elements: */
+    oo = offsets;
+    for(jj = 0; jj < size; jj++) {
+        double tmp = 0.0;
+        switch (input->descr->type_num) {
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Bool,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, UInt8,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, UInt16,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, UInt32,
+                                                        minimum, tmp, border_flag_value, ss);
+#if HAS_UINT64
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, UInt64,
+                                                        minimum, tmp, border_flag_value, ss);
+#endif
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Int8,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Int16,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Int32,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Int64,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Float32,
+                                                        minimum, tmp, border_flag_value, ss);
+            CASE_MIN_OR_MAX_POINT(pi, oo, filter_size, cvalue, Float64,
+                                                        minimum, tmp, border_flag_value, ss);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        switch (output->descr->type_num) {
+            CASE_FILTER_OUT(po, tmp, Bool);
+            CASE_FILTER_OUT(po, tmp, UInt8);
+            CASE_FILTER_OUT(po, tmp, UInt16);
+            CASE_FILTER_OUT(po, tmp, UInt32);
+#if HAS_UINT64
+            CASE_FILTER_OUT(po, tmp, UInt64);
+#endif
+            CASE_FILTER_OUT(po, tmp, Int8);
+            CASE_FILTER_OUT(po, tmp, Int16);
+            CASE_FILTER_OUT(po, tmp, Int32);
+            CASE_FILTER_OUT(po, tmp, Int64);
+            CASE_FILTER_OUT(po, tmp, Float32);
+            CASE_FILTER_OUT(po, tmp, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
+    }
+exit:
+    if (offsets) free(offsets);
+    if (ss) free(ss);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+static double NI_Select(double *buffer, int min, int max, int rank)
+{
+    int ii, jj;
+    double x, t;
+
+    if (min == max)
+        return buffer[min];
+
+    x = buffer[min];
+    ii = min - 1;
+    jj = max + 1;
+    for(;;) {
+        do
+            jj--;
+        while(buffer[jj] > x);
+        do
+            ii++;
+        while(buffer[ii] < x);
+        if (ii < jj) {
+            t = buffer[ii];
+            buffer[ii] = buffer[jj];
+            buffer[jj] = t;
+        } else {
+            break;
+        }
+    }
+
+    ii = jj - min + 1;
+    if (rank < ii)
+        return NI_Select(buffer, min, jj, rank);
+    else
+        return NI_Select(buffer, jj + 1, max, rank - ii);
+}
+
+#define CASE_RANK_POINT(_pi, _offsets, _filter_size, _cval, _type, \
+                                                _rank, _buffer, _res, _mv)                 \
+case t ## _type:                                                   \
+{                                                                  \
+    maybelong _ii;                                                   \
+    for(_ii = 0; _ii < _filter_size; _ii++) {                        \
+        maybelong _offset = _offsets[_ii];                             \
+        if (_offset == _mv)                                            \
+            _buffer[_ii] = (_type)_cval;                                 \
+        else                                                           \
+            _buffer[_ii] = *(_type*)(_pi + _offsets[_ii]);               \
+    }                                                                \
+    _res = (_type)NI_Select(_buffer, 0, _filter_size - 1, _rank);    \
+}                                                                  \
+break
+
+int NI_RankFilter(PyArrayObject* input, int rank,
+                                    PyArrayObject* footprint, PyArrayObject* output,
+                                    NI_ExtendMode mode, double cvalue, maybelong *origins)
+{
+    maybelong fsize, jj, filter_size = 0, border_flag_value;
+    maybelong *offsets = NULL, *oo, size;
+    NI_FilterIterator fi;
+    NI_Iterator ii, io;
+    char *pi, *po;
+    Bool *pf = NULL;
+    double *buffer = NULL;
+    int ll;
+
+    /* get the the footprint: */
+    fsize = 1;
+    for(ll = 0; ll < footprint->nd; ll++)
+        fsize *= footprint->dimensions[ll];
+    pf = (Bool*)PyArray_DATA(footprint);
+    for(jj = 0; jj < fsize; jj++) {
+        if (pf[jj]) {
+            ++filter_size;
+        }
+    }
+    /* buffer for rank calculation: */
+    buffer = (double*)malloc(filter_size * sizeof(double));
+    if (!buffer) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    /* iterator over the elements: */
+    oo = offsets;
+    /* initialize filter offsets: */
+    if (!NI_InitFilterOffsets(input, pf, footprint->dimensions, origins,
+                                                        mode, &offsets, &border_flag_value, NULL))
+        goto exit;
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(input->nd, footprint->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 exit;
+    /* get data pointers an array size: */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* iterator over the elements: */
+    oo = offsets;
+    for(jj = 0; jj < size; jj++) {
+        double tmp = 0.0;
+        switch (input->descr->type_num) {
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Bool,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, UInt8,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, UInt16,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, UInt32,
+                                            rank, buffer, tmp, border_flag_value);
+#if HAS_UINT64
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, UInt64,
+                                            rank, buffer, tmp, border_flag_value);
+#endif
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Int8,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Int16,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Int32,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Int64,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Float32,
+                                            rank, buffer, tmp, border_flag_value);
+            CASE_RANK_POINT(pi, oo, filter_size, cvalue, Float64,
+                                            rank, buffer, tmp, border_flag_value);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        switch (output->descr->type_num) {
+            CASE_FILTER_OUT(po, tmp, Bool);
+            CASE_FILTER_OUT(po, tmp, UInt8);
+            CASE_FILTER_OUT(po, tmp, UInt16);
+            CASE_FILTER_OUT(po, tmp, UInt32);
+#if HAS_UINT64
+            CASE_FILTER_OUT(po, tmp, UInt64);
+#endif
+            CASE_FILTER_OUT(po, tmp, Int8);
+            CASE_FILTER_OUT(po, tmp, Int16);
+            CASE_FILTER_OUT(po, tmp, Int32);
+            CASE_FILTER_OUT(po, tmp, Int64);
+            CASE_FILTER_OUT(po, tmp, Float32);
+            CASE_FILTER_OUT(po, tmp, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
+    }
+exit:
+    if (offsets) free(offsets);
+    if (buffer) free(buffer);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+int NI_GenericFilter1D(PyArrayObject *input,
+                int (*function)(double*, maybelong, double*, maybelong, void*),
+                void* data, long filter_size, int axis, PyArrayObject *output,
+                NI_ExtendMode mode, double cval, long origin)
+{
+    int more;
+    maybelong ii, lines, length, size1, size2;
+    double *ibuffer = NULL, *obuffer = NULL;
+    NI_LineBuffer iline_buffer, oline_buffer;
+
+    /* allocate and initialize the line buffers: */
+    size1 = filter_size / 2;
+    size2 = filter_size - size1 - 1;
+    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;
+    /* 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);
+            double *oline = NI_GET_LINE(oline_buffer, ii);
+            if (!function(iline, length + size1 + size2, oline, length, data)) {
+                if (!PyErr_Occurred())
+                    PyErr_SetString(PyExc_RuntimeError,
+                                                    "unknown error in line processing function");
+                goto exit;
+            }
+        }
+        /* 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_FILTER_POINT(_pi, _offsets, _filter_size, _cvalue, _type, \
+                                                    _res, _mv, _function, _data, _buffer)        \
+case t ## _type:                                                       \
+{                                                                      \
+    maybelong _ii, _offset;                                              \
+    for(_ii = 0; _ii < _filter_size; _ii++) {                            \
+        _offset = _offsets[_ii];                                           \
+        if (_offset == _mv)                                                \
+            _buffer[_ii] = (double)_cvalue;                                  \
+        else                                                               \
+            _buffer[_ii] = (double)*(_type*)(_pi + _offset);                 \
+    }                                                                    \
+    if (!_function(_buffer, _filter_size, &_res, _data)) {               \
+        if (!PyErr_Occurred())                                             \
+            PyErr_SetString(PyExc_RuntimeError,                              \
+                                            "unknown error in filter function");             \
+            goto exit;                                                       \
+    }                                                                    \
+}                                                                      \
+break
+
+
+int NI_GenericFilter(PyArrayObject* input,
+            int (*function)(double*, maybelong, double*, void*), void *data,
+            PyArrayObject* footprint, PyArrayObject* output,
+            NI_ExtendMode mode, double cvalue, maybelong *origins)
+{
+    Bool *pf = NULL;
+    maybelong fsize, jj, filter_size = 0, border_flag_value;
+    maybelong *offsets = NULL, *oo, size;
+    NI_FilterIterator fi;
+    NI_Iterator ii, io;
+    char *pi, *po;
+    double *buffer = NULL;
+    int ll;
+
+    /* get the the footprint: */
+    fsize = 1;
+    for(ll = 0; ll < footprint->nd; ll++)
+        fsize *= footprint->dimensions[ll];
+    pf = (Bool*)PyArray_DATA(footprint);
+    for(jj = 0; jj < fsize; jj++) {
+        if (pf[jj])
+            ++filter_size;
+    }
+    /* initialize filter offsets: */
+    if (!NI_InitFilterOffsets(input, pf, footprint->dimensions, origins,
+                                                        mode, &offsets, &border_flag_value, NULL))
+        goto exit;
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(input->nd, footprint->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 exit;
+    /* get data pointers an array size: */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* buffer for filter calculation: */
+    buffer = (double*)malloc(filter_size * sizeof(double));
+    if (!buffer) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    /* iterate over the elements: */
+    oo = offsets;
+    for(jj = 0; jj < size; jj++) {
+        double tmp = 0.0;
+        switch (input->descr->type_num) {
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Bool,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, UInt8,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, UInt16,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, UInt32,
+                                                tmp, border_flag_value, function, data, buffer);
+#if HAS_UINT64
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, UInt64,
+                                                tmp, border_flag_value, function, data, buffer);
+#endif
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Int8,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Int16,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Int32,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Int64,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Float32,
+                                                tmp, border_flag_value, function, data, buffer);
+            CASE_FILTER_POINT(pi, oo, filter_size, cvalue, Float64,
+                                                tmp, border_flag_value, function, data, buffer);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        switch (output->descr->type_num) {
+            CASE_FILTER_OUT(po, tmp, Bool);
+            CASE_FILTER_OUT(po, tmp, UInt8);
+            CASE_FILTER_OUT(po, tmp, UInt16);
+            CASE_FILTER_OUT(po, tmp, UInt32);
+#if HAS_UINT64
+            CASE_FILTER_OUT(po, tmp, UInt64);
+#endif
+            CASE_FILTER_OUT(po, tmp, Int8);
+            CASE_FILTER_OUT(po, tmp, Int16);
+            CASE_FILTER_OUT(po, tmp, Int32);
+            CASE_FILTER_OUT(po, tmp, Int64);
+            CASE_FILTER_OUT(po, tmp, Float32);
+            CASE_FILTER_OUT(po, tmp, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            goto exit;
+        }
+        NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
+    }
+exit:
+    if (offsets) free(offsets);
+    if (buffer) free(buffer);
+    return PyErr_Occurred() ? 0 : 1;
+}

Added: branches/Interpolate1D/ndimage/ni_filters.h
===================================================================
--- branches/Interpolate1D/ndimage/ni_filters.h	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/ni_filters.h	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,54 @@
+/* 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 NI_FILTERS_H
+#define NI_FILTERS_H
+
+int NI_Correlate1D(PyArrayObject*, PyArrayObject*, int, PyArrayObject*,
+                                     NI_ExtendMode, double, maybelong);
+int NI_Correlate(PyArrayObject*, PyArrayObject*, PyArrayObject*,
+                                 NI_ExtendMode, double, maybelong*);
+int NI_UniformFilter1D(PyArrayObject*, long, int, PyArrayObject*,
+                                             NI_ExtendMode, double, long);
+int NI_MinOrMaxFilter1D(PyArrayObject*, long, int, PyArrayObject*,
+                                                NI_ExtendMode, double, long, int);
+int NI_MinOrMaxFilter(PyArrayObject*, PyArrayObject*, PyArrayObject*,
+                                            PyArrayObject*, NI_ExtendMode, double, maybelong*,
+                                            int);
+int NI_RankFilter(PyArrayObject*, int, PyArrayObject*, PyArrayObject*,
+                                    NI_ExtendMode, double, maybelong*);
+int NI_GenericFilter1D(PyArrayObject*, int (*)(double*, maybelong, 
+                                             double*, maybelong, void*), void*, long, int,
+                                             PyArrayObject*, NI_ExtendMode, double, long);
+int NI_GenericFilter(PyArrayObject*, int (*)(double*, maybelong, double*,
+                                         void*), void*, PyArrayObject*, PyArrayObject*,
+                                         NI_ExtendMode, double, maybelong*);
+#endif

Added: branches/Interpolate1D/ndimage/ni_fourier.c
===================================================================
--- branches/Interpolate1D/ndimage/ni_fourier.c	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/ni_fourier.c	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,548 @@
+/* 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 <stdlib.h>
+#include <math.h>
+#include <assert.h>
+
+#if !defined(M_PI)
+#define M_PI 3.14159265358979323846
+#endif
+
+#define _NI_GAUSSIAN 0
+#define _NI_UNIFORM 1
+#define _NI_ELLIPSOID 2
+
+static double polevl(double x, const double coef[], int N)
+{
+    double ans;
+    const double *p = coef;
+    int i = N;
+
+    ans = *p++;
+    do
+        ans = ans * x + *p++;
+    while(--i);
+
+    return ans ;
+}
+
+double p1evl(double x, const double coef[], int N)
+{
+    double ans;
+    const double *p = coef;
+    int i = N - 1;
+
+    ans = x + *p++;
+    do
+        ans = ans * x + *p++;
+    while(--i);
+
+    return ans;
+}
+
+#define THPIO4 2.35619449019234492885
+#define SQ2OPI .79788456080286535588
+#define Z1 1.46819706421238932572E1
+#define Z2 4.92184563216946036703E1
+
+static double _bessel_j1(double x)
+{
+    double w, z, p, q, xn;
+    const double RP[4] = {
+        -8.99971225705559398224E8,
+        4.52228297998194034323E11,
+        -7.27494245221818276015E13,
+        3.68295732863852883286E15,
+    };
+    const double RQ[8] = {
+        6.20836478118054335476E2,
+        2.56987256757748830383E5,
+        8.35146791431949253037E7,
+        2.21511595479792499675E10,
+        4.74914122079991414898E12,
+        7.84369607876235854894E14,
+        8.95222336184627338078E16,
+        5.32278620332680085395E18,
+    };
+    const double PP[7] = {
+        7.62125616208173112003E-4,
+        7.31397056940917570436E-2,
+        1.12719608129684925192E0,
+        5.11207951146807644818E0,
+        8.42404590141772420927E0,
+        5.21451598682361504063E0,
+        1.00000000000000000254E0,
+    };
+    const double PQ[7] = {
+        5.71323128072548699714E-4,
+        6.88455908754495404082E-2,
+        1.10514232634061696926E0,
+        5.07386386128601488557E0,
+        8.39985554327604159757E0,
+        5.20982848682361821619E0,
+        9.99999999999999997461E-1,
+    };
+    const double QP[8] = {
+        5.10862594750176621635E-2,
+        4.98213872951233449420E0,
+        7.58238284132545283818E1,
+        3.66779609360150777800E2,
+        7.10856304998926107277E2,
+        5.97489612400613639965E2,
+        2.11688757100572135698E2,
+        2.52070205858023719784E1,
+    };
+    const double QQ[7] = {
+        7.42373277035675149943E1,
+        1.05644886038262816351E3,
+        4.98641058337653607651E3,
+        9.56231892404756170795E3,
+        7.99704160447350683650E3,
+        2.82619278517639096600E3,
+        3.36093607810698293419E2,
+    };
+
+    w = x;
+    if (x < 0)
+        w = -x;
+
+    if (w <= 5.0) {
+        z = x * x;
+        w = polevl(z, RP, 3) / p1evl(z, RQ, 8);
+        w = w * x * (z - Z1) * (z - Z2);
+        return w ;
+    }
+
+    w = 5.0 / x;
+    z = w * w;
+    p = polevl(z, PP, 6) / polevl(z, PQ, 6);
+    q = polevl(z, QP, 7) / p1evl(z, QQ, 7);
+    xn = x - THPIO4;
+    p = p * cos(xn) - w * q * sin(xn);
+    return p * SQ2OPI / sqrt(x);
+}
+
+#define CASE_FOURIER_OUT_RR(_po, _tmp, _type) \
+case t ## _type:                              \
+    *(_type*)_po = _tmp;                        \
+    break
+
+#define CASE_FOURIER_OUT_RC(_po, _tmp, _type) \
+case t ## _type:                              \
+    (*(_type*)_po).real = tmp;                  \
+    (*(_type*)_po).imag = 0.0;                  \
+    break
+
+#define CASE_FOURIER_OUT_CC(_po, _tmp_r, _tmp_i, _type) \
+case t ## _type:                                        \
+    (*(_type*)_po).real = _tmp_r;                         \
+    (*(_type*)_po).imag = _tmp_i;                         \
+    break
+
+#define CASE_FOURIER_FILTER_RC(_pi, _tmp, _tmp_r, _tmp_i, _type) \
+case t ## _type:                                                 \
+    _tmp_r = (*(_type*)_pi).real * _tmp;                           \
+    _tmp_i = (*(_type*)_pi).imag * _tmp;                           \
+    break;
+
+#define CASE_FOURIER_FILTER_RR(_pi, _tmp, _type) \
+case t ## _type:                                 \
+    _tmp *= *(_type*)_pi;                          \
+    break;
+
+int NI_FourierFilter(PyArrayObject *input, PyArrayObject* parameter_array,
+                        maybelong n, int axis, PyArrayObject* output, int filter_type)
+{
+    NI_Iterator ii, io;
+    char *pi, *po;
+    double *parameters = NULL, **params = NULL;
+    maybelong kk, hh, size;
+    Float64 *iparameters = (void *)PyArray_DATA(parameter_array);
+    int ll;
+
+    /* precalculate the parameters: */
+    parameters = (double*)malloc(input->nd * sizeof(double));
+    if (!parameters) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(kk = 0; kk < input->nd; kk++) {
+        /* along the direction of the real transform we must use the given
+             length of that dimensons, unless a complex transform is assumed
+             (n < 0): */
+        int shape = kk == axis ?
+                        (n < 0 ? input->dimensions[kk] : n) : input->dimensions[kk];
+        switch (filter_type) {
+            case _NI_GAUSSIAN:
+                parameters[kk] = *iparameters++ * M_PI / (double)shape;
+                parameters[kk] = -2.0 * parameters[kk] * parameters[kk];
+                break;
+            case _NI_ELLIPSOID:
+            case _NI_UNIFORM:
+                parameters[kk] = *iparameters++;
+                break;
+        }
+    }
+    /* allocate memory for tables: */
+    params = (double**) malloc(input->nd * sizeof(double*));
+    if (!params) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(kk = 0; kk < input->nd; kk++)
+        params[kk] = NULL;
+    for(kk = 0; kk < input->nd; kk++) {
+        if (input->dimensions[kk] > 1) {
+            params[kk] = (double*)malloc(input->dimensions[kk] * sizeof(double));
+            if (!params[kk]) {
+                PyErr_NoMemory();
+                goto exit;
+            }
+        }
+    }
+    switch (filter_type) {
+        case _NI_GAUSSIAN:
+            /* calculate the tables of exponentials: */
+            for (hh = 0; hh < input->nd; hh++) {
+                if (params[hh]) {
+                    if (hh == axis && n >= 0) {
+                        for(kk = 0; kk < input->dimensions[hh]; kk++) {
+                            double tmp = parameters[hh] * kk * kk;
+                            params[hh][kk] = fabs(tmp) > 50.0 ? 0.0 : exp(tmp);
+                        }
+                    } else {
+                        int jj = 0;
+                        for(kk = 0; kk < (input->dimensions[hh] + 1) / 2; kk++) {
+                            double tmp = parameters[hh] * kk * kk;
+                            params[hh][jj++] = fabs(tmp) > 50.0 ? 0.0 : exp(tmp);
+                        }
+                        for(kk = -(input->dimensions[hh] / 2); kk < 0; kk++) {
+                            double tmp = parameters[hh] * kk * kk;
+                            params[hh][jj++] = fabs(tmp) > 50.0 ? 0.0 : exp(tmp);
+                        }
+                    }
+                }
+            }
+            break;
+        case _NI_UNIFORM:
+            /* calculate the tables of parameters: */
+            for (hh = 0; hh < input->nd; hh++) {
+                if (params[hh]) {
+                    params[hh][0] = 1.0;
+                    if (hh == axis && n >= 0) {
+                        double tmp = M_PI * parameters[hh] / n;
+                        for(kk = 1; kk < input->dimensions[hh]; kk++)
+                            params[hh][kk] = tmp > 0.0 ?
+                                                                            sin(tmp * kk) / (tmp * kk) : 0.0;
+                    } else {
+                        double tmp = M_PI * parameters[hh] / input->dimensions[hh];
+                        int jj = 1;
+                        for(kk = 1; kk < (input->dimensions[hh] + 1) / 2; kk++)
+                            params[hh][jj++] = tmp > 0.0 ?
+                                                                            sin(tmp * kk) / (tmp * kk) : 0.0;
+                        for(kk = -(input->dimensions[hh] / 2); kk < 0; kk++)
+                            params[hh][jj++] = tmp > 0.0 ?
+                                                                            sin(tmp * kk) / (tmp * kk) : 0.0;
+                    }
+                }
+            }
+            break;
+        case _NI_ELLIPSOID:
+            /* calculate the tables of parameters: */
+            for (hh = 0; hh < input->nd; hh++) {
+                if (params[hh]) {
+                    params[hh][0] = 1.0;
+                    if (hh == axis && n >= 0) {
+                        double tmp = M_PI * parameters[hh] / n;
+                        for(kk = 0; kk < input->dimensions[hh]; kk++)
+                            params[hh][kk] = (double)kk * tmp;
+                    } else {
+                        double tmp = M_PI * parameters[hh] / input->dimensions[hh];
+                        int jj = 0;
+                        for(kk = 0; kk < (input->dimensions[hh] + 1) / 2; kk++)
+                            params[hh][jj++] = (double)kk * tmp;
+                        for(kk = -(input->dimensions[hh] / 2); kk < 0; kk++)
+                            params[hh][jj++] = (double)kk * tmp;
+                    }
+                } else if (input->dimensions[hh] > 0) {
+                    params[hh][0] = 1.0;
+                }
+            }
+            if (input->nd > 1)
+                for(hh = 0; hh < input->nd; hh++)
+                    for(kk = 0; kk < input->dimensions[hh]; kk++)
+                        params[hh][kk] = params[hh][kk] * params[hh][kk];
+            break;
+        default:
+            break;
+    }
+    /* initialize input element iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* initialize output element iterator: */
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* iterator over the elements: */
+    for(hh = 0; hh < size; hh++) {
+        double tmp = 1.0;
+        switch (filter_type) {
+        case _NI_GAUSSIAN:
+        case _NI_UNIFORM:
+            for(kk = 0; kk < input->nd; kk++)
+                if (params[kk])
+                    tmp *= params[kk][ii.coordinates[kk]];
+            break;
+        case _NI_ELLIPSOID:
+            switch (input->nd) {
+            case 1:
+                tmp = params[0][ii.coordinates[0]];
+                tmp = tmp > 0.0 ? sin(tmp) / (tmp) : 1.0;
+                break;
+            case 2:
+                tmp = 0.0;
+                for(kk = 0; kk < 2; kk++)
+                    tmp += params[kk][ii.coordinates[kk]];
+                tmp = sqrt(tmp);
+                tmp = tmp > 0.0 ? 2.0 * _bessel_j1(tmp) / tmp : 1.0;
+                break;
+            case 3:
+                {
+                    double r = 0.0;
+                    for(kk = 0; kk < 3; kk++)
+                        r += params[kk][ii.coordinates[kk]];
+                    r = sqrt(r);
+                    if (r > 0.0) {
+                        tmp = 3.0 * (sin(r) - r * cos(r));
+                        tmp /= r * r * r;
+                    } else {
+                        tmp = 1.0;
+                    }
+                }
+                break;
+            }
+            break;
+        default:
+            break;
+        }
+        if (input->descr->type_num == tComplex64 ||
+                input->descr->type_num == tComplex128) {
+            double tmp_r = 0.0, tmp_i = 0.0;
+            switch (input->descr->type_num) {
+                CASE_FOURIER_FILTER_RC(pi, tmp, tmp_r, tmp_i, Complex64);
+                CASE_FOURIER_FILTER_RC(pi, tmp, tmp_r, tmp_i, Complex128);
+            default:
+                PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                goto exit;
+            }
+            switch (output->descr->type_num) {
+                CASE_FOURIER_OUT_CC(po, tmp_r, tmp_i, Complex64);
+                CASE_FOURIER_OUT_CC(po, tmp_r, tmp_i, Complex128);
+            default:
+                PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                goto exit;
+            }
+        } else {
+            switch (input->descr->type_num) {
+                CASE_FOURIER_FILTER_RR(pi, tmp, Bool)
+                CASE_FOURIER_FILTER_RR(pi, tmp, UInt8)
+                CASE_FOURIER_FILTER_RR(pi, tmp, UInt16)
+                CASE_FOURIER_FILTER_RR(pi, tmp, UInt32)
+#if HAS_UINT64
+                CASE_FOURIER_FILTER_RR(pi, tmp, UInt64)
+#endif
+                CASE_FOURIER_FILTER_RR(pi, tmp, Int8)
+                CASE_FOURIER_FILTER_RR(pi, tmp, Int16)
+                CASE_FOURIER_FILTER_RR(pi, tmp, Int32)
+                CASE_FOURIER_FILTER_RR(pi, tmp, Int64)
+                CASE_FOURIER_FILTER_RR(pi, tmp, Float32)
+                CASE_FOURIER_FILTER_RR(pi, tmp, Float64)
+            default:
+                PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                goto exit;
+            }
+            switch (output->descr->type_num) {
+                CASE_FOURIER_OUT_RR(po, tmp, Float32);
+                CASE_FOURIER_OUT_RR(po, tmp, Float64);
+                CASE_FOURIER_OUT_RC(po, tmp, Complex64);
+                CASE_FOURIER_OUT_RC(po, tmp, Complex128);
+            default:
+                PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                goto exit;
+            }
+        }
+        NI_ITERATOR_NEXT2(ii, io, pi, po);
+    }
+
+ exit:
+    if (parameters) free(parameters);
+    if (params) {
+        for(kk = 0; kk < input->nd; kk++)
+            if (params[kk]) free(params[kk]);
+        free(params);
+    }
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+#define CASE_FOURIER_SHIFT_R(_pi, _tmp, _r, _i, _cost, _sint, _type) \
+case t ## _type:                                                     \
+    _tmp = *(_type*)_pi;                                               \
+    _r = _tmp * _cost;                                                 \
+    _i = _tmp * _sint;                                                 \
+    break;
+
+#define CASE_FOURIER_SHIFT_C(_pi, _r, _i, _cost, _sint, _type)     \
+case t ## _type:                                                   \
+    _r = (*(_type*)_pi).real * _cost - (*(_type*)_pi).imag * _sint;  \
+    _i = (*(_type*)_pi).real * _sint + (*(_type*)_pi).imag * _cost;  \
+    break;
+
+int NI_FourierShift(PyArrayObject *input, PyArrayObject* shift_array,
+            maybelong n, int axis, PyArrayObject* output)
+{
+    NI_Iterator ii, io;
+    char *pi, *po;
+    double *shifts = NULL, **params = NULL;
+    maybelong kk, hh, size;
+    Float64 *ishifts = (void *)PyArray_DATA(shift_array);
+    int ll;
+
+    /* precalculate the shifts: */
+    shifts = (double*)malloc(input->nd * sizeof(double));
+    if (!shifts) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(kk = 0; kk < input->nd; kk++) {
+        /* along the direction of the real transform we must use the given
+             length of that dimensons, unless a complex transform is assumed
+             (n < 0): */
+        int shape = kk == axis ?
+                        (n < 0 ? input->dimensions[kk] : n) : input->dimensions[kk];
+        shifts[kk] = -2.0 * M_PI * *ishifts++ / (double)shape;
+    }
+    /* allocate memory for tables: */
+    params = (double**) malloc(input->nd * sizeof(double*));
+    if (!params) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(kk = 0; kk < input->nd; kk++)
+        params[kk] = NULL;
+    for(kk = 0; kk < input->nd; kk++) {
+        if (input->dimensions[kk] > 1) {
+            params[kk] = (double*)malloc(input->dimensions[kk] * sizeof(double));
+            if (!params[kk]) {
+                PyErr_NoMemory();
+                goto exit;
+            }
+        }
+    }
+    for (hh = 0; hh < input->nd; hh++) {
+        if (params[hh]) {
+            if (hh == axis && n >= 0) {
+                for(kk = 0; kk < input->dimensions[hh]; kk++)
+                    params[hh][kk] = shifts[hh] * kk;
+            } else {
+                int jj = 0;
+                for(kk = 0; kk < (input->dimensions[hh] + 1) / 2; kk++) {
+                    params[hh][jj++] = shifts[hh] * kk;
+                }
+                for(kk = -(input->dimensions[hh] / 2); kk < 0; kk++) {
+                    params[hh][jj++] = shifts[hh] * kk;
+                }
+            }
+        }
+    }
+    /* initialize input element iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* initialize output element iterator: */
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* iterator over the elements: */
+    for(hh = 0; hh < size; hh++) {
+        double tmp = 0.0, sint, cost, r = 0.0, i = 0.0;
+        for(kk = 0; kk < input->nd; kk++)
+            if (params[kk])
+                tmp += params[kk][ii.coordinates[kk]];
+        sint = sin(tmp);
+        cost = cos(tmp);
+        switch (input->descr->type_num) {
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Bool)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, UInt8)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, UInt16)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, UInt32)
+#if HAS_UINT64
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, UInt64)
+#endif
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Int8)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Int16)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Int32)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Int64)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Float32)
+            CASE_FOURIER_SHIFT_R(pi, tmp, r, i, cost, sint, Float64)
+            CASE_FOURIER_SHIFT_C(pi, r, i, cost, sint, Complex64)
+            CASE_FOURIER_SHIFT_C(pi, r, i, cost, sint, Complex128)
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        switch (output->descr->type_num) {
+            CASE_FOURIER_OUT_CC(po, r, i, Complex64);
+            CASE_FOURIER_OUT_CC(po, r, i, Complex128);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        NI_ITERATOR_NEXT2(ii, io, pi, po);
+    }
+
+ exit:
+    if (shifts) free(shifts);
+    if (params) {
+        for(kk = 0; kk < input->nd; kk++)
+            if (params[kk]) free(params[kk]);
+        free(params);
+    }
+    return PyErr_Occurred() ? 0 : 1;
+}

Added: branches/Interpolate1D/ndimage/ni_fourier.h
===================================================================
--- branches/Interpolate1D/ndimage/ni_fourier.h	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/ni_fourier.h	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,40 @@
+/* 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 NI_FOURIER_H
+#define NI_FOURIER_H
+
+int NI_FourierFilter(PyArrayObject*, PyArrayObject*, maybelong, int,
+                                         PyArrayObject*, int);
+int NI_FourierShift(PyArrayObject*, PyArrayObject*, maybelong, int,
+                                        PyArrayObject*);
+
+#endif

Added: branches/Interpolate1D/ndimage/ni_interpolation.c
===================================================================
--- branches/Interpolate1D/ndimage/ni_interpolation.c	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/ni_interpolation.c	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,966 @@
+/* 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_interpolation.h"
+#include <stdlib.h>
+#include <math.h>
+
+/* calculate the B-spline interpolation coefficients for given x: */
+static void
+spline_coefficients(double x, int order, double *result)
+{
+    int hh;
+    double y, start;
+
+    if (order & 1) {
+        start = (int)floor(x) - order / 2;
+    } else {
+        start = (int)floor(x + 0.5) - order / 2;
+    }
+
+    for(hh = 0; hh <= order; hh++)  {
+        y = fabs(start - x + hh);
+
+        switch(order) {
+        case 1:
+            result[hh] = y > 1.0 ? 0.0 : 1.0 - y;
+            break;
+        case 2:
+            if (y < 0.5) {
+                result[hh] = 0.75 - y * y;
+            } else if (y < 1.5) {
+                y = 1.5 - y;
+                result[hh] = 0.5 * y * y;
+            } else {
+                result[hh] = 0.0;
+            }
+            break;
+        case 3:
+            if (y < 1.0) {
+                result[hh] =
+                    (y * y * (y - 2.0) * 3.0 + 4.0) / 6.0;
+            } else if (y < 2.0) {
+                y = 2.0 - y;
+                result[hh] = y * y * y / 6.0;
+            } else {
+                result[hh] = 0.0;
+            }
+            break;
+        case 4:
+            if (y < 0.5) {
+                y *= y;
+                result[hh] = y * (y * 0.25 - 0.625) + 115.0 / 192.0;
+            } else if (y < 1.5) {
+                result[hh] = y * (y * (y * (5.0 / 6.0 - y / 6.0) - 1.25) +
+                                                    5.0 / 24.0) + 55.0 / 96.0;
+            } else if (y < 2.5) {
+                y -= 2.5;
+                y *= y;
+                result[hh] = y * y / 24.0;
+            } else {
+                result[hh] = 0.0;
+            }
+            break;
+        case 5:
+            if (y < 1.0) {
+                double f = y * y;
+                result[hh] =
+                    f * (f * (0.25 - y / 12.0) - 0.5) + 0.55;
+            } else if (y < 2.0) {
+                result[hh] = y * (y * (y * (y * (y / 24.0 - 0.375)
+                                                    + 1.25) -  1.75) + 0.625) + 0.425;
+            } else if (y < 3.0) {
+                double f = 3.0 - y;
+                y = f * f;
+                result[hh] = f * y * y / 120.0;
+            } else {
+                result[hh] = 0.0;
+            }
+            break;
+        }
+    }
+}
+
+/* map a coordinate outside the borders, according to the requested
+     boundary condition: */
+static double
+map_coordinate(double in, maybelong len, int mode)
+{
+    if (in < 0) {
+        switch (mode) {
+        case NI_EXTEND_MIRROR:
+            if (len <= 1) {
+                in = 0;
+            } else {
+                maybelong sz2 = 2 * len - 2;
+                in = sz2 * (maybelong)(-in / sz2) + in;
+                in = in <= 1 - len ? in + sz2 : -in;
+            }
+            break;
+        case NI_EXTEND_REFLECT:
+            if (len <= 1) {
+                in = 0;
+            } else {
+                maybelong sz2 = 2 * len;
+                if (in < -sz2)
+                    in = sz2 * (maybelong)(-in / sz2) + in;
+                in = in < -len ? in + sz2 : -in - 1;
+            }
+            break;
+        case NI_EXTEND_WRAP:
+            if (len <= 1) {
+                in = 0;
+            } else {
+                maybelong sz = len - 1;
+                // Integer division of -in/sz gives (-in mod sz)
+                // Note that 'in' is negative
+                in += sz * ((maybelong)(-in / sz) + 1);
+            }
+            break;
+        case NI_EXTEND_NEAREST:
+            in = 0;
+            break;
+        case NI_EXTEND_CONSTANT:
+            in = -1;
+            break;
+        }
+    } else if (in > len-1) {
+        switch (mode) {
+        case NI_EXTEND_MIRROR:
+            if (len <= 1) {
+                in = 0;
+            } else {
+                maybelong sz2 = 2 * len - 2;
+                in -= sz2 * (maybelong)(in / sz2);
+                if (in >= len)
+                    in = sz2 - in;
+            }
+            break;
+        case NI_EXTEND_REFLECT:
+            if (len <= 1) {
+                in = 0;
+            } else {
+                maybelong sz2 = 2 * len;
+                in -= sz2 * (maybelong)(in / sz2);
+                if (in >= len)
+                    in = sz2 - in - 1;
+            }
+            break;
+        case NI_EXTEND_WRAP:
+            if (len <= 1) {
+                in = 0;
+            } else {
+                maybelong sz = len - 1;
+                in -= sz * (maybelong)(in / sz);
+            }
+            break;
+        case NI_EXTEND_NEAREST:
+            in = len - 1;
+            break;
+        case NI_EXTEND_CONSTANT:
+            in = -1;
+            break;
+        }
+    }
+
+    return in;
+}
+
+#define BUFFER_SIZE 256000
+#define TOLERANCE 1e-15
+
+/* one-dimensional spline filter: */
+int NI_SplineFilter1D(PyArrayObject *input, int order, int axis,
+                                            PyArrayObject *output)
+{
+    int hh, npoles = 0, more;
+    maybelong kk, ll, lines, len;
+    double *buffer = NULL, weight, pole[2];
+    NI_LineBuffer iline_buffer, oline_buffer;
+
+    len = input->nd > 0 ? input->dimensions[axis] : 1;
+    if (len < 1)
+        goto exit;
+
+    /* these are used in the spline filter calculation below: */
+    switch (order) {
+    case 2:
+        npoles = 1;
+        pole[0] = sqrt(8.0) - 3.0;
+        break;
+    case 3:
+        npoles = 1;
+        pole[0] = sqrt(3.0) - 2.0;
+        break;
+    case 4:
+        npoles = 2;
+        pole[0] = sqrt(664.0 - sqrt(438976.0)) + sqrt(304.0) - 19.0;
+        pole[1] = sqrt(664.0 + sqrt(438976.0)) - sqrt(304.0) - 19.0;
+        break;
+    case 5:
+        npoles = 2;
+        pole[0] = sqrt(67.5 - sqrt(4436.25)) + sqrt(26.25) - 6.5;
+        pole[1] = sqrt(67.5 + sqrt(4436.25)) - sqrt(26.25) - 6.5;
+        break;
+    default:
+        break;
+    }
+
+    weight = 1.0;
+    for(hh = 0; hh < npoles; hh++)
+        weight *= (1.0 - pole[hh]) * (1.0 - 1.0 / pole[hh]);
+
+    /* allocate an initialize the line buffer, only a single one is used,
+         because the calculation is in-place: */
+    lines = -1;
+    if (!NI_AllocateLineBuffer(input, axis, 0, 0, &lines, BUFFER_SIZE,
+                                                         &buffer))
+        goto exit;
+    if (!NI_InitLineBuffer(input, axis, 0, 0, lines, buffer,
+                                                 NI_EXTEND_DEFAULT, 0.0, &iline_buffer))
+        goto exit;
+    if (!NI_InitLineBuffer(output, axis, 0, 0, lines, buffer,
+                                                 NI_EXTEND_DEFAULT, 0.0, &oline_buffer))
+        goto exit;
+
+    /* 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 buffer: */
+        for(kk = 0; kk < lines; kk++) {
+            /* get line: */
+            double *ln = NI_GET_LINE(iline_buffer, kk);
+            /* spline filter: */
+            if (len > 1) {
+                for(ll = 0; ll < len; ll++)
+                    ln[ll] *= weight;
+                for(hh = 0; hh < npoles; hh++) {
+                    double p = pole[hh];
+                    int max = (int)ceil(log(TOLERANCE) / log(fabs(p)));
+                    if (max < len) {
+                        double zn = p;
+                        double sum = ln[0];
+                        for(ll = 1; ll < max; ll++) {
+                            sum += zn * ln[ll];
+                            zn *= p;
+                        }
+                        ln[0] = sum;
+                    } else {
+                        double zn = p;
+                        double iz = 1.0 / p;
+                        double z2n = pow(p, (double)(len - 1));
+                        double sum = ln[0] + z2n * ln[len - 1];
+                        z2n *= z2n * iz;
+                        for(ll = 1; ll <= len - 2; ll++) {
+                            sum += (zn + z2n) * ln[ll];
+                            zn *= p;
+                            z2n *= iz;
+                        }
+                        ln[0] = sum / (1.0 - zn * zn);
+                    }
+                    for(ll = 1; ll < len; ll++)
+                        ln[ll] += p * ln[ll - 1];
+                    ln[len-1] = (p / (p * p - 1.0)) * (ln[len-1] + p * ln[len-2]);
+                    for(ll = len - 2; ll >= 0; ll--)
+                        ln[ll] = p * (ln[ll + 1] - ln[ll]);
+                }
+            }
+        }
+        /* copy lines from buffer to array: */
+        if (!NI_LineBufferToArray(&oline_buffer))
+            goto exit;
+    } while(more);
+
+ exit:
+    if (buffer) free(buffer);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+#define CASE_MAP_COORDINATES(_p, _coor, _rank, _stride, _type) \
+case t ## _type:                                                    \
+{                                                              \
+    int _hh;                                                     \
+    for(_hh = 0; _hh < _rank; _hh++) {                           \
+        _coor[_hh] = *(_type*)_p;                                  \
+        _p += _stride;                                             \
+    }                                                            \
+}                                                              \
+break;
+
+#define CASE_INTERP_COEFF(_coeff, _pi, _idx, _type) \
+case t ## _type:                                    \
+    _coeff = *(_type*)(_pi + _idx);                   \
+    break;
+
+#define CASE_INTERP_OUT(_po, _t, _type) \
+case t ## _type:                        \
+    *(_type*)_po = (_type)_t;             \
+    break;
+
+#define CASE_INTERP_OUT_UINT(_po, _t, _type, type_min, type_max) \
+case t ## _type:                             \
+    _t = _t > 0 ? _t + 0.5 : 0;                \
+    _t = _t > type_max ? type_max : t;         \
+    _t = _t < type_min ? type_min : t;         \
+    *(_type*)_po = (_type)_t;                  \
+    break;
+
+#define CASE_INTERP_OUT_INT(_po, _t, _type, type_min, type_max) \
+case t ## _type:                            \
+    _t = _t > 0 ? _t + 0.5 : _t - 0.5;        \
+    _t = _t > type_max ? type_max : t;        \
+    _t = _t < type_min ? type_min : t;        \
+    *(_type*)_po = (_type)_t;                 \
+    break;
+
+int
+NI_GeometricTransform(PyArrayObject *input, int (*map)(maybelong*, double*,
+                int, int, void*), void* map_data, PyArrayObject* matrix_ar,
+                PyArrayObject* shift_ar, PyArrayObject *coordinates,
+                PyArrayObject *output, int order, int mode, double cval)
+{
+    char *po, *pi, *pc = NULL;
+    maybelong **edge_offsets = NULL, **data_offsets = NULL, filter_size;
+    maybelong ftmp[MAXDIM], *fcoordinates = NULL, *foffsets = NULL;
+    maybelong cstride = 0, kk, hh, ll, jj, *idxs = NULL;
+    maybelong size;
+    double **splvals = NULL, icoor[MAXDIM];
+    double idimensions[MAXDIM], istrides[MAXDIM];
+    NI_Iterator io, ic;
+    Float64 *matrix = matrix_ar ? (Float64*)PyArray_DATA(matrix_ar) : NULL;
+    Float64 *shift = shift_ar ? (Float64*)PyArray_DATA(shift_ar) : NULL;
+    int irank = 0, orank, qq;
+
+    for(kk = 0; kk < input->nd; kk++) {
+        idimensions[kk] = input->dimensions[kk];
+        istrides[kk] = input->strides[kk];
+    }
+    irank = input->nd;
+    orank = output->nd;
+
+    /* if the mapping is from array coordinates: */
+    if (coordinates) {
+        /* initialze a line iterator along the first axis: */
+        if (!NI_InitPointIterator(coordinates, &ic))
+            goto exit;
+        cstride = ic.strides[0];
+        if (!NI_LineIterator(&ic, 0))
+            goto exit;
+        pc = (void *)(PyArray_DATA(coordinates));
+    }
+
+    /* offsets used at the borders: */
+    edge_offsets = (maybelong**)malloc(irank * sizeof(maybelong*));
+    data_offsets = (maybelong**)malloc(irank * sizeof(maybelong*));
+    if (!edge_offsets || !data_offsets) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < irank; jj++)
+        data_offsets[jj] = NULL;
+    for(jj = 0; jj < irank; jj++) {
+        data_offsets[jj] = (maybelong*)malloc((order + 1) * sizeof(maybelong));
+        if (!data_offsets[jj]) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+    /* will hold the spline coefficients: */
+    splvals = (double**)malloc(irank * sizeof(double*));
+    if (!splvals) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < irank; jj++)
+        splvals[jj] = NULL;
+    for(jj = 0; jj < irank; jj++) {
+        splvals[jj] = (double*)malloc((order + 1) * sizeof(double));
+        if (!splvals[jj]) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+
+    filter_size = 1;
+    for(jj = 0; jj < irank; jj++)
+        filter_size *= order + 1;
+    idxs = (maybelong*)malloc(filter_size * sizeof(idxs));
+    if (!idxs) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+
+    /* initialize output iterator: */
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+
+    /* get data pointers: */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+
+    /* make a table of all possible coordinates within the spline filter: */
+    fcoordinates = (maybelong*)malloc(irank * filter_size * sizeof(maybelong));
+    /* make a table of all offsets within the spline filter: */
+    foffsets = (maybelong*)malloc(filter_size * sizeof(maybelong));
+    if (!fcoordinates || !foffsets) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < irank; jj++)
+        ftmp[jj] = 0;
+    kk = 0;
+    for(hh = 0; hh < filter_size; hh++) {
+        for(jj = 0; jj < irank; jj++)
+            fcoordinates[jj + hh * irank] = ftmp[jj];
+        foffsets[hh] = kk;
+        for(jj = irank - 1; jj >= 0; jj--) {
+            if (ftmp[jj] < order) {
+                ftmp[jj]++;
+                kk += istrides[jj];
+                break;
+            } else {
+                ftmp[jj] = 0;
+                kk -= istrides[jj] * order;
+            }
+        }
+    }
+
+    size = 1;
+    for(qq = 0; qq < output->nd; qq++)
+        size *= output->dimensions[qq];
+    for(kk = 0; kk < size; kk++) {
+        double t = 0.0;
+        int constant = 0, edge = 0, offset = 0;
+        if (map) {
+            /* call mappint functions: */
+            if (!map(io.coordinates, icoor, orank, irank, map_data)) {
+                if (!PyErr_Occurred())
+                    PyErr_SetString(PyExc_RuntimeError,
+                                                    "unknown error in mapping function");
+                goto exit;
+            }
+        } else if (matrix) {
+            /* do an affine transformation: */
+            Float64 *p = matrix;
+            for(hh = 0; hh < irank; hh++) {
+                icoor[hh] = 0.0;
+                for(ll = 0; ll < orank; ll++)
+                    icoor[hh] += io.coordinates[ll] * *p++;
+                icoor[hh] += shift[hh];
+            }
+        } else if (coordinates) {
+            /* mapping is from an coordinates array: */
+            char *p = pc;
+            switch(coordinates->descr->type_num) {
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Bool);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, UInt8);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, UInt16);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, UInt32);
+#if HAS_UINT64
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, UInt64);
+#endif
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Int8);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Int16);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Int32);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Int64);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Float32);
+                CASE_MAP_COORDINATES(p, icoor, irank, cstride, Float64);
+            default:
+                PyErr_SetString(PyExc_RuntimeError,
+                                                "coordinate array data type not supported");
+                goto exit;
+            }
+        }
+        /* iterate over axes: */
+        for(hh = 0; hh < irank; hh++) {
+            /* if the input coordinate is outside the borders, map it: */
+            double cc = map_coordinate(icoor[hh], idimensions[hh], mode);
+            if (cc > -1.0) {
+                /* find the filter location along this axis: */
+                int start;
+                if (order & 1) {
+                    start = (int)floor(cc) - order / 2;
+                } else {
+                    start = (int)floor(cc + 0.5) - order / 2;
+                }
+                /* get the offset to the start of the filter: */
+                offset += istrides[hh] * start;
+                if (start < 0 || start + order >= idimensions[hh]) {
+                    /* implement border mapping, if outside border: */
+                    edge = 1;
+                    edge_offsets[hh] = data_offsets[hh];
+                    for(ll = 0; ll <= order; ll++) {
+                        int idx = start + ll;
+                        int len = idimensions[hh];
+                        if (len <= 1) {
+                            idx = 0;
+                        } else {
+                            int s2 = 2 * len - 2;
+                            if (idx < 0) {
+                                idx = s2 * (int)(-idx / s2) + idx;
+                                idx = idx <= 1 - len ? idx + s2 : -idx;
+                            } else if (idx >= len) {
+                                idx -= s2 * (int)(idx / s2);
+                                if (idx >= len)
+                                    idx = s2 - idx;
+                            }
+                        }
+                        /* calculate and store the offests at this edge: */
+                        edge_offsets[hh][ll] = istrides[hh] * (idx - start);
+                    }
+                } else {
+                    /* we are not at the border, use precalculated offsets: */
+                    edge_offsets[hh] = NULL;
+                }
+                spline_coefficients(cc, order, splvals[hh]);
+            } else {
+                /* we use the constant border condition: */
+                constant = 1;
+                break;
+            }
+        }
+
+        if (!constant) {
+            maybelong *ff = fcoordinates;
+            for(hh = 0; hh < filter_size; hh++) {
+                int idx = 0;
+                if (edge) {
+                    for(ll = 0; ll < irank; ll++) {
+                        if (edge_offsets[ll])
+                            idx += edge_offsets[ll][ff[ll]];
+                        else
+                            idx += ff[ll] * istrides[ll];
+                    }
+                } else {
+                    idx = foffsets[hh];
+                }
+                idx += offset;
+                idxs[hh] = idx;
+                ff += irank;
+            }
+        }
+        if (!constant) {
+            maybelong *ff = fcoordinates;
+            t = 0.0;
+            for(hh = 0; hh < filter_size; hh++) {
+                double coeff = 0.0;
+                switch(input->descr->type_num) {
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Bool);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt8);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt16);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt32);
+#if HAS_UINT64
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt64);
+#endif
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int8);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int16);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int32);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int64);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Float32);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Float64);
+                default:
+                    PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                    goto exit;
+                }
+                /* calculate the interpolated value: */
+                for(ll = 0; ll < irank; ll++)
+                    if (order > 0)
+                        coeff *= splvals[ll][ff[ll]];
+                t += coeff;
+                ff += irank;
+            }
+        } else {
+            t = cval;
+        }
+        /* store output value: */
+        switch (output->descr->type_num) {
+            CASE_INTERP_OUT(po, t, Bool);
+            CASE_INTERP_OUT_UINT(po, t, UInt8, 0, MAX_UINT8);
+            CASE_INTERP_OUT_UINT(po, t, UInt16, 0, MAX_UINT16);
+            CASE_INTERP_OUT_UINT(po, t, UInt32, 0, MAX_UINT32);
+#if HAS_UINT64
+            /* FIXME */
+            CASE_INTERP_OUT_UINT(po, t, UInt64, 0, MAX_UINT32);
+#endif
+            CASE_INTERP_OUT_INT(po, t, Int8, MIN_INT8, MAX_INT8);
+            CASE_INTERP_OUT_INT(po, t, Int16, MIN_INT16, MAX_INT16);
+            CASE_INTERP_OUT_INT(po, t, Int32, MIN_INT32, MAX_INT32);
+            CASE_INTERP_OUT_INT(po, t, Int64, MIN_INT64, MAX_INT64);
+            CASE_INTERP_OUT(po, t, Float32);
+            CASE_INTERP_OUT(po, t, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        if (coordinates) {
+            NI_ITERATOR_NEXT2(io, ic, po, pc);
+        } else {
+            NI_ITERATOR_NEXT(io, po);
+        }
+    }
+
+ exit:
+    if (edge_offsets)
+        free(edge_offsets);
+    if (data_offsets) {
+        for(jj = 0; jj < irank; jj++)
+            free(data_offsets[jj]);
+        free(data_offsets);
+    }
+    if (splvals) {
+        for(jj = 0; jj < irank; jj++)
+            free(splvals[jj]);
+        free(splvals);
+    }
+    if (foffsets)
+        free(foffsets);
+    if (fcoordinates)
+        free(fcoordinates);
+    if (idxs)
+        free(idxs);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+int NI_ZoomShift(PyArrayObject *input, PyArrayObject* zoom_ar,
+                                 PyArrayObject* shift_ar, PyArrayObject *output,
+                                 int order, int mode, double cval)
+{
+    char *po, *pi;
+    maybelong **zeros = NULL, **offsets = NULL, ***edge_offsets = NULL;
+    maybelong ftmp[MAXDIM], *fcoordinates = NULL, *foffsets = NULL;
+    maybelong jj, hh, kk, filter_size, odimensions[MAXDIM];
+    maybelong idimensions[MAXDIM], istrides[MAXDIM], *idxs = NULL;
+    maybelong size;
+    double ***splvals = NULL;
+    NI_Iterator io;
+    Float64 *zooms = zoom_ar ? (Float64*)PyArray_DATA(zoom_ar) : NULL;
+    Float64 *shifts = shift_ar ? (Float64*)PyArray_DATA(shift_ar) : NULL;
+    int rank = 0, qq;
+
+    for(kk = 0; kk < input->nd; kk++) {
+        idimensions[kk] = input->dimensions[kk];
+        istrides[kk] = input->strides[kk];
+        odimensions[kk] = output->dimensions[kk];
+    }
+    rank = input->nd;
+
+    /* if the mode is 'constant' we need some temps later: */
+    if (mode == NI_EXTEND_CONSTANT) {
+        zeros = (maybelong**)malloc(rank * sizeof(maybelong*));
+        if (!zeros) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+        for(jj = 0; jj < rank; jj++)
+            zeros[jj] = NULL;
+        for(jj = 0; jj < rank; jj++) {
+            zeros[jj] = (maybelong*)malloc(odimensions[jj] * sizeof(maybelong));
+            if(!zeros[jj]) {
+                PyErr_NoMemory();
+                goto exit;
+            }
+        }
+    }
+
+    /* store offsets, along each axis: */
+    offsets = (maybelong**)malloc(rank * sizeof(maybelong*));
+    /* store spline coefficients, along each axis: */
+    splvals = (double***)malloc(rank * sizeof(double**));
+    /* store offsets at all edges: */
+    edge_offsets = (maybelong***)malloc(rank * sizeof(maybelong**));
+    if (!offsets || !splvals || !edge_offsets) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < rank; jj++) {
+        offsets[jj] = NULL;
+        splvals[jj] = NULL;
+        edge_offsets[jj] = NULL;
+    }
+    for(jj = 0; jj < rank; jj++) {
+        offsets[jj] = (maybelong*)malloc(odimensions[jj] * sizeof(maybelong));
+        splvals[jj] = (double**)malloc(odimensions[jj] * sizeof(double*));
+        edge_offsets[jj] = (maybelong**)malloc(odimensions[jj] * sizeof(maybelong*));
+        if (!offsets[jj] || !splvals[jj] || !edge_offsets[jj]) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+        for(hh = 0; hh < odimensions[jj]; hh++) {
+            splvals[jj][hh] = NULL;
+            edge_offsets[jj][hh] = NULL;
+        }
+    }
+
+    /* precalculate offsets, and offsets at the edge: */
+    for(jj = 0; jj < rank; jj++) {
+        double shift = 0.0, zoom = 0.0;
+        if (shifts)
+            shift = shifts[jj];
+        if (zooms)
+            zoom = zooms[jj];
+        for(kk = 0; kk < odimensions[jj]; kk++) {
+            double cc = (double)kk;
+            if (shifts)
+                cc += shift;
+            if (zooms)
+                cc *= zoom;
+            cc = map_coordinate(cc, idimensions[jj], mode);
+            if (cc > -1.0) {
+                int start;
+                if (zeros && zeros[jj])
+                    zeros[jj][kk] = 0;
+                if (order & 1) {
+                    start = (int)floor(cc) - order / 2;
+                } else {
+                    start = (int)floor(cc + 0.5) - order / 2;
+                }
+                offsets[jj][kk] = istrides[jj] * start;
+                if (start < 0 || start + order >= idimensions[jj]) {
+                    edge_offsets[jj][kk] = (maybelong*)malloc((order + 1) * sizeof(maybelong));
+                    if (!edge_offsets[jj][kk]) {
+                        PyErr_NoMemory();
+                        goto exit;
+                    }
+                    for(hh = 0; hh <= order; hh++) {
+                        int idx = start + hh;
+                         int len = idimensions[jj];
+                        if (len <= 1) {
+                            idx = 0;
+                        } else {
+                            int s2 = 2 * len - 2;
+                            if (idx < 0) {
+                                idx = s2 * (int)(-idx / s2) + idx;
+                                idx = idx <= 1 - len ? idx + s2 : -idx;
+                            } else if (idx >= len) {
+                                idx -= s2 * (int)(idx / s2);
+                                if (idx >= len)
+                                    idx = s2 - idx;
+                            }
+                        }
+                        edge_offsets[jj][kk][hh] = istrides[jj] * (idx - start);
+                    }
+                }
+                if (order > 0) {
+                    splvals[jj][kk] = (double*)malloc((order + 1) * sizeof(double));
+                    if (!splvals[jj][kk]) {
+                        PyErr_NoMemory();
+                        goto exit;
+                    }
+                    spline_coefficients(cc, order, splvals[jj][kk]);
+                }
+            } else {
+                zeros[jj][kk] = 1;
+            }
+        }
+    }
+
+    filter_size = 1;
+    for(jj = 0; jj < rank; jj++)
+        filter_size *= order + 1;
+    idxs = (maybelong*)malloc(filter_size * sizeof(idxs));
+    if (!idxs) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+
+    /* store all coordinates and offsets with filter: */
+    fcoordinates = (maybelong*)malloc(rank * filter_size * sizeof(maybelong));
+    foffsets = (maybelong*)malloc(filter_size * sizeof(maybelong));
+    if (!fcoordinates || !foffsets) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+
+    for(jj = 0; jj < rank; jj++)
+        ftmp[jj] = 0;
+    kk = 0;
+    for(hh = 0; hh < filter_size; hh++) {
+        for(jj = 0; jj < rank; jj++)
+            fcoordinates[jj + hh * rank] = ftmp[jj];
+        foffsets[hh] = kk;
+        for(jj = rank - 1; jj >= 0; jj--) {
+            if (ftmp[jj] < order) {
+                ftmp[jj]++;
+                kk += istrides[jj];
+                break;
+            } else {
+                ftmp[jj] = 0;
+                kk -= istrides[jj] * order;
+            }
+        }
+    }
+    size = 1;
+    for(qq = 0; qq < output->nd; qq++)
+        size *= output->dimensions[qq];
+    for(kk = 0; kk < size; kk++) {
+        double t = 0.0;
+        int edge = 0, oo = 0, zero = 0;
+
+        for(hh = 0; hh < rank; hh++) {
+            if (zeros && zeros[hh][io.coordinates[hh]]) {
+                /* we use constant border condition */
+                zero = 1;
+                break;
+            }
+            oo += offsets[hh][io.coordinates[hh]];
+            if (edge_offsets[hh][io.coordinates[hh]])
+                edge = 1;
+        }
+
+        if (!zero) {
+            maybelong *ff = fcoordinates;
+            for(hh = 0; hh < filter_size; hh++) {
+                int idx = 0;
+                if (edge) {
+                        /* use precalculated edge offsets: */
+                    for(jj = 0; jj < rank; jj++) {
+                        if (edge_offsets[jj][io.coordinates[jj]])
+                            idx += edge_offsets[jj][io.coordinates[jj]][ff[jj]];
+                        else
+                            idx += ff[jj] * istrides[jj];
+                    }
+                    idx += oo;
+                } else {
+                    /* use normal offsets: */
+                    idx += oo + foffsets[hh];
+                }
+                idxs[hh] = idx;
+                ff += rank;
+            }
+        }
+        if (!zero) {
+            maybelong *ff = fcoordinates;
+            t = 0.0;
+            for(hh = 0; hh < filter_size; hh++) {
+                double coeff = 0.0;
+                switch(input->descr->type_num) {
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Bool);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt8);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt16);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt32);
+#if HAS_UINT64
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], UInt64);
+#endif
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int8);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int16);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int32);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Int64);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Float32);
+                    CASE_INTERP_COEFF(coeff, pi, idxs[hh], Float64);
+                default:
+                    PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                    goto exit;
+                }
+                /* calculate interpolated value: */
+                for(jj = 0; jj < rank; jj++)
+                    if (order > 0)
+                        coeff *= splvals[jj][io.coordinates[jj]][ff[jj]];
+                t += coeff;
+                ff += rank;
+            }
+        } else {
+            t = cval;
+        }
+        /* store output: */
+        switch (output->descr->type_num) {
+            CASE_INTERP_OUT(po, t, Bool);
+            CASE_INTERP_OUT_UINT(po, t, UInt8, 0, MAX_UINT8);
+            CASE_INTERP_OUT_UINT(po, t, UInt16, 0, MAX_UINT16);
+            CASE_INTERP_OUT_UINT(po, t, UInt32, 0, MAX_UINT32);
+#if HAS_UINT64
+            /* FIXME */
+            CASE_INTERP_OUT_UINT(po, t, UInt64, 0, MAX_UINT32);
+#endif
+            CASE_INTERP_OUT_INT(po, t, Int8, MIN_INT8, MAX_INT8);
+            CASE_INTERP_OUT_INT(po, t, Int16, MIN_INT16, MAX_INT16);
+            CASE_INTERP_OUT_INT(po, t, Int32, MIN_INT32, MAX_INT32);
+            CASE_INTERP_OUT_INT(po, t, Int64, MIN_INT64, MAX_INT64);
+            CASE_INTERP_OUT(po, t, Float32);
+            CASE_INTERP_OUT(po, t, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        NI_ITERATOR_NEXT(io, po);
+    }
+
+ exit:
+    if (zeros) {
+        for(jj = 0; jj < rank; jj++)
+            if (zeros[jj])
+                free(zeros[jj]);
+        free(zeros);
+    }
+    if (offsets) {
+        for(jj = 0; jj < rank; jj++)
+            if (offsets[jj])
+                free(offsets[jj]);
+        free(offsets);
+    }
+    if (splvals) {
+        for(jj = 0; jj < rank; jj++) {
+            if (splvals[jj]) {
+                for(hh = 0; hh < odimensions[jj]; hh++)
+                    if (splvals[jj][hh])
+                        free(splvals[jj][hh]);
+                free(splvals[jj]);
+            }
+        }
+        free(splvals);
+    }
+    if (edge_offsets) {
+        for(jj = 0; jj < rank; jj++) {
+            if (edge_offsets[jj]) {
+                for(hh = 0; hh < odimensions[jj]; hh++)
+                    if (edge_offsets[jj][hh])
+                        free(edge_offsets[jj][hh]);
+                free(edge_offsets[jj]);
+            }
+        }
+        free(edge_offsets);
+    }
+    if (foffsets)
+        free(foffsets);
+    if (fcoordinates)
+        free(fcoordinates);
+    if (idxs)
+        free(idxs);
+    return PyErr_Occurred() ? 0 : 1;
+}

Added: branches/Interpolate1D/ndimage/ni_interpolation.h
===================================================================
--- branches/Interpolate1D/ndimage/ni_interpolation.h	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/ni_interpolation.h	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,43 @@
+/* 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 NI_INTERPOLATION_H
+#define NI_INTERPOLATION_H
+
+int NI_SplineFilter1D(PyArrayObject*, int, int, PyArrayObject*);
+int NI_GeometricTransform(PyArrayObject*, int (*)(maybelong*, double*, int, int,
+                                                    void*), void*, PyArrayObject*, PyArrayObject*,
+                                                    PyArrayObject*, PyArrayObject*, int, int,
+                                                    double);
+int NI_ZoomShift(PyArrayObject*, PyArrayObject*, PyArrayObject*,
+                                 PyArrayObject*, int, int, double);
+
+#endif

Added: branches/Interpolate1D/ndimage/ni_measure.c
===================================================================
--- branches/Interpolate1D/ndimage/ni_measure.c	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/ni_measure.c	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,1197 @@
+/* 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_measure.h"
+#include <stdlib.h>
+#include <math.h>
+#include <float.h>
+#include <assert.h>
+
+typedef struct {
+    Int32 index1, index2;
+    void* next;
+} _index_pair;
+
+#define CASE_LABEL(_p, _pi, _type) \
+case t ## _type:                   \
+    *_p = *(_type*)_pi ? -1 : 0;     \
+    break
+
+int NI_Label(PyArrayObject* input, PyArrayObject* strct,
+                         maybelong *max_label, PyArrayObject* output)
+{
+    int kk;
+    maybelong jj, ll, ssize, size, filter_size, *offsets = NULL;
+    maybelong mask_value, *oo;
+    Bool *ps, *footprint = NULL;
+    char *pi, *po;
+    Int32 index = 0, *index_map = NULL;
+    NI_FilterIterator fi;
+    NI_Iterator ii, io;
+    _index_pair *pairs = NULL;
+
+    /* structure size */
+    ssize = 1;
+    for(kk = 0; kk < strct->nd; kk++)
+        ssize *= strct->dimensions[kk];
+    /* we only use the first half of the structure data, so we make a
+         temporary structure for use with the filter functions: */
+    footprint = (Bool*)malloc(ssize * sizeof(Bool));
+    if (!footprint) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    ps = (Bool*)PyArray_DATA(strct);
+    filter_size = 0;
+    for(jj = 0; jj < ssize / 2; jj++) {
+        footprint[jj] = ps[jj];
+        if (ps[jj])
+            ++filter_size;
+    }
+    for(jj = ssize / 2; jj < ssize; jj++)
+        footprint[jj] = 0;
+    /* get data and size */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(kk = 0; kk < output->nd; kk++)
+        size *= output->dimensions[kk];
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+    /* set all elements in the output corresponding to non-zero elements
+         in input to -1: */
+    for(jj = 0; jj < size; jj++) {
+        Int32 *p = (Int32*)po;
+        switch (input->descr->type_num) {
+        CASE_LABEL(p, pi, Bool);
+        CASE_LABEL(p, pi, UInt8);
+        CASE_LABEL(p, pi, UInt16);
+        CASE_LABEL(p, pi, UInt32);
+#if HAS_UINT64
+        CASE_LABEL(p, pi, UInt64);
+#endif
+        CASE_LABEL(p, pi, Int8);
+        CASE_LABEL(p, pi, Int16);
+        CASE_LABEL(p, pi, Int32);
+        CASE_LABEL(p, pi, Int64);
+        CASE_LABEL(p, pi, Float32);
+        CASE_LABEL(p, pi, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        NI_ITERATOR_NEXT2(ii, io, pi, po);
+    }
+
+    /* calculate the filter offsets: */
+    if (!NI_InitFilterOffsets(output, footprint, strct->dimensions, NULL,
+                                                    NI_EXTEND_CONSTANT, &offsets, &mask_value, NULL))
+        goto exit;
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(input->nd, strct->dimensions, filter_size,
+                                                                                     input->dimensions, NULL, &fi))
+        goto exit;
+    /* reset output iterator: */
+    NI_ITERATOR_RESET(io);
+    po = (void *)PyArray_DATA(output);
+    /* iterator over the elements: */
+    oo = offsets;
+    for(jj = 0; jj < size; jj++) {
+        if (*(Int32*)po < 0) {
+            Int32 neighbor = 0;
+            /* iterate over structuring element: */
+            for(ll = 0; ll < filter_size; ll++) {
+                int offset = oo[ll];
+                if (offset != mask_value) {
+                    Int32 tt = *(Int32*)(po + offset);
+                    if (tt > 0) {
+                        /* this element is next to an already found object: */
+                        if (neighbor && neighbor != tt) {
+                            /* we have two objects that must be merged later: */
+                            _index_pair* tp = (_index_pair*)malloc(sizeof(_index_pair));
+                            if (!tp) {
+                                PyErr_NoMemory();
+                                goto exit;
+                            }
+                            tp->next = pairs;
+                            /* the pairs must be ordered: */
+                            if (neighbor < tt) {
+                                tp->index1 = neighbor;
+                                tp->index2 = tt;
+                            } else {
+                                tp->index1 = tt;
+                                tp->index2 = neighbor;
+                            }
+                            pairs = tp;
+                        } else {
+                            neighbor = tt;
+                        }
+                    }
+                }
+            }
+            if (neighbor) {
+                /* this point belongs to an existing object */
+                *(Int32*)po = neighbor;
+            } else {
+                /* this may be a new object: */
+                *(Int32*)po = ++index;
+            }
+        }
+        NI_FILTER_NEXT(fi, io, oo, po);
+    }
+    *max_label = index;
+    /* merge any touching objects: */
+    if (pairs) {
+        Int32 counter;
+        index_map = (Int32*)malloc(index * sizeof(Int32));
+        if (!index_map) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+        for(jj = 0; jj < index; jj++)
+            index_map[jj] = (Int32)jj;
+        while (pairs) {
+            Int32 idx1 = pairs->index1 - 1;
+            Int32 idx2 = pairs->index2 - 1;
+            if (index_map[idx2] == idx1 || index_map[idx2] == idx2) {
+                /* if this pair was already processed, or if idx2 was not
+                     mapped yet, we delete this pair and map idx2 to idx1: */
+                _index_pair *tp = pairs;
+                pairs = tp->next;
+                free(tp);
+                index_map[idx2] = idx1;
+            } else {
+                /* idx2 was already mapped, therefore we find what it was
+                     mapped to and change the current pair to the result of that
+                     and idx1. Since the pair is not destroyed, it will be
+                     re-processed with the adapted values.  */
+                idx2 = index_map[idx2];
+                /* keep the pairs ordered: */
+                if (idx1 < idx2) {
+                    pairs->index1 = idx1 + 1;
+                    pairs->index2 = idx2 + 1;
+                } else {
+                    pairs->index1 = idx2 + 1;
+                    pairs->index2 = idx1 + 1;
+                }
+            }
+        }
+        for(jj = 0; jj < index; jj++) {
+            /* if the current index maps to a index that is also mapped,
+                 change it to map to that index. Since an index always maps to
+                 a lower index or to itself, this will make sure that at the
+                 end all indices map to an unmapped index. */
+            if (index_map[index_map[jj]] < index_map[jj])
+                index_map[jj] = index_map[index_map[jj]];
+        }
+        /* renumber the indices that are not mapped: */
+        counter = 0;
+        for(jj = 0; jj < index; jj++)
+            if (index_map[jj] == jj)
+                index_map[jj] = ++counter;
+            else
+                index_map[jj] = index_map[index_map[jj]];
+    }
+
+    /* relabel the output if we merged some objects: */
+    if (index_map) {
+        *max_label = 0;
+        NI_ITERATOR_RESET(io);
+        po = (void *)PyArray_DATA(output);
+        for(jj = 0; jj < size; jj++) {
+            Int32 p = *(Int32*)po;
+            if (p > 0 )
+                *(Int32*)po = index_map[p - 1];
+            if (*(Int32*)po > *max_label)
+                *max_label = *(Int32*)po;
+            NI_ITERATOR_NEXT(io, po);
+        }
+    }
+ exit:
+    if (offsets) free(offsets);
+    if (index_map) free(index_map);
+    while (pairs) {
+        _index_pair *tp = pairs;
+        pairs = (_index_pair*)pairs->next;
+        free(tp);
+    }
+    if (footprint)
+        free(footprint);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+#define CASE_FIND_OBJECT_POINT(_pi, _regions, _rank, _dimensions, \
+                                                             _max_label, _ii, _type)            \
+case t ## _type:                                                  \
+{                                                                 \
+    int _kk;                                                        \
+    maybelong _sindex = *(_type*)_pi - 1;                           \
+    if (_sindex >= 0 && _sindex < _max_label) {                     \
+        if (_rank > 0) {                                              \
+            _sindex *= 2 * _rank;                                       \
+            if (_regions[_sindex] < 0) {                                \
+                for(_kk = 0; _kk < _rank; _kk++) {                        \
+                    maybelong _cc = _ii.coordinates[_kk];                   \
+                    _regions[_sindex + _kk] = _cc;                          \
+                    _regions[_sindex + _kk + _rank] = _cc + 1;              \
+                }                                                         \
+            } else {                                                    \
+                for(_kk = 0; _kk < _rank; _kk++) {                        \
+                    maybelong _cc = _ii.coordinates[_kk];                   \
+                    if (_cc < _regions[_sindex + _kk])                      \
+                        _regions[_sindex + _kk] = _cc;                        \
+                    if (_cc + 1 > _regions[_sindex + _kk + _rank])          \
+                        _regions[_sindex + _kk + _rank] = _cc + 1;            \
+                }                                                         \
+            }                                                           \
+        } else {                                                      \
+            _regions[_sindex] = 1;                                      \
+        }                                                             \
+    }                                                               \
+}                                                                 \
+break
+
+int NI_FindObjects(PyArrayObject* input, maybelong max_label,
+                                     maybelong* regions)
+{
+    int kk;
+    maybelong size, jj;
+    NI_Iterator ii;
+    char *pi;
+
+    /* get input data, size and iterator: */
+    pi = (void *)PyArray_DATA(input);
+    size = 1;
+    for(kk = 0; kk < input->nd; kk++)
+        size *= input->dimensions[kk];
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    if (input->nd > 0) {
+        for(jj = 0; jj < 2 * input->nd * max_label; jj++)
+            regions[jj] = -1;
+    } else {
+        for(jj = 0; jj < max_label; jj++)
+            regions[jj] = -1;
+    }
+    /* iterate over all points: */
+    for(jj = 0 ; jj < size; jj++) {
+        switch (input->descr->type_num) {
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii,  Bool);
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, UInt8);
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, UInt16);
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, UInt32);
+#if HAS_UINT64
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, UInt64);
+#endif
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, Int8);
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, Int16);
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, Int32);
+        CASE_FIND_OBJECT_POINT(pi, regions, input->nd, input->dimensions,
+                                                     max_label, ii, Int64);
+            break;
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        NI_ITERATOR_NEXT(ii, pi);
+    }
+ exit:
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+
+/* macro to get input value: */
+#if HAS_UINT64
+#define NI_GET_VALUE(_pi, _v, _type)                                  \
+{                                                                     \
+    switch(_type) {                                                     \
+    case tBool:                                                         \
+        _v = (*(Bool*)_pi) != 0;                                          \
+        break;                                                            \
+    case tUInt8:                                                        \
+        _v = *(UInt8*)_pi;                                                \
+        break;                                                            \
+    case tUInt16:                                                       \
+        _v = *(UInt16*)_pi;                                               \
+        break;                                                            \
+    case tUInt32:                                                       \
+        _v = *(UInt32*)_pi;                                               \
+        break;                                                            \
+    case tInt8:                                                         \
+        _v = *(Int8*)_pi;                                                 \
+        break;                                                            \
+    case tInt16:                                                        \
+        _v = *(Int16*)_pi;                                                \
+        break;                                                            \
+    case tInt32:                                                        \
+        _v = *(Int32*)_pi;                                                \
+        break;                                                            \
+    case tInt64:                                                        \
+        _v = *(Int64*)_pi;                                                \
+        break;                                                            \
+    case tUInt64:                                                       \
+        _v = *(UInt64*)_pi;                                               \
+        break;                                                            \
+    case tFloat32:                                                      \
+        _v = *(Float32*)_pi;                                              \
+        break;                                                            \
+    case tFloat64:                                                      \
+        _v = *(Float64*)_pi;                                              \
+        break;                                                            \
+    default:                                                            \
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported"); \
+            return 0;                                                       \
+    }                                                                   \
+}
+#else
+#define NI_GET_VALUE(_pi, _v, _type)                                  \
+{                                                                     \
+    switch(_type) {                                                     \
+    case tBool:                                                         \
+        _v = (*(Bool*)_pi) != 0;                                          \
+        break;                                                            \
+    case tUInt8:                                                        \
+        _v = *(UInt8*)_pi;                                                \
+        break;                                                            \
+    case tUInt16:                                                       \
+        _v = *(UInt16*)_pi;                                               \
+        break;                                                            \
+    case tUInt32:                                                       \
+        _v = *(UInt32*)_pi;                                               \
+        break;                                                            \
+    case tInt8:                                                         \
+        _v = *(Int8*)_pi;                                                 \
+        break;                                                            \
+    case tInt16:                                                        \
+        _v = *(Int16*)_pi;                                                \
+        break;                                                            \
+    case tInt32:                                                        \
+        _v = *(Int32*)_pi;                                                \
+        break;                                                            \
+    case tInt64:                                                        \
+        _v = *(Int64*)_pi;                                                \
+        break;                                                            \
+    case tFloat32:                                                      \
+        _v = *(Float32*)_pi;                                              \
+        break;                                                            \
+    case tFloat64:                                                      \
+        _v = *(Float64*)_pi;                                              \
+        break;                                                            \
+    default:                                                            \
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported"); \
+            return 0;                                                       \
+    }                                                                   \
+}
+#endif
+
+/* macro to get label value: */
+#if HAS_UINT64
+#define NI_GET_LABEL(_pm, _label, _type)                              \
+{                                                                     \
+    if (_pm) {                                                          \
+        switch(_type) {                                                   \
+        case tBool:                                                       \
+            _label = *(Bool*)_pm;                                           \
+            break;                                                          \
+        case tUInt8:                                                      \
+            _label = *(UInt8*)_pm;                                          \
+            break;                                                          \
+        case tUInt16:                                                     \
+            _label = *(UInt16*)_pm;                                         \
+            break;                                                          \
+        case tUInt32:                                                     \
+            _label = *(UInt32*)_pm;                                         \
+            break;                                                          \
+        case tUInt64:                                                     \
+            _label = *(UInt64*)_pm;                                         \
+            break;                                                          \
+        case tInt8:                                                       \
+            _label = *(Int8*)_pm;                                           \
+            break;                                                          \
+        case tInt16:                                                      \
+            _label = *(Int16*)_pm;                                          \
+            break;                                                          \
+        case tInt32:                                                      \
+            _label = *(Int32*)_pm;                                          \
+             break;                                                         \
+        case tInt64:                                                      \
+            _label = *(Int64*)_pm;                                          \
+             break;                                                         \
+        case tFloat32:                                                    \
+            _label = *(Float32*)_pm;                                        \
+            break;                                                          \
+        case tFloat64:                                                    \
+            _label = *(Float64*)_pm;                                        \
+            break;                                                          \
+        default:                                                          \
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported"); \
+            return 0;                                                       \
+        }                                                                 \
+    }                                                                   \
+}
+#else
+#define NI_GET_LABEL(_pm, _label, _type)                              \
+{                                                                     \
+    if (_pm) {                                                          \
+        switch(_type) {                                                   \
+        case tBool:                                                       \
+            _label = *(Bool*)_pm;                                           \
+            break;                                                          \
+        case tUInt8:                                                      \
+            _label = *(UInt8*)_pm;                                          \
+            break;                                                          \
+        case tUInt16:                                                     \
+            _label = *(UInt16*)_pm;                                         \
+            break;                                                          \
+        case tUInt32:                                                     \
+            _label = *(UInt32*)_pm;                                         \
+            break;                                                          \
+        case tInt8:                                                       \
+            _label = *(Int8*)_pm;                                           \
+            break;                                                          \
+        case tInt16:                                                      \
+            _label = *(Int16*)_pm;                                          \
+            break;                                                          \
+        case tInt32:                                                      \
+            _label = *(Int32*)_pm;                                          \
+             break;                                                         \
+        case tInt64:                                                      \
+            _label = *(Int64*)_pm;                                          \
+             break;                                                         \
+        case tFloat32:                                                    \
+            _label = *(Float32*)_pm;                                        \
+            break;                                                          \
+        case tFloat64:                                                    \
+            _label = *(Float64*)_pm;                                        \
+            break;                                                          \
+        default:                                                          \
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported"); \
+            return 0;                                                       \
+        }                                                                 \
+    }                                                                   \
+}
+#endif
+
+int NI_Statistics(PyArrayObject *input, PyArrayObject *labels,
+    maybelong min_label, maybelong max_label, maybelong *indices,
+    maybelong n_results, double *sum, maybelong *total, double *variance,
+    double *minimum, double *maximum, maybelong* min_pos, maybelong* max_pos)
+{
+    char *pi = NULL, *pm = NULL;
+    NI_Iterator ii, mi;
+    maybelong jj, size, idx = 0, label = 1, doit = 1;
+    int qq;
+
+    /* input iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        return 0;
+    /* input data: */
+    pi = (void *)PyArray_DATA(input);
+    if (labels) {
+        if (!NI_InitPointIterator(labels, &mi))
+            return 0;
+        pm = (void *)PyArray_DATA(labels);
+    }
+    /* input size: */
+    size = 1;
+    for(qq = 0; qq < input->nd; qq++)
+        size *= input->dimensions[qq];
+    for(jj = 0; jj < n_results; jj++) {
+        if (sum)
+            sum[jj] = 0.0;
+        if (total)
+            total[jj] = 0;
+        if (variance)
+            variance[jj] = 0;
+        if (minimum)
+            minimum[jj] = DBL_MAX;
+        if (maximum)
+            maximum[jj] = -DBL_MAX;
+        if (min_pos)
+            min_pos[jj] = 0;
+        if (max_pos)
+            max_pos[jj] = 0;
+    }
+    /* iterate over array: */
+    for(jj = 0; jj < size; jj++) {
+        NI_GET_LABEL(pm, label, labels->descr->type_num);
+        if (min_label >= 0) {
+            if (label >= min_label && label <= max_label) {
+                idx = indices[label - min_label];
+                doit = idx >= 0;
+            } else {
+                doit = 0;
+            }
+        } else {
+            doit = label != 0;
+        }
+        if (doit) {
+            double val;
+            NI_GET_VALUE(pi, val, input->descr->type_num);
+            if (sum)
+                sum[idx] += val;
+            if (total)
+                total[idx]++;
+            if (minimum && val < minimum[idx]) {
+                minimum[idx] = val;
+                if (min_pos)
+                    min_pos[idx] = jj;
+            }
+            if (maximum && (val > maximum[idx])) {
+                maximum[idx] = val;
+                if (max_pos)
+                    max_pos[idx] = jj;
+            }
+        }
+        if (labels) {
+            NI_ITERATOR_NEXT2(ii, mi, pi, pm);
+        } else {
+            NI_ITERATOR_NEXT(ii, pi);
+        }
+    }
+    if (minimum) {
+        for(jj = 0; jj < n_results; jj++) {
+            if (!(minimum[jj] < DBL_MAX))
+                minimum[jj] = 0.0;
+        }
+    }
+    if (maximum) {
+        for(jj = 0; jj < n_results; jj++) {
+            if (!(maximum[jj] > -DBL_MAX))
+                maximum[jj] = 0.0;
+        }
+    }
+    if (variance) {
+        int do_var = 0;
+        for(jj = 0; jj < n_results; jj++)
+            if (total[jj] > 1) {
+                do_var = 1;
+                break;
+            }
+        if (do_var) {
+            /* reset input iterator: */
+            NI_ITERATOR_RESET(ii);
+            pi = (void *)PyArray_DATA(input);
+            if (labels) {
+                /* reset label iterator: */
+                NI_ITERATOR_RESET(mi);
+                pm = (void *)PyArray_DATA(labels);
+            }
+            for(jj = 0; jj < size; jj++) {
+                NI_GET_LABEL(pm, label, labels->descr->type_num);
+                if (min_label >= 0) {
+                    if (label >= min_label && label <= max_label) {
+                        idx = indices[label - min_label];
+                        doit = idx >= 0;
+                    } else {
+                        doit = 0;
+                    }
+                } else {
+                    doit = label != 0;
+                }
+                if (doit) {
+                    double val;
+                    NI_GET_VALUE(pi, val, input->descr->type_num);
+                    val = val - sum[idx] / total[idx];
+                    variance[idx] += val * val;
+                }
+                if (labels) {
+                    NI_ITERATOR_NEXT2(ii, mi, pi, pm);
+                } else {
+                    NI_ITERATOR_NEXT(ii, pi);
+                }
+            }
+            for(jj = 0; jj < n_results; jj++)
+                variance[jj] = (total[jj] > 1 ?
+                                                variance[jj] / (total[jj] - 1) : 0.0);
+        }
+    }
+    return 1;
+}
+
+
+int NI_CenterOfMass(PyArrayObject *input, PyArrayObject *labels,
+                            maybelong min_label, maybelong max_label, maybelong *indices,
+                            maybelong n_results, double *center_of_mass)
+{
+    char *pi = NULL, *pm = NULL;
+    NI_Iterator ii, mi;
+    maybelong jj, kk, size, idx = 0, label = 1, doit = 1;
+    double *sum = NULL;
+    int qq;
+
+    /* input iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* input data: */
+    pi = (void *)PyArray_DATA(input);
+    if (labels) {
+        if (!NI_InitPointIterator(labels, &mi))
+            goto exit;
+        pm = (void *)PyArray_DATA(labels);
+    }
+    /* input size: */
+    size = 1;
+    for(qq = 0; qq < input->nd; qq++)
+        size *= input->dimensions[qq];
+    sum = (double*)malloc(n_results * sizeof(double));
+    if (!sum) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < n_results; jj++) {
+        sum[jj] = 0.0;
+        for(kk = 0; kk < input->nd; kk++)
+            center_of_mass[jj * input->nd + kk] = 0.0;
+    }
+    /* iterate over array: */
+    for(jj = 0; jj < size; jj++) {
+        NI_GET_LABEL(pm, label, labels->descr->type_num);
+        if (min_label >= 0) {
+            if (label >= min_label && label <= max_label) {
+                idx = indices[label - min_label];
+                doit = idx >= 0;
+            } else {
+                doit = 0;
+            }
+        } else {
+            doit = label != 0;
+        }
+        if (doit) {
+            double val;
+            NI_GET_VALUE(pi, val, input->descr->type_num);
+            sum[idx] += val;
+            for(kk = 0; kk < input->nd; kk++)
+                center_of_mass[idx * input->nd + kk] += val * ii.coordinates[kk];
+        }
+        if (labels) {
+            NI_ITERATOR_NEXT2(ii, mi, pi, pm);
+        } else {
+            NI_ITERATOR_NEXT(ii, pi);
+        }
+    }
+    for(jj = 0; jj < n_results; jj++)
+        for(kk = 0; kk < input->nd; kk++)
+            center_of_mass[jj * input->nd + kk] /= sum[jj];
+ exit:
+    if (sum)
+        free(sum);
+    return  PyErr_Occurred() == NULL;
+}
+
+
+int NI_Histogram(PyArrayObject *input, PyArrayObject *labels,
+                            maybelong min_label, maybelong max_label, maybelong *indices,
+                            maybelong n_results, PyArrayObject **histograms,
+                            double min, double max, maybelong nbins)
+{
+    char *pi = NULL, *pm = NULL;
+    NI_Iterator ii, mi;
+    maybelong jj, kk, size, idx = 0, label = 1, doit = 1;
+    Int32 **ph = NULL;
+    double bsize;
+    int qq;
+
+    /* input iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* input data: */
+    pi = (void *)PyArray_DATA(input);
+    if (labels) {
+        if (!NI_InitPointIterator(labels, &mi))
+            goto exit;
+        pm = (void *)PyArray_DATA(labels);
+    }
+    ph = (Int32**)malloc(n_results * sizeof(Int32*));
+    if (!ph) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < n_results; jj++) {
+            ph[jj] = (Int32*)PyArray_DATA(histograms[jj]);
+            for(kk = 0; kk < nbins; kk++)
+                    ph[jj][kk] = 0;
+    }
+    bsize = (max - min) / (double)nbins;
+    /* input size: */
+    size = 1;
+    for(qq = 0; qq < input->nd; qq++)
+        size *= input->dimensions[qq];
+    /* iterate over array: */
+    for(jj = 0; jj < size; jj++) {
+        NI_GET_LABEL(pm, label, labels->descr->type_num);
+        if (min_label >= 0) {
+            if (label >= min_label && label <= max_label) {
+                idx = indices[label - min_label];
+                doit = idx >= 0;
+            } else {
+                doit = 0;
+            }
+        } else {
+            doit = label != 0;
+        }
+        if (doit) {
+            int bin;
+            double val;
+            NI_GET_VALUE(pi, val, input->descr->type_num);
+            if (val >= min && val < max) {
+                bin = (int)((val - min) / bsize);
+                ++(ph[idx][bin]);
+            }
+        }
+        if (labels) {
+            NI_ITERATOR_NEXT2(ii, mi, pi, pm);
+        } else {
+            NI_ITERATOR_NEXT(ii, pi);
+        }
+    }
+ exit:
+    if (ph)
+        free(ph);
+    return  PyErr_Occurred() == NULL;
+}
+
+#define WS_GET_INDEX(_index, _c_strides, _b_strides, _rank, _out, \
+                                         _contiguous, _type)                          \
+do {                                                              \
+    if (_contiguous) {                                              \
+        _out = _index * sizeof(_type);                                \
+    } else {                                                        \
+        int _qq;                                                      \
+        maybelong _cc, _idx = _index;                                 \
+        _out = 0;                                                     \
+        for (_qq = 0; _qq < _rank; _qq++) {                           \
+            _cc = _idx / _c_strides[_qq];                               \
+            _idx -= _cc * _c_strides[_qq];                              \
+            _out += _b_strides[_qq] * _cc;                              \
+        }                                                             \
+    }                                                               \
+} while(0)
+
+#define CASE_GET_INPUT(_ival, _pi, _type) \
+case t ## _type:                          \
+    _ival = *((_type*)_pi);                 \
+    break
+
+#define CASE_GET_LABEL(_label, _pm, _type) \
+case t ## _type:                           \
+    _label = *(_type*)_pm;                   \
+    break
+
+#define CASE_PUT_LABEL(_label, _pl, _type) \
+case t ## _type:                           \
+    *((_type*)_pl) = _label;                 \
+    break
+
+#define CASE_WINDEX1(_v_index, _p_index, _strides, _istrides, _irank,  \
+                                         _icont, _p_idx, _v_idx, _pi, _vval, _pval, _type) \
+case t ## _type:                                                       \
+    WS_GET_INDEX(_v_index, _strides, _istrides, _irank, _p_idx, _icont,  \
+                             _type);                                                 \
+    WS_GET_INDEX(_p_index, _strides, _istrides, _irank, _v_idx, _icont,  \
+                             _type);                                                 \
+    _vval = *(_type*)(_pi + _v_idx);                                     \
+    _pval = *(_type*)(_pi + _p_idx);                                     \
+    break
+
+#define CASE_WINDEX2(_v_index, _strides, _ostrides, _irank, _idx, \
+                                         _ocont, _label, _pl, _type)                  \
+case t ## _type:                                                  \
+    WS_GET_INDEX(_v_index, _strides, _ostrides, _irank, _idx,       \
+                             _ocont, _type);                                    \
+    _label = *(_type*)(_pl + _idx);                                 \
+    break
+
+#define CASE_WINDEX3(_p_index, _strides, _ostrides, _irank, _idx, \
+                                         _ocont, _label, _pl, _type)                  \
+case t ## _type:                                                  \
+    WS_GET_INDEX(_p_index, _strides, _ostrides, _irank, _idx,       \
+                             _ocont, _type);                                    \
+    *(_type*)(_pl + _idx) = _label;                                 \
+break
+
+#define DONE_TYPE UInt8
+#define COST_TYPE UInt16
+#define WS_MAXDIM 7
+
+typedef struct {
+    maybelong index;
+    COST_TYPE cost;
+    void *next, *prev;
+    DONE_TYPE done;
+} NI_WatershedElement;
+
+int NI_WatershedIFT(PyArrayObject* input, PyArrayObject* markers,
+                                        PyArrayObject* strct, PyArrayObject* output)
+{
+    char *pl, *pm, *pi;
+    int ll;
+    maybelong size, jj, hh, kk, maxval;
+    maybelong strides[WS_MAXDIM], coordinates[WS_MAXDIM];
+    maybelong *nstrides = NULL, nneigh, ssize;
+    int i_contiguous, o_contiguous;
+    NI_WatershedElement *temp = NULL, **first = NULL, **last = NULL;
+    Bool *ps = NULL;
+    NI_Iterator mi, ii, li;
+
+    i_contiguous = PyArray_ISCONTIGUOUS(input);
+    o_contiguous = PyArray_ISCONTIGUOUS(output);
+    ssize = 1;
+    for(ll = 0; ll < strct->nd; ll++)
+        ssize *= strct->dimensions[ll];
+    if (input->nd > WS_MAXDIM) {
+        PyErr_SetString(PyExc_RuntimeError, "too many dimensions");
+        goto exit;
+    }
+    size = 1;
+    for(ll = 0; ll < input->nd; ll++)
+        size *= input->dimensions[ll];
+    /* Storage for the temporary queue data. */
+    temp = (NI_WatershedElement*)malloc(size * sizeof(NI_WatershedElement));
+    if (!temp) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    pi = (void *)PyArray_DATA(input);
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* Initialization and find the maximum of the input. */
+    maxval = 0;
+    for(jj = 0; jj < size; jj++) {
+        int ival = 0;
+        switch(input->descr->type_num) {
+        CASE_GET_INPUT(ival, pi, UInt8);
+        CASE_GET_INPUT(ival, pi, UInt16);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        temp[jj].index = jj;
+        temp[jj].done = 0;
+        if (ival > maxval)
+            maxval = ival;
+        NI_ITERATOR_NEXT(ii, pi);
+    }
+    pi = (void *)PyArray_DATA(input);
+    /* Allocate and initialize the storage for the queue. */
+    first = (NI_WatershedElement**)malloc((maxval + 1) *
+                                                                                sizeof(NI_WatershedElement*));
+    last = (NI_WatershedElement**)malloc((maxval + 1) *
+                                                                             sizeof(NI_WatershedElement*));
+    if (!first || !last) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(hh = 0; hh <= maxval; hh++) {
+        first[hh] = NULL;
+        last[hh] = NULL;
+    }
+    if (!NI_InitPointIterator(markers, &mi))
+        goto exit;
+    if (!NI_InitPointIterator(output, &li))
+        goto exit;
+    pm = (void *)PyArray_DATA(markers);
+    pl = (void *)PyArray_DATA(output);
+    /* initialize all nodes */
+    for(ll = 0; ll < input->nd; ll++)
+        coordinates[ll] = 0;
+    for(jj = 0; jj < size; jj++) {
+        /* get marker */
+        int label = 0;
+        switch(markers->descr->type_num) {
+        CASE_GET_LABEL(label, pm, UInt8);
+        CASE_GET_LABEL(label, pm, UInt16);
+        CASE_GET_LABEL(label, pm, UInt32);
+#if HAS_UINT64
+        CASE_GET_LABEL(label, pm, UInt64);
+#endif
+        CASE_GET_LABEL(label, pm, Int8);
+        CASE_GET_LABEL(label, pm, Int16);
+        CASE_GET_LABEL(label, pm, Int32);
+        CASE_GET_LABEL(label, pm, Int64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        switch(output->descr->type_num) {
+        CASE_PUT_LABEL(label, pl, UInt8);
+        CASE_PUT_LABEL(label, pl, UInt16);
+        CASE_PUT_LABEL(label, pl, UInt32);
+#if HAS_UINT64
+        CASE_PUT_LABEL(label, pl, UInt64);
+#endif
+        CASE_PUT_LABEL(label, pl, Int8);
+        CASE_PUT_LABEL(label, pl, Int16);
+        CASE_PUT_LABEL(label, pl, Int32);
+        CASE_PUT_LABEL(label, pl, Int64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        NI_ITERATOR_NEXT2(mi, li, pm, pl);
+        if (label != 0) {
+            /* This node is a marker */
+            temp[jj].cost = 0;
+            if (!first[0]) {
+                first[0] = &(temp[jj]);
+                first[0]->next = NULL;
+                first[0]->prev = NULL;
+                last[0] = first[0];
+            } else {
+                if (label > 0) {
+                    /* object markers are enqueued at the beginning, so they are
+                         processed first. */
+                    temp[jj].next = first[0];
+                    temp[jj].prev = NULL;
+                    first[0]->prev = &(temp[jj]);
+                    first[0] = &(temp[jj]);
+                } else {
+                    /* background markers are enqueued at the end, so they are
+                         processed after the object markers. */
+                    temp[jj].next = NULL;
+                    temp[jj].prev = last[0];
+                    last[0]->next = &(temp[jj]);
+                    last[0] = &(temp[jj]);
+                }
+            }
+        } else {
+            /* This node is not a marker */
+            temp[jj].cost = maxval + 1;
+            temp[jj].next = NULL;
+            temp[jj].prev = NULL;
+        }
+        for(ll = input->nd - 1; ll >= 0; ll--)
+            if (coordinates[ll] < input->dimensions[ll] - 1) {
+                coordinates[ll]++;
+                break;
+            } else {
+                coordinates[ll] = 0;
+            }
+    }
+
+    pl = (void *)PyArray_DATA(output);
+    ps = (Bool*)PyArray_DATA(strct);
+    nneigh = 0;
+    for (kk = 0; kk < ssize; kk++)
+        if (ps[kk] && kk != (ssize / 2))
+            ++nneigh;
+    nstrides = (maybelong*)malloc(nneigh * sizeof(maybelong));
+    if (!nstrides) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    strides[input->nd - 1] = 1;
+    for(ll = input->nd - 2; ll >= 0; ll--)
+        strides[ll] = input->dimensions[ll + 1] * strides[ll + 1];
+    for(ll = 0; ll < input->nd; ll++)
+        coordinates[ll] = -1;
+    for(kk = 0; kk < nneigh; kk++)
+        nstrides[kk] = 0;
+    jj = 0;
+    for(kk = 0; kk < ssize; kk++) {
+        if (ps[kk]) {
+            int offset = 0;
+            for(ll = 0; ll < input->nd; ll++)
+                offset += coordinates[ll] * strides[ll];
+            if (offset != 0)
+                nstrides[jj++] += offset;
+        }
+        for(ll = input->nd - 1; ll >= 0; ll--)
+            if (coordinates[ll] < 1) {
+                coordinates[ll]++;
+                break;
+            } else {
+                coordinates[ll] = -1;
+            }
+    }
+    /* Propagation phase: */
+    for(jj = 0; jj <= maxval; jj++) {
+        while (first[jj]) {
+            /* dequeue first element: */
+            NI_WatershedElement *v = first[jj];
+            first[jj] = first[jj]->next;
+            if (first[jj])
+                first[jj]->prev = NULL;
+            v->prev = NULL;
+            v->next = NULL;
+            /* Mark element as done: */
+            v->done = 1;
+            /* Iterate over the neighbors of the element: */
+            for(hh = 0; hh < nneigh; hh++) {
+                maybelong v_index = v->index, p_index = v->index, idx, cc;
+                int qq, outside = 0;
+                p_index += nstrides[hh];
+                /* check if the neighbor is within the extent of the array: */
+                idx = p_index;
+                for (qq = 0; qq < input->nd; qq++) {
+                    cc = idx / strides[qq];
+                    if (cc < 0 || cc >= input->dimensions[qq]) {
+                        outside = 1;
+                        break;
+                    }
+                    idx -= cc * strides[qq];
+                }
+                if (!outside) {
+                    NI_WatershedElement *p = &(temp[p_index]);
+                    if (!(p->done)) {
+                        /* If the neighbor was not processed yet: */
+                        int max, pval, vval, wvp, pcost, label, p_idx, v_idx;
+                        switch(input->descr->type_num) {
+                        CASE_WINDEX1(v_index, p_index, strides, input->strides,
+                                                 input->nd, i_contiguous, p_idx, v_idx, pi,
+                                                 vval, pval, UInt8);
+                        CASE_WINDEX1(v_index, p_index, strides, input->strides,
+                                                 input->nd, i_contiguous, p_idx, v_idx, pi,
+                                                 vval, pval, UInt16);
+                        default:
+                            PyErr_SetString(PyExc_RuntimeError,
+                                                            "data type not supported");
+                            goto exit;
+                        }
+                        /* Calculate cost: */
+                        wvp = pval - vval;
+                        if (wvp < 0)
+                            wvp = -wvp;
+                        /* Find the maximum of this cost and the current
+                             element cost: */
+                        pcost = p->cost;
+                        max = v->cost > wvp ? v->cost : wvp;
+                        if (max < pcost) {
+                            /* If this maximum is less than the neighbors cost,
+                                 adapt the cost and the label of the neighbor: */
+                            int idx;
+                            p->cost = max;
+                            switch(output->descr->type_num) {
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt8);
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt16);
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt32);
+#if HAS_UINT64
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt64);
+#endif
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int8);
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int16);
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int32);
+                            CASE_WINDEX2(v_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int64);
+                            default:
+                                PyErr_SetString(PyExc_RuntimeError,
+                                                                "data type not supported");
+                                goto exit;
+                            }
+                            switch(output->descr->type_num) {
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt8);
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt16);
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt32);
+#if HAS_UINT64
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, UInt64);
+#endif
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int8);
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int16);
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int32);
+                            CASE_WINDEX3(p_index, strides, output->strides, input->nd,
+                                                     idx, o_contiguous, label, pl, Int64);
+                            default:
+                                PyErr_SetString(PyExc_RuntimeError,
+                                                                "data type not supported");
+                                goto exit;
+                            }
+                            /* If the neighbor is in a queue, remove it: */
+                            if (p->next || p->prev) {
+                                NI_WatershedElement *prev = p->prev, *next = p->next;
+                                if (first[pcost] == p)
+                                    first[pcost] = next;
+                                if (last[pcost] == p)
+                                    last[pcost] = prev;
+                                if (prev)
+                                    prev->next = next;
+                                if (next)
+                                    next->prev = prev;
+                            }
+                            /* Insert the neighbor in the appropiate queue: */
+                            if (label < 0) {
+                                p->prev = last[max];
+                                p->next = NULL;
+                                if (last[max])
+                                    last[max]->next = p;
+                                last[max] = p;
+                                if (!first[max])
+                                    first[max] = p;
+                            } else {
+                                p->next = first[max];
+                                p->prev = NULL;
+                                if (first[max])
+                                    first[max]->prev = p;
+                                first[max] = p;
+                                if (!last[max])
+                                    last[max] = p;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+ exit:
+    if (temp)
+        free(temp);
+    if (first)
+        free(first);
+    if (last)
+        free(last);
+    if (nstrides)
+        free(nstrides);
+    return PyErr_Occurred() ? 0 : 1;
+}

Added: branches/Interpolate1D/ndimage/ni_measure.h
===================================================================
--- branches/Interpolate1D/ndimage/ni_measure.h	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/ni_measure.h	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,59 @@
+/* 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 NI_MEASURE_H
+#define NI_MEASURE_H
+
+#include "nd_image.h"
+
+/* structure for array regions to find objects: */
+typedef struct {
+    int start[NI_MAXDIM], end[NI_MAXDIM];
+} NI_ObjectRegion;
+
+int NI_Label(PyArrayObject*, PyArrayObject*, maybelong*, PyArrayObject*);
+
+int NI_FindObjects(PyArrayObject*, maybelong, maybelong*);
+
+int NI_CenterOfMass(PyArrayObject*, PyArrayObject*, maybelong, maybelong,
+                                        maybelong*, maybelong, double*);
+
+int NI_Histogram(PyArrayObject*, PyArrayObject*, maybelong, maybelong, 
+             maybelong*, maybelong,  PyArrayObject**, double, double, maybelong);
+
+int NI_Statistics(PyArrayObject*, PyArrayObject*, maybelong, maybelong,
+                                    maybelong*, maybelong, double*, maybelong*, double*, 
+                                    double*, double*, maybelong*, maybelong*);
+
+int NI_WatershedIFT(PyArrayObject*, PyArrayObject*, PyArrayObject*, 
+                                        PyArrayObject*);
+
+#endif

Added: branches/Interpolate1D/ndimage/ni_morphology.c
===================================================================
--- branches/Interpolate1D/ndimage/ni_morphology.c	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/ni_morphology.c	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,955 @@
+/* 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_morphology.h"
+#include <stdlib.h>
+#include <math.h>
+#include <limits.h>
+#include <float.h>
+
+#define LIST_SIZE 100000
+
+#define CASE_GET_MASK(_msk_value, _pm, _type) \
+case t ## _type:                              \
+    _msk_value = *(_type*)_pm ? 1 : 0;          \
+    break
+
+#define CASE_OUTPUT(_po, _out, _type) \
+case t ## _type:                      \
+    *(_type*)_po = (_type)_out;         \
+    break
+
+#define CASE_NI_ERODE_POINT(_pi, _out, _offsets, _filter_size, _type, \
+                                                        _mv,  _border_value, _bv, _center_is_true,\
+                                                        _true, _false, _changed)                  \
+case t ## _type:                                                      \
+{                                                                     \
+    maybelong _ii, _oo;                                                 \
+    int _in = *(_type*)_pi ? 1 : 0;                                     \
+    if (_mv) {                                                          \
+        if (_center_is_true && _in == false) {                            \
+            _changed = 0;                                                   \
+            _out = _in;                                                     \
+        } else {                                                          \
+            _out = _true;                                                   \
+            for(_ii = 0; _ii < _filter_size; _ii++) {                       \
+                _oo = _offsets[_ii];                                          \
+                if (_oo == _bv) {                                             \
+                    if (!_border_value) {                                       \
+                        _out = _false;                                            \
+                        break;                                                    \
+                    }                                                           \
+                } else {                                                      \
+                    int _nn = *(_type*)(_pi + _oo) ? _true : _false;            \
+                    if (!_nn) {                                                 \
+                        _out = _false;                                            \
+                        break;                                                    \
+                    }                                                           \
+                }                                                             \
+            }                                                               \
+            _changed = _out != _in;                                         \
+        }                                                                 \
+    } else {                                                            \
+        _out = _in;                                                       \
+    }                                                                   \
+}                                                                     \
+break
+
+int NI_BinaryErosion(PyArrayObject* input, PyArrayObject* strct,
+                PyArrayObject* mask, PyArrayObject* output, int bdr_value,
+                maybelong *origins, int invert, int center_is_true, int* changed,
+                NI_CoordinateList **coordinate_list)
+{
+    maybelong struct_size = 0, *offsets = NULL, size, *oo, jj;
+    maybelong ssize, block_size = 0, *current = NULL, border_flag_value;
+    int kk, true, false, msk_value;
+    NI_Iterator ii, io, mi;
+    NI_FilterIterator fi;
+    Bool *ps, out = 0;
+    char *pi, *po, *pm = NULL;
+    NI_CoordinateBlock *block = NULL;
+
+    ps = (Bool*)PyArray_DATA(strct);
+    ssize = 1;
+    for(kk = 0; kk < strct->nd; kk++)
+        ssize *= strct->dimensions[kk];
+    for(jj = 0; jj < ssize; jj++)
+        if (ps[jj]) ++struct_size;
+    if (mask) {
+        if (!NI_InitPointIterator(mask, &mi))
+            return 0;
+        pm = (void *)PyArray_DATA(mask);
+    }
+    /* calculate the filter offsets: */
+    if (!NI_InitFilterOffsets(input, ps, strct->dimensions, origins,
+                                    NI_EXTEND_CONSTANT, &offsets, &border_flag_value, NULL))
+        goto exit;
+    /* initialize input element iterator: */
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+    /* initialize output element iterator: */
+    if (!NI_InitPointIterator(output, &io))
+        goto exit;
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(input->nd, strct->dimensions, struct_size,
+                                                         input->dimensions, origins, &fi))
+        goto exit;
+
+    /* get data pointers an size: */
+    pi = (void *)PyArray_DATA(input);
+    po = (void *)PyArray_DATA(output);
+    size = 1;
+    for(kk = 0; kk < input->nd; kk++)
+        size *= input->dimensions[kk];
+    if (invert) {
+        bdr_value = bdr_value ? 0 : 1;
+        true = 0;
+        false = 1;
+    } else {
+        bdr_value = bdr_value ? 1 : 0;
+        true = 1;
+        false = 0;
+    }
+    if (coordinate_list) {
+        block_size = LIST_SIZE / input->nd / sizeof(int);
+        if (block_size < 1)
+            block_size = 1;
+        if (block_size > size)
+            block_size = size;
+        *coordinate_list = NI_InitCoordinateList(block_size, input->nd);
+        if (!*coordinate_list)
+            goto exit;
+    }
+    /* iterator over the elements: */
+    oo = offsets;
+    *changed = 0;
+    msk_value = 1;
+    for(jj = 0; jj < size; jj++) {
+        int pchange = 0;
+        if (mask) {
+            switch(mask->descr->type_num) {
+            CASE_GET_MASK(msk_value, pm, Bool);
+            CASE_GET_MASK(msk_value, pm, UInt8);
+            CASE_GET_MASK(msk_value, pm, UInt16);
+            CASE_GET_MASK(msk_value, pm, UInt32);
+#if HAS_UINT64
+            CASE_GET_MASK(msk_value, pm, UInt64);
+#endif
+            CASE_GET_MASK(msk_value, pm, Int8);
+            CASE_GET_MASK(msk_value, pm, Int16);
+            CASE_GET_MASK(msk_value, pm, Int32);
+            CASE_GET_MASK(msk_value, pm, Int64);
+            CASE_GET_MASK(msk_value, pm, Float32);
+            CASE_GET_MASK(msk_value, pm, Float64);
+            default:
+                PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+                return 0;
+            }
+        }
+        switch (input->descr->type_num) {
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Bool, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, UInt8, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, UInt16, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, UInt32, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+#if HAS_UINT64
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, UInt64, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+#endif
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Int8, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Int16, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Int32, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Int64, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Float32, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        CASE_NI_ERODE_POINT(pi, out, oo, struct_size, Float64, msk_value,
+                                                bdr_value, border_flag_value, center_is_true,
+                                                true, false, pchange);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        switch (output->descr->type_num) {
+        CASE_OUTPUT(po, out, Bool);
+        CASE_OUTPUT(po, out, UInt8);
+        CASE_OUTPUT(po, out, UInt16);
+        CASE_OUTPUT(po, out, UInt32);
+#if HAS_UINT64
+        CASE_OUTPUT(po, out, UInt64);
+#endif
+        CASE_OUTPUT(po, out, Int8);
+        CASE_OUTPUT(po, out, Int16);
+        CASE_OUTPUT(po, out, Int32);
+        CASE_OUTPUT(po, out, Int64);
+        CASE_OUTPUT(po, out, Float32);
+        CASE_OUTPUT(po, out, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+        if (pchange) {
+            *changed = 1;
+            if (coordinate_list) {
+                if (block == NULL ||  block->size == block_size) {
+                    block = NI_CoordinateListAddBlock(*coordinate_list);
+                    current = block->coordinates;
+                }
+                for(kk = 0; kk < input->nd; kk++)
+                    *current++ = ii.coordinates[kk];
+                block->size++;
+            }
+        }
+        if (mask) {
+            NI_FILTER_NEXT3(fi, ii, io, mi, oo, pi, po, pm);
+        } else {
+            NI_FILTER_NEXT2(fi, ii, io, oo, pi, po);
+        }
+    }
+
+ exit:
+    if (offsets)
+        free(offsets);
+    if (PyErr_Occurred()) {
+        if (coordinate_list) {
+            NI_FreeCoordinateList(*coordinate_list);
+            *coordinate_list = NULL;
+        }
+        return 0;
+    } else {
+        return 1;
+    }
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+#define CASE_ERODE_POINT2(_struct_size, _offsets, _coordinate_offsets, \
+                                                    _pi, _oo, _irank, _list1, _list2,            \
+                                                    _current_coors1, _current_coors2, _block1,   \
+                                                    _block2, _bf_value, _true, _false, _type,    \
+                                                    _mklist)                                     \
+case t ## _type:                                                       \
+{                                                                      \
+    maybelong _hh, _kk;                                                  \
+    for(_hh = 0; _hh < _struct_size; _hh++) {                            \
+        maybelong _to = _offsets[_oo + _hh];                               \
+        if (_to != _bf_value && *(_type*)(_pi + _to) == _true) {           \
+            if (_mklist) {                                                   \
+                maybelong *_tc = &(_coordinate_offsets[(_oo + _hh) * _irank]); \
+                if (_block2 == NULL || _block2->size == _list2->block_size) {  \
+                    _block2 = NI_CoordinateListAddBlock(_list2);                 \
+                    _current_coors2 = _block2->coordinates;                      \
+                }                                                              \
+                for(_kk = 0; _kk < _irank; _kk++)                              \
+                    *_current_coors2++ = _current_coors1[_kk] + _tc[_kk];        \
+                _block2->size++;                                               \
+            }                                                                \
+            *(_type*)(_pi + _to) = _false;                                   \
+        }                                                                  \
+    }                                                                    \
+}                                                                      \
+break
+
+int NI_BinaryErosion2(PyArrayObject* array, PyArrayObject* strct,
+                                            PyArrayObject* mask, int niter, maybelong *origins,
+                                            int invert, NI_CoordinateList **iclist)
+{
+    maybelong struct_size = 0, *offsets = NULL, oo, jj, ssize;
+    maybelong *coordinate_offsets = NULL, size = 0;
+    maybelong *current_coordinates1 = NULL, *current_coordinates2 = NULL;
+    maybelong kk, border_flag_value, current = 0;
+    int true, false;
+    NI_Iterator ii, mi;
+    NI_FilterIterator fi, ci;
+    Bool *ps;
+    char *pi, *ibase, *pm = NULL;
+    NI_CoordinateBlock *block1 = NULL, *block2 = NULL;
+    NI_CoordinateList *list1 = NULL, *list2 = NULL;
+
+    ps = (Bool*)PyArray_DATA(strct);
+    ssize = 1;
+    for(kk = 0; kk < strct->nd; kk++)
+        ssize *= strct->dimensions[kk];
+    for(jj = 0; jj < ssize; jj++)
+        if (ps[jj]) ++struct_size;
+
+    /* calculate the filter offsets: */
+    if (!NI_InitFilterOffsets(array, ps, strct->dimensions, origins,
+                                                        NI_EXTEND_CONSTANT, &offsets,
+                                                        &border_flag_value, &coordinate_offsets))
+        goto exit;
+
+    /* initialize input element iterator: */
+    if (!NI_InitPointIterator(array, &ii))
+        goto exit;
+
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(array->nd, strct->dimensions, struct_size,
+                                                         array->dimensions, origins, &fi))
+        goto exit;
+    if (!NI_InitFilterIterator(array->nd, strct->dimensions,
+                                                         struct_size * array->nd, array->dimensions,
+                                                         origins, &ci))
+        goto exit;
+
+    /* get data pointers and size: */
+    ibase = pi = (void *)PyArray_DATA(array);
+
+    if (invert) {
+        true = 0;
+        false = 1;
+    } else {
+        true = 1;
+        false = 0;
+    }
+
+    if (mask) {
+        /* iterator, data pointer and type of mask array: */
+        if (!NI_InitPointIterator(mask, &mi))
+            return 0;
+        pm = (void *)PyArray_DATA(mask);
+
+        size = 1;
+        for(kk = 0; kk < array->nd; kk++)
+            size *= array->dimensions[kk];
+
+        for(jj = 0; jj < size; jj++) {
+            if (*(Int8*)pm) {
+                *(Int8*)pm = -1;
+            } else {
+                *(Int8*)pm = (Int8)*(Bool*)pi;
+                *(Bool*)pi = false;
+            }
+            NI_ITERATOR_NEXT2(ii, mi,  pi, pm)
+        }
+        NI_ITERATOR_RESET(ii)
+                pi = (void *)PyArray_DATA(array);
+    }
+
+    list1 = NI_InitCoordinateList((*iclist)->block_size, (*iclist)->rank);
+    list2 = NI_InitCoordinateList((*iclist)->block_size, (*iclist)->rank);
+    if (!list1 || !list2)
+        goto exit;
+    if (NI_CoordinateListStealBlocks(list2, *iclist))
+        goto exit;
+    block2 = list2->blocks;
+    jj = 0;
+    while(block1 || block2) {
+        int mklist = 1;
+        if (!block1) {
+            if (niter <= 0 || jj < niter) {
+                if (NI_CoordinateListStealBlocks(list1, list2))
+                    goto exit;
+                block1 = list1->blocks;
+                block2 = NULL;
+                current_coordinates1 = block1->coordinates;
+                current = 0;
+                ++jj;
+                mklist = niter <= 0 || jj < niter;
+            } else {
+                break;
+            }
+        }
+        NI_ITERATOR_GOTO(ii, current_coordinates1, ibase, pi);
+        NI_FILTER_GOTO(fi, ii, 0, oo);
+
+        switch (array->descr->type_num) {
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Bool, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, UInt8, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, UInt16, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, UInt32, mklist);
+#if HAS_UINT64
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, UInt64, mklist);
+#endif
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Int8, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Int16, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Int32, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Int64, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Float32, mklist);
+        CASE_ERODE_POINT2(struct_size, offsets, coordinate_offsets, pi,
+                                            oo, array->nd, list1, list2, current_coordinates1,
+                                            current_coordinates2, block1, block2,
+                                            border_flag_value, true, false, Float64, mklist);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "data type not supported");
+            goto exit;
+        }
+
+        ++current;
+        if (current == block1->size) {
+            block1 = NI_CoordinateListDeleteBlock(list1);
+            if (block1) {
+                current_coordinates1 = block1->coordinates;
+                current = 0;
+            }
+        } else {
+            current_coordinates1 += array->nd;
+        }
+    }
+
+    if (mask) {
+        NI_ITERATOR_RESET(ii)
+        NI_ITERATOR_RESET(mi)
+        pi = (void *)PyArray_DATA(array);
+        pm = (void *)PyArray_DATA(mask);
+        for(jj = 0; jj < size; jj++) {
+            int value = *(Int8*)pm;
+            if (value >= 0)
+                *(Bool*)pi = value;
+            NI_ITERATOR_NEXT2(ii, mi,  pi, pm)
+        }
+    }
+
+ exit:
+    if (offsets)
+        free(offsets);
+    if (coordinate_offsets)
+        free(coordinate_offsets);
+    NI_FreeCoordinateList(list1);
+    NI_FreeCoordinateList(list2);
+    if (PyErr_Occurred()) {
+        return 0;
+    } else {
+        return 1;
+    }
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+
+#define NI_DISTANCE_EUCLIDIAN  1
+#define NI_DISTANCE_CITY_BLOCK 2
+#define NI_DISTANCE_CHESSBOARD 3
+
+typedef struct {
+    maybelong *coordinates;
+    maybelong index;
+    void *next;
+} NI_BorderElement;
+
+int NI_DistanceTransformBruteForce(PyArrayObject* input, int metric,
+                                                                     PyArrayObject *sampling_arr,
+                                                                     PyArrayObject* distances,
+                                                                     PyArrayObject* features)
+{
+    maybelong size, jj, min_index = 0;
+    int kk;
+    NI_BorderElement *border_elements = NULL, *temp;
+    NI_Iterator ii, di, fi;
+    char *pi, *pd = NULL, *pf = NULL;
+    Float64 *sampling = sampling_arr ? (void *)PyArray_DATA(sampling_arr) : NULL;
+
+    /* check the output arrays: */
+    if (distances) {
+            pd = (void *)PyArray_DATA(distances);
+        if (!NI_InitPointIterator(distances, &di))
+            goto exit;
+    }
+
+    if (features) {
+            pf = (void *)PyArray_DATA(features);
+        if (!NI_InitPointIterator(features, &fi))
+            goto exit;
+    }
+
+    size = 1;
+    for(kk = 0; kk < input->nd; kk++)
+        size *= input->dimensions[kk];
+    pi = (void *)PyArray_DATA(input);
+
+    if (!NI_InitPointIterator(input, &ii))
+        goto exit;
+
+    for(jj = 0; jj < size; jj++) {
+        if (*(Int8*)pi < 0) {
+            temp = (NI_BorderElement*)malloc(sizeof(NI_BorderElement));
+            if (!temp) {
+                PyErr_NoMemory();
+                goto exit;
+            }
+            temp->next = border_elements;
+            border_elements = temp;
+            temp->index = jj;
+            temp->coordinates = (maybelong*)malloc(input->nd * sizeof(maybelong));
+            for(kk = 0; kk < input->nd; kk++)
+                    temp->coordinates[kk] = ii.coordinates[kk];
+        }
+        NI_ITERATOR_NEXT(ii, pi);
+    }
+
+    NI_ITERATOR_RESET(ii);
+    pi = (void *)PyArray_DATA(input);
+
+    switch(metric) {
+    case NI_DISTANCE_EUCLIDIAN:
+        for(jj = 0; jj < size; jj++) {
+            if (*(Int8*)pi > 0) {
+                double distance = DBL_MAX;
+                temp = border_elements;
+                while(temp) {
+                    double d = 0.0, t;
+                    for(kk = 0; kk < input->nd; kk++) {
+                        t = ii.coordinates[kk] - temp->coordinates[kk];
+                        if (sampling)
+                            t *= sampling[kk];
+                        d += t * t;
+                    }
+                    if (d < distance) {
+                        distance = d;
+                        if (features)
+                            min_index = temp->index;
+                    }
+                    temp = temp->next;
+                }
+                if (distances)
+                    *(Float64*)pd = sqrt(distance);
+                if (features)
+                    *(Int32*)pf = min_index;
+            } else {
+                if (distances)
+                    *(Float64*)pd = 0.0;
+                if (features)
+                    *(Int32*)pf = jj;
+            }
+            if (features && distances) {
+                NI_ITERATOR_NEXT3(ii, di, fi, pi, pd, pf);
+            } else if (distances) {
+                NI_ITERATOR_NEXT2(ii, di, pi, pd);
+            } else {
+                NI_ITERATOR_NEXT2(ii, fi, pi, pf);
+            }
+        }
+        break;
+    case NI_DISTANCE_CITY_BLOCK:
+    case NI_DISTANCE_CHESSBOARD:
+        for(jj = 0; jj < size; jj++) {
+            if (*(Int8*)pi > 0) {
+                unsigned long distance = ULONG_MAX;
+                temp = border_elements;
+                while(temp) {
+                    unsigned int d = 0;
+                    maybelong t;
+                    for(kk = 0; kk < input->nd; kk++) {
+                        t = ii.coordinates[kk] - temp->coordinates[kk];
+                        if (t < 0)
+                            t = -t;
+                        if (metric == NI_DISTANCE_CITY_BLOCK) {
+                            d += t;
+                        } else {
+                            if ((unsigned int)t > d)
+                                d = t;
+                        }
+                    }
+                    if (d < distance) {
+                        distance = d;
+                        if (features)
+                            min_index = temp->index;
+                    }
+                    temp = temp->next;
+                }
+                if (distances)
+                    *(UInt32*)pd = distance;
+                if (features)
+                    *(Int32*)pf = min_index;
+            } else {
+                if (distances)
+                    *(UInt32*)pd = 0;
+                if (features)
+                    *(Int32*)pf = jj;
+            }
+            if (features && distances) {
+                NI_ITERATOR_NEXT3(ii, di, fi, pi, pd, pf);
+            } else if (distances) {
+                NI_ITERATOR_NEXT2(ii, di, pi, pd);
+            } else {
+                 NI_ITERATOR_NEXT2(ii, fi, pi, pf);
+            }
+        }
+        break;
+    default:
+        PyErr_SetString(PyExc_RuntimeError,  "distance metric not supported");
+        goto exit;
+    }
+
+ exit:
+    while (border_elements) {
+        temp = border_elements;
+        border_elements = border_elements->next;
+        if (temp->coordinates)
+            free(temp->coordinates);
+        free(temp);
+    }
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+
+int NI_DistanceTransformOnePass(PyArrayObject *strct,
+                                                PyArrayObject* distances, PyArrayObject *features)
+{
+    int kk;
+    maybelong jj, ii, ssize, size, filter_size, mask_value, *oo;
+    maybelong *foffsets = NULL, *foo = NULL, *offsets = NULL;
+    Bool *ps, *pf = NULL, *footprint = NULL;
+    char *pd;
+    NI_FilterIterator si, ti;
+    NI_Iterator di, fi;
+
+    ssize = 1;
+    for(kk = 0; kk < strct->nd; kk++)
+        ssize *= strct->dimensions[kk];
+
+    /* we only use the first half of the structure data, so we make a
+         temporary structure for use with the filter functions: */
+    footprint = (Bool*)malloc(ssize * sizeof(Bool));
+    if (!footprint) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    ps = (Bool*)PyArray_DATA(strct);
+    filter_size = 0;
+    for(jj = 0; jj < ssize / 2; jj++) {
+        footprint[jj] = ps[jj];
+        if (ps[jj])
+            ++filter_size;
+    }
+    for(jj = ssize / 2; jj < ssize; jj++)
+        footprint[jj] = 0;
+    /* get data and size */
+    pd = (void *)PyArray_DATA(distances);
+    size = 1;
+    for(kk = 0; kk < distances->nd; kk++)
+        size *= distances->dimensions[kk];
+    if (!NI_InitPointIterator(distances, &di))
+        goto exit;
+    /* calculate the filter offsets: */
+    if (!NI_InitFilterOffsets(distances, footprint, strct->dimensions, NULL,
+                                                    NI_EXTEND_CONSTANT, &offsets, &mask_value, NULL))
+        goto exit;
+    /* initialize filter iterator: */
+    if (!NI_InitFilterIterator(distances->nd, strct->dimensions,
+                                                    filter_size, distances->dimensions, NULL, &si))
+        goto exit;
+
+    if (features) {
+        maybelong dummy;
+        /* initialize point iterator: */
+        pf = (void *)PyArray_DATA(features);
+        if (!NI_InitPointIterator(features, &fi))
+            goto exit;
+        /* calculate the filter offsets: */
+        if (!NI_InitFilterOffsets(features, footprint, strct->dimensions,
+                                                NULL, NI_EXTEND_CONSTANT, &foffsets, &dummy, NULL))
+            goto exit;
+        /* initialize filter iterator: */
+        if (!NI_InitFilterIterator(distances->nd, strct->dimensions,
+                                                     filter_size, distances->dimensions, NULL, &ti))
+            goto exit;
+    }
+    /* iterator over the elements: */
+    oo = offsets;
+    if (features)
+        foo = foffsets;
+    for(jj = 0; jj < size; jj++) {
+        Int32 value = *(Int32*)pd;
+        if (value != 0) {
+            Int32 min = value;
+            maybelong min_offset = 0;
+            /* iterate over structuring element: */
+            for(ii = 0; ii < filter_size; ii++) {
+                maybelong offset = oo[ii];
+                Int32 tt = -1;
+                if (offset < mask_value)
+                    tt = *(Int32*)(pd + offset);
+                if (tt >= 0) {
+                    if ((min < 0) || (tt + 1 < min)) {
+                        min = tt + 1;
+                        if (features)
+                            min_offset = foo[ii];
+                    }
+                }
+            }
+            *(Int32*)pd = min;
+            if (features)
+                *(Int32*)pf = *(Int32*)(pf + min_offset);
+        }
+        if (features) {
+            NI_FILTER_NEXT(ti, fi, foo, pf);
+        }
+        NI_FILTER_NEXT(si, di, oo, pd);
+    }
+
+ exit:
+    if (offsets) free(offsets);
+    if (foffsets) free(foffsets);
+    if (footprint)
+        free(footprint);
+    return PyErr_Occurred() ? 0 : 1;
+}
+
+static void _VoronoiFT(char *pf, maybelong len, maybelong *coor, int rank,
+                                             int d, maybelong stride, maybelong cstride,
+                                             maybelong **f, maybelong *g, Float64 *sampling)
+{
+    maybelong l = -1, ii, maxl, idx1, idx2;
+    int jj;
+
+    for(ii = 0; ii < len; ii++)
+        for(jj = 0; jj < rank; jj++)
+            f[ii][jj] = *(Int32*)(pf + ii * stride + cstride * jj);
+    for(ii = 0; ii < len; ii++) {
+        if (*(Int32*)(pf + ii * stride) >= 0) {
+            double fd = f[ii][d];
+            double wR = 0.0;
+            for(jj = 0; jj < rank; jj++) {
+                if (jj != d) {
+                    double tw = f[ii][jj] - coor[jj];
+                    if (sampling)
+                        tw *= sampling[jj];
+                    wR += tw * tw;
+                }
+            }
+            while(l >= 1) {
+                double a, b, c, uR = 0.0, vR = 0.0, f1;
+                idx1 = g[l];
+                f1 = f[idx1][d];
+                idx2 = g[l - 1];
+                a = f1 - f[idx2][d];
+                b = fd - f1;
+                if (sampling) {
+                    a *= sampling[d];
+                    b *= sampling[d];
+                }
+                c = a + b;
+                for(jj = 0; jj < rank; jj++) {
+                    if (jj != d) {
+                        double cc = coor[jj];
+                        double tu = f[idx2][jj] - cc;
+                        double tv = f[idx1][jj] - cc;
+                        if (sampling) {
+                            tu *= sampling[jj];
+                            tv *= sampling[jj];
+                        }
+                        uR += tu * tu;
+                        vR += tv * tv;
+                    }
+                }
+                if (c * vR - b * uR - a * wR - a * b * c <= 0.0)
+                    break;
+                --l;
+            }
+            ++l;
+            g[l] = ii;
+        }
+    }
+    maxl = l;
+    if (maxl >= 0) {
+        l = 0;
+        for (ii = 0; ii < len; ii++) {
+            double delta1 = 0.0, t;
+            for(jj = 0; jj < rank; jj++) {
+                t = jj == d ? f[g[l]][jj] - ii : f[g[l]][jj] - coor[jj];
+                if (sampling)
+                    t *= sampling[jj];
+                delta1 += t * t;
+            }
+            while (l < maxl) {
+                double delta2 = 0.0;
+                for(jj = 0; jj < rank; jj++) {
+                    t = jj == d ? f[g[l + 1]][jj] - ii : f[g[l + 1]][jj] - coor[jj];
+                    if (sampling)
+                        t *= sampling[jj];
+                    delta2 += t * t;
+                }
+                if (delta1 <= delta2)
+                    break;
+                delta1 = delta2;
+                ++l;
+            }
+            idx1 = g[l];
+            for(jj = 0; jj < rank; jj++)
+                *(Int32*)(pf + ii * stride + jj * cstride) = f[idx1][jj];
+        }
+    }
+}
+
+
+/* Recursive feature transform */
+static void _ComputeFT(char *pi, char *pf, maybelong *ishape,
+                                             maybelong *istrides, maybelong *fstrides, int rank,
+                                             int d, maybelong *coor, maybelong **f, maybelong *g,
+                                             PyArrayObject *features, Float64 *sampling)
+{
+    int kk;
+    maybelong jj;
+
+    if (d == 0) {
+        char *tf1 = pf;
+        for(jj = 0; jj < ishape[0]; jj++) {
+            if (*(Int8*)pi) {
+                *(Int32*)tf1 = -1;
+            } else {
+                char *tf2 = tf1;
+                *(Int32*)tf2 = jj;
+                for(kk = 1; kk < rank; kk++) {
+                    tf2 += fstrides[0];
+                    *(Int32*)tf2 = coor[kk];
+                }
+            }
+            pi += istrides[0];
+            tf1 += fstrides[1];
+        }
+        _VoronoiFT(pf, ishape[0], coor, rank, 0, fstrides[1], fstrides[0], f,
+                             g, sampling);
+    } else {
+        UInt32 axes = 0;
+        char *tf = pf;
+        maybelong size = 1;
+        NI_Iterator ii;
+
+        for(jj = 0; jj < ishape[d]; jj++) {
+            coor[d] = jj;
+            _ComputeFT(pi, tf, ishape, istrides, fstrides, rank, d - 1, coor, f,
+                                 g, features, sampling);
+            pi += istrides[d];
+            tf += fstrides[d + 1];
+        }
+
+        for(jj = 0; jj < d; jj++) {
+            axes |= (UInt32)1 << (jj + 1);
+            size *= ishape[jj];
+        }
+        NI_InitPointIterator(features, &ii);
+        NI_SubspaceIterator(&ii, axes);
+        tf = pf;
+        for(jj = 0; jj < size; jj++) {
+            for(kk = 0; kk < d; kk++)
+                coor[kk] = ii.coordinates[kk];
+            _VoronoiFT(tf, ishape[d], coor, rank, d, fstrides[d + 1],
+                                 fstrides[0], f, g, sampling);
+            NI_ITERATOR_NEXT(ii, tf);
+        }
+        for(kk = 0; kk < d; kk++)
+            coor[kk] = 0;
+    }
+}
+
+/* Exact euclidean feature transform, as described in: C. R. Maurer,
+     Jr., R. Qi, V. Raghavan, "A linear time algorithm for computing
+     exact euclidean distance transforms of binary images in arbitrary
+     dimensions. IEEE Trans. PAMI 25, 265-270, 2003. */
+int NI_EuclideanFeatureTransform(PyArrayObject* input,
+                                                                 PyArrayObject *sampling_arr,
+                                                                 PyArrayObject* features)
+{
+    int ii;
+    maybelong coor[NI_MAXDIM], mx = 0, jj;
+    maybelong *tmp = NULL, **f = NULL, *g = NULL;
+    char *pi, *pf;
+    Float64 *sampling = sampling_arr ? ((void *)PyArray_DATA(sampling_arr)) : NULL;
+
+    pi = (void *)PyArray_DATA(input);
+    pf = (void *)PyArray_DATA(features);
+    for(ii = 0; ii < input->nd; ii++) {
+        coor[ii] = 0;
+        if (input->dimensions[ii] > mx)
+            mx = input->dimensions[ii];
+    }
+
+    /* Some temporaries */
+    f = (maybelong**)malloc(mx * sizeof(maybelong*));
+    g = (maybelong*)malloc(mx * sizeof(maybelong));
+    tmp = (maybelong*)malloc(mx * input->nd * sizeof(maybelong));
+    if (!f || !g || !tmp) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    for(jj = 0; jj < mx; jj++)
+        f[jj] = tmp + jj * input->nd;
+
+    /* First call of recursive feature transform */
+    _ComputeFT(pi, pf, input->dimensions, input->strides, features->strides,
+                         input->nd, input->nd - 1, coor, f, g, features, sampling);
+
+ exit:
+    if (f)
+        free(f);
+    if (g)
+        free(g);
+    if (tmp)
+        free(tmp);
+
+    return PyErr_Occurred() ? 0 : 1;
+}

Added: branches/Interpolate1D/ndimage/ni_morphology.h
===================================================================
--- branches/Interpolate1D/ndimage/ni_morphology.h	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/ni_morphology.h	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,46 @@
+/* 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 NI_MORPHOLOGY_H
+#define NI_MORPHOLOGY_H
+
+int NI_BinaryErosion(PyArrayObject*, PyArrayObject*, PyArrayObject*, 
+         PyArrayObject*, int, maybelong*, int, int, int*, NI_CoordinateList**);
+int NI_BinaryErosion2(PyArrayObject*, PyArrayObject*, PyArrayObject*,
+                                            int, maybelong*, int, NI_CoordinateList**);
+int NI_DistanceTransformBruteForce(PyArrayObject*, int, PyArrayObject*,
+                                                                     PyArrayObject*, PyArrayObject*);
+int NI_DistanceTransformOnePass(PyArrayObject*, PyArrayObject *,
+                                                                PyArrayObject*);
+int NI_EuclideanFeatureTransform(PyArrayObject*, PyArrayObject*, 
+                                                                 PyArrayObject*);
+
+#endif

Added: branches/Interpolate1D/ndimage/ni_support.c
===================================================================
--- branches/Interpolate1D/ndimage/ni_support.c	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/ni_support.c	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,751 @@
+/* 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"
+
+/* initialize iterations over single array elements: */
+int NI_InitPointIterator(PyArrayObject *array, NI_Iterator *iterator)
+{
+    int ii;
+
+    iterator->rank_m1 = array->nd - 1;
+    for(ii = 0; ii < array->nd; ii++) {
+        /* adapt dimensions for use in the macros: */
+        iterator->dimensions[ii] = array->dimensions[ii] - 1;
+        /* initialize coordinates: */
+        iterator->coordinates[ii] = 0;
+        /* initialize strides: */
+        iterator->strides[ii] = array->strides[ii];
+        /* calculate the strides to move back at the end of an axis: */
+        iterator->backstrides[ii] =
+                array->strides[ii] * iterator->dimensions[ii];
+    }
+    return 1;
+}
+
+
+/* initialize iteration over a lower sub-space: */
+int NI_SubspaceIterator(NI_Iterator *iterator, UInt32 axes)
+{
+    int ii, last = 0;
+
+    for(ii = 0; ii <= iterator->rank_m1; ii++) {
+        if (axes & (((UInt32)1) << ii)) {
+            if (last != ii) {
+                iterator->dimensions[last] = iterator->dimensions[ii];
+                iterator->strides[last] = iterator->strides[ii];
+                iterator->backstrides[last] = iterator->backstrides[ii];
+            }
+            ++last;
+        }
+    }
+    iterator->rank_m1 = last - 1;
+    return 1;
+}
+
+/* initialize iteration over array lines: */
+int NI_LineIterator(NI_Iterator *iterator, int axis)
+{
+    UInt32 axes = ((UInt32)1) << axis;
+    return NI_SubspaceIterator(iterator, ~axes);
+}
+
+
+/******************************************************************/
+/* Line buffers */
+/******************************************************************/
+
+/* Allocate line buffer data */
+int NI_AllocateLineBuffer(PyArrayObject* array, int axis, maybelong size1,
+        maybelong size2, maybelong *lines, maybelong max_size, double **buffer)
+{
+    maybelong line_size, max_lines;
+    int ii;
+
+    /* the number of lines of the array is an upper limit for the
+         number of lines in the buffer: */
+    max_lines = 1;
+    for(ii = 0; ii < array->nd; ii++)
+        max_lines *= array->dimensions[ii];
+    if (array->nd > 0 && array->dimensions[axis] > 0)
+        max_lines /= array->dimensions[axis];
+    /* calculate the space needed for one line, including space to
+         support the boundary conditions: */
+    line_size = sizeof(double) * (array->dimensions[axis] + size1 + size2);
+    /* if *lines < 1, no number of lines is proposed, so we calculate it
+         from the maximum size allowed: */
+    if (*lines < 1) {
+        *lines = line_size > 0 ? max_size / line_size : 0;
+        if (*lines < 1)
+            *lines = 1;
+    }
+    /* no need to allocate too many lines: */
+    if (*lines > max_lines)
+        *lines = max_lines;
+    /* allocate data for the buffer: */
+    *buffer = (double*)malloc(*lines * line_size);
+    if (!*buffer) {
+        PyErr_NoMemory();
+        return 0;
+    }
+    return 1;
+}
+
+/* Initialize a line buffer */
+int NI_InitLineBuffer(PyArrayObject *array, int axis, maybelong size1,
+        maybelong size2, maybelong buffer_lines, double *buffer_data,
+        NI_ExtendMode extend_mode, double extend_value, NI_LineBuffer *buffer)
+{
+    maybelong line_length = 0, array_lines = 0, size;
+    int ii;
+
+    size = 1;
+    for(ii = 0; ii < array->nd; ii++)
+        size *= array->dimensions[ii];
+    /* check if the buffer is big enough: */
+    if (size > 0 && buffer_lines < 1) {
+        PyErr_SetString(PyExc_RuntimeError, "buffer too small");
+        return 0;
+    }
+    /* Initialize a line iterator to move over the array: */
+    if (!NI_InitPointIterator(array, &(buffer->iterator)))
+        return 0;
+    if (!NI_LineIterator(&(buffer->iterator), axis))
+        return 0;
+    line_length = array->nd > 0 ? array->dimensions[axis] : 1;
+    if (line_length > 0)
+        array_lines = line_length > 0 ? size / line_length : 1;
+    /* initialize the buffer structure: */
+    buffer->array_data = (void *)PyArray_DATA(array);
+    buffer->buffer_data = buffer_data;
+    buffer->buffer_lines = buffer_lines;
+    buffer->array_type = array->descr->type_num;
+    buffer->array_lines = array_lines;
+    buffer->next_line = 0;
+    buffer->size1 = size1;
+    buffer->size2 = size2;
+    buffer->line_length = line_length;
+    buffer->line_stride = array->nd > 0 ? array->strides[axis] : 0;
+    buffer->extend_mode = extend_mode;
+    buffer->extend_value = extend_value;
+    return 1;
+}
+
+/* Extend a line in memory to implement boundary conditions: */
+int NI_ExtendLine(double *line, maybelong length, maybelong size1,
+                                maybelong size2, NI_ExtendMode mode, double constant_value)
+{
+    maybelong ii, jj, length1, nextend, rextend;
+    double *l1, *l2, *l3, val;
+
+    switch (mode) {
+    case NI_EXTEND_WRAP:
+        nextend = size1 / length;
+        rextend = size1 - nextend * length;
+        l1 = line + size1 + length - rextend;
+        l2 = line;
+        for(ii = 0; ii < rextend; ii++)
+            *l2++ = *l1++;
+        for(ii = 0; ii < nextend; ii++) {
+            l1 = line + size1;
+            for(jj = 0; jj < length; jj++)
+                *l2++ = *l1++;
+        }
+        nextend = size2 / length;
+        rextend = size2 - nextend * length;
+        l1 = line + size1;
+        l2 = line + size1 + length;
+        for(ii = 0; ii < nextend; ii++) {
+            l3 = l1;
+            for(jj = 0; jj < length; jj++)
+                *l2++ = *l3++;
+        }
+        for(ii = 0; ii < rextend; ii++)
+            *l2++ = *l1++;
+        break;
+    case NI_EXTEND_MIRROR:
+        if (length == 1) {
+            l1 = line;
+            val = line[size1];
+            for(ii = 0; ii < size1; ii++)
+                *l1++ = val;
+            l1 = line + size1 + length;
+            val = line[size1 + length - 1];
+            for(ii = 0; ii < size2; ii++)
+                *l1++ = val;
+        } else {
+            length1 = length - 1;
+            nextend = size1 / length1;
+            rextend = size1 - nextend * length1;
+            l1 = line + size1 + 1;
+            l2 = l1 - 2;
+            for(ii = 0; ii < nextend; ii++) {
+                l3 = l1;
+                for(jj = 0; jj < length1; jj++)
+                    *l2-- = *l3++;
+                l1 -= length1;
+            }
+            for(ii = 0; ii < rextend; ii++)
+                *l2-- = *l1++;
+            nextend = size2 / length1;
+            rextend = size2 - nextend * length1;
+            l1 = line + size1 + length1 - 1;
+            l2 = l1 + 2;
+            for(ii = 0; ii < nextend; ii++) {
+                l3 = l1;
+                for(jj = 0; jj < length1; jj++)
+                    *l2++ = *l3--;
+                l1 += length1;
+            }
+            for(ii = 0; ii < rextend; ii++)
+                *l2++ = *l1--;
+        }
+        break;
+    case NI_EXTEND_REFLECT:
+        nextend = size1 / length;
+        rextend = size1 - nextend * length;
+        l1 = line + size1;
+        l2 = l1 - 1;
+        for(ii = 0; ii < nextend; ii++) {
+            l3 = l1;
+            for(jj = 0; jj < length; jj++)
+                *l2-- = *l3++;
+            l1 -= length;
+        }
+        l3 = l1;
+        for(ii = 0; ii < rextend; ii++)
+            *l2-- = *l3++;
+        nextend = size2 / length;
+        rextend = size2 - nextend * length;
+        l1 = line + size1 + length - 1;
+        l2 = l1 + 1;
+        for(ii = 0; ii < nextend; ii++) {
+            l3 = l1;
+            for(jj = 0; jj < length; jj++)
+                *l2++ = *l3--;
+            l1 += length;
+        }
+        for(ii = 0; ii < rextend; ii++)
+            *l2++ = *l1--;
+        break;
+    case NI_EXTEND_NEAREST:
+        l1 = line;
+        val = line[size1];
+        for(ii = 0; ii < size1; ii++)
+            *l1++ = val;
+        l1 = line + size1 + length;
+        val = line[size1 + length - 1];
+        for(ii = 0; ii < size2; ii++)
+            *l1++ = val;
+        break;
+    case NI_EXTEND_CONSTANT:
+        l1 = line;
+        for(ii = 0; ii < size1; ii++)
+            *l1++ = constant_value;
+        l1 = line + size1 + length;
+        for(ii = 0; ii < size2; ii++)
+            *l1++ = constant_value;
+        break;
+    default:
+        PyErr_SetString(PyExc_RuntimeError, "mode not supported");
+        return 0;
+    }
+    return 1;
+}
+
+
+#define CASE_COPY_DATA_TO_LINE(_pi, _po, _length, _stride, _type) \
+case t ## _type:                                                  \
+{                                                                 \
+    maybelong _ii;                                                  \
+    for(_ii = 0; _ii < _length; _ii++) {                            \
+        _po[_ii] = (double)*(_type*)_pi;                              \
+        _pi += _stride;                                               \
+    }                                                               \
+}                                                                 \
+break
+
+
+/* Copy a line from an array to a buffer: */
+int NI_ArrayToLineBuffer(NI_LineBuffer *buffer,
+                                                 maybelong *number_of_lines, int *more)
+{
+    double *pb = buffer->buffer_data;
+    char *pa;
+    maybelong length = buffer->line_length;
+
+    pb += buffer->size1;
+    *number_of_lines = 0;
+    /* fill until all lines in the array have been processed, or until
+         the buffer is full: */
+    while (buffer->next_line < buffer->array_lines &&
+                 *number_of_lines < buffer->buffer_lines) {
+        pa = buffer->array_data;
+        /* copy the data from the array to the buffer: */
+        switch (buffer->array_type) {
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Bool);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, UInt8);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, UInt16);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, UInt32);
+#if HAS_UINT64
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, UInt64);
+#endif
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Int8);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Int16);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Int32);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Int64);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Float32);
+            CASE_COPY_DATA_TO_LINE(pa, pb, length, buffer->line_stride, Float64);
+        default:
+            PyErr_Format(PyExc_RuntimeError, "array type %d not supported", buffer->array_type);
+            return 0;
+        }
+        /* goto next line in the array: */
+        NI_ITERATOR_NEXT(buffer->iterator, buffer->array_data);
+        /* implement boundary conditions to the line: */
+        if (buffer->size1 + buffer->size2 > 0)
+            if (!NI_ExtendLine(pb - buffer->size1, length, buffer->size1,
+                                                 buffer->size2, buffer->extend_mode,
+                                                 buffer->extend_value))
+                return 0;
+        /* The number of the array lines copied: */
+        ++(buffer->next_line);
+        /* keep track of (and return) the number of lines in the buffer: */
+        ++(*number_of_lines);
+        pb += buffer->line_length + buffer->size1 + buffer->size2;
+    }
+    /* if not all array lines were processed, *more is set true: */
+    *more = buffer->next_line < buffer->array_lines;
+    return 1;
+}
+
+#define CASE_COPY_LINE_TO_DATA(_pi, _po, _length, _stride, _type) \
+case t ## _type:                                                  \
+{                                                                 \
+    maybelong _ii;                                                  \
+    for(_ii = 0; _ii < _length; _ii++) {                            \
+        *(_type*)_po = (_type)_pi[_ii];                               \
+        _po += _stride;                                               \
+    }                                                               \
+}                                                                 \
+break
+
+/* Copy a line from a buffer to an array: */
+int NI_LineBufferToArray(NI_LineBuffer *buffer)
+{
+    double *pb = buffer->buffer_data;
+    char *pa;
+    maybelong jj, length = buffer->line_length;
+
+    pb += buffer->size1;
+    for(jj = 0; jj < buffer->buffer_lines; jj++) {
+        /* if all array lines are copied return: */
+        if (buffer->next_line == buffer->array_lines)
+            break;
+        pa = buffer->array_data;
+        /* copy data from the buffer to the array: */
+        switch (buffer->array_type) {
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Bool);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, UInt8);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, UInt16);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, UInt32);
+#if HAS_UINT64
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, UInt64);
+#endif
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Int8);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Int16);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Int32);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Int64);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Float32);
+            CASE_COPY_LINE_TO_DATA(pb, pa, length, buffer->line_stride, Float64);
+        default:
+            PyErr_SetString(PyExc_RuntimeError, "array type not supported");
+            return 0;
+        }
+        /* move to the next line in the array: */
+        NI_ITERATOR_NEXT(buffer->iterator, buffer->array_data);
+        /* number of lines copied: */
+        ++(buffer->next_line);
+        /* move the buffer data pointer to the next line: */
+        pb += buffer->line_length + buffer->size1 + buffer->size2;
+    }
+    return 1;
+}
+
+/******************************************************************/
+/* Multi-dimensional filter support functions */
+/******************************************************************/
+
+/* Initialize a filter iterator: */
+int
+NI_InitFilterIterator(int rank, maybelong *filter_shape,
+                    maybelong filter_size, maybelong *array_shape,
+                    maybelong *origins, NI_FilterIterator *iterator)
+{
+    int ii;
+    maybelong fshape[MAXDIM], forigins[MAXDIM];
+
+    for(ii = 0; ii < rank; ii++) {
+        fshape[ii] = *filter_shape++;
+        forigins[ii] = origins ? *origins++ : 0;
+    }
+    /* calculate the strides, used to move the offsets pointer through
+         the offsets table: */
+    if (rank > 0) {
+        iterator->strides[rank - 1] = filter_size;
+        for(ii = rank - 2; ii >= 0; ii--) {
+            maybelong step = array_shape[ii + 1] < fshape[ii + 1] ?
+                                                                         array_shape[ii + 1] : fshape[ii + 1];
+            iterator->strides[ii] =  iterator->strides[ii + 1] * step;
+        }
+    }
+    for(ii = 0; ii < rank; ii++) {
+        maybelong step = array_shape[ii] < fshape[ii] ?
+                                                                                         array_shape[ii] : fshape[ii];
+        maybelong orgn = fshape[ii] / 2 + forigins[ii];
+        /* stride for stepping back to previous offsets: */
+        iterator->backstrides[ii] = (step - 1) * iterator->strides[ii];
+        /* initialize boundary extension sizes: */
+        iterator->bound1[ii] = orgn;
+        iterator->bound2[ii] = array_shape[ii] - fshape[ii] + orgn;
+    }
+    return 1;
+}
+
+/* Calculate the offsets to the filter points, for all border regions and
+     the interior of the array: */
+int NI_InitFilterOffsets(PyArrayObject *array, Bool *footprint,
+         maybelong *filter_shape, maybelong* origins,
+         NI_ExtendMode mode, maybelong **offsets, maybelong *border_flag_value,
+         maybelong **coordinate_offsets)
+{
+    int rank, ii;
+    maybelong kk, ll, filter_size = 1, offsets_size = 1, max_size = 0;
+    maybelong max_stride = 0, *ashape = NULL, *astrides = NULL;
+    maybelong footprint_size = 0, coordinates[MAXDIM], position[MAXDIM];
+    maybelong fshape[MAXDIM], forigins[MAXDIM], *po, *pc = NULL;
+
+    rank = array->nd;
+    ashape = array->dimensions;
+    astrides = array->strides;
+    for(ii = 0; ii < rank; ii++) {
+        fshape[ii] = *filter_shape++;
+        forigins[ii] = origins ? *origins++ : 0.0;
+    }
+    /* the size of the footprint array: */
+    for(ii = 0; ii < rank; ii++)
+        filter_size *= fshape[ii];
+    /* calculate the number of non-zero elements in the footprint: */
+    if (footprint) {
+        for(kk = 0; kk < filter_size; kk++)
+            if (footprint[kk])
+                ++footprint_size;
+    } else {
+        footprint_size = filter_size;
+    }
+    /* calculate how many sets of offsets must be stored: */
+    for(ii = 0; ii < rank; ii++)
+        offsets_size *= (ashape[ii] < fshape[ii] ? ashape[ii] : fshape[ii]);
+    /* allocate offsets data: */
+    *offsets = (maybelong*)malloc(offsets_size * footprint_size *
+                                                                                                                sizeof(maybelong));
+    if (!*offsets) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    if (coordinate_offsets) {
+        *coordinate_offsets = (maybelong*)malloc(offsets_size * rank *
+                                                                             footprint_size * sizeof(maybelong));
+        if (!*coordinate_offsets) {
+            PyErr_NoMemory();
+            goto exit;
+        }
+    }
+    for(ii = 0; ii < rank; ii++) {
+        maybelong stride;
+        /* find maximum axis size: */
+        if (ashape[ii] > max_size)
+            max_size = ashape[ii];
+        /* find maximum stride: */
+        stride = astrides[ii] < 0 ? -astrides[ii] : astrides[ii];
+        if (stride > max_stride)
+            max_stride = stride;
+        /* coordinates for iterating over the kernel elements: */
+        coordinates[ii] = 0;
+        /* keep track of the kernel position: */
+        position[ii] = 0;
+    }
+    /* the flag to indicate that we are outside the border must have a
+         value that is larger than any possible offset: */
+    *border_flag_value = max_size * max_stride + 1;
+    /* calculate all possible offsets to elements in the filter kernel,
+         for all regions in the array (interior and border regions): */
+    po = *offsets;
+    if (coordinate_offsets) {
+        pc = *coordinate_offsets;
+    }
+    /* iterate over all regions: */
+    for(ll = 0; ll < offsets_size; ll++) {
+        /* iterate over the elements in the footprint array: */
+        for(kk = 0; kk < filter_size; kk++) {
+            maybelong offset = 0;
+            /* only calculate an offset if the footprint is 1: */
+            if (!footprint || footprint[kk]) {
+                /* find offsets along all axes: */
+                for(ii = 0; ii < rank; ii++) {
+                    maybelong orgn = fshape[ii] / 2 + forigins[ii];
+                    maybelong cc = coordinates[ii] - orgn + position[ii];
+                    maybelong len = ashape[ii];
+                    /* apply boundary conditions, if necessary: */
+                    switch (mode) {
+                    case NI_EXTEND_MIRROR:
+                        if (cc < 0) {
+                            if (len <= 1) {
+                                cc = 0;
+                            } else {
+                                int sz2 = 2 * len - 2;
+                                cc = sz2 * (int)(-cc / sz2) + cc;
+                                cc = cc <= 1 - len ? cc + sz2 : -cc;
+                            }
+                        } else if (cc >= len) {
+                            if (len <= 1) {
+                                cc = 0;
+                            } else {
+                                int sz2 = 2 * len - 2;
+                                cc -= sz2 * (int)(cc / sz2);
+                                if (cc >= len)
+                                    cc = sz2 - cc;
+                            }
+                        }
+                        break;
+                    case NI_EXTEND_REFLECT:
+                        if (cc < 0) {
+                            if (len <= 1) {
+                                cc = 0;
+                            } else {
+                                int sz2 = 2 * len;
+                                if (cc < -sz2)
+                                    cc = sz2 * (int)(-cc / sz2) + cc;
+                                cc = cc < -len ? cc + sz2 : -cc - 1;
+                            }
+                        } else if (cc >= len) {
+                            if (len <= 1) {cc = 0;
+                            } else {
+                                int sz2 = 2 * len;
+                                cc -= sz2 * (int)(cc / sz2);
+                                if (cc >= len)
+                                    cc = sz2 - cc - 1;
+                            }
+                        }
+                        break;
+                    case NI_EXTEND_WRAP:
+                        if (cc < 0) {
+                            if (len <= 1) {
+                                cc = 0;
+                            } else {
+                                int sz = len;
+                                cc += sz * (int)(-cc / sz);
+                                if (cc < 0)
+                                    cc += sz;
+                            }
+                        } else if (cc >= len) {
+                            if (len <= 1) {
+                                cc = 0;
+                            } else {
+                                int sz = len;
+                                cc -= sz * (int)(cc / sz);
+                            }
+                        }
+                        break;
+                    case NI_EXTEND_NEAREST:
+                        if (cc < 0) {
+                            cc = 0;
+                        } else if (cc >= len) {
+                            cc = len - 1;
+                        }
+                        break;
+                    case NI_EXTEND_CONSTANT:
+                        if (cc < 0 || cc >= len)
+                            cc = *border_flag_value;
+                        break;
+                    default:
+                    PyErr_SetString(PyExc_RuntimeError,
+                                                                                    "boundary mode not supported");
+                        goto exit;
+                    }
+
+                    /* calculate offset along current axis: */
+                    if (cc == *border_flag_value) {
+                        /* just flag that we are outside the border */
+                        offset = *border_flag_value;
+                        if (coordinate_offsets)
+                            pc[ii] = 0;
+                        break;
+                    } else {
+                        /* use an offset that is possibly mapped from outside the
+                             border: */
+                        cc = cc - position[ii];
+                        offset += astrides[ii] * cc;
+                        if (coordinate_offsets)
+                            pc[ii] = cc;
+                    }
+                }
+                /* store the offset */
+                *po++ = offset;
+                if (coordinate_offsets)
+                    pc += rank;
+            }
+            /* next point in the filter: */
+            for(ii = rank - 1; ii >= 0; ii--) {
+                if (coordinates[ii] < fshape[ii] - 1) {
+                    coordinates[ii]++;
+                    break;
+                } else {
+                    coordinates[ii] = 0;
+                }
+            }
+        }
+
+        /* move to the next array region: */
+        for(ii = rank - 1; ii >= 0; ii--) {
+            int orgn = fshape[ii] / 2 + forigins[ii];
+            if (position[ii] == orgn) {
+                position[ii] += ashape[ii] - fshape[ii] + 1;
+                if (position[ii] <= orgn)
+                    position[ii] = orgn + 1;
+            } else {
+                position[ii]++;
+            }
+            if (position[ii] < ashape[ii]) {
+                break;
+            } else {
+                position[ii] = 0;
+            }
+        }
+    }
+
+ exit:
+    if (PyErr_Occurred()) {
+        if (*offsets)
+            free(*offsets);
+        if (coordinate_offsets && *coordinate_offsets)
+            free(*coordinate_offsets);
+        return 0;
+    } else {
+        return 1;
+    }
+}
+
+NI_CoordinateList* NI_InitCoordinateList(int size, int rank)
+{
+    NI_CoordinateList *list = \
+        (NI_CoordinateList*)malloc(sizeof(NI_CoordinateList));
+    if (!list) {
+        PyErr_NoMemory();
+        return NULL;
+    }
+    list->block_size = size;
+    list->rank = rank;
+    list->blocks = NULL;
+    return list;
+}
+
+int NI_CoordinateListStealBlocks(NI_CoordinateList *list1,
+                                                                 NI_CoordinateList *list2)
+{
+    if (list1->block_size != list2->block_size ||
+            list1->rank != list2->rank) {
+        PyErr_SetString(PyExc_RuntimeError, "coordinate lists not compatible");
+        return 1;
+    }
+    if (list1->blocks) {
+        PyErr_SetString(PyExc_RuntimeError, "first is list not empty");
+        return 1;
+    }
+    list1->blocks = list2->blocks;
+    list2->blocks = NULL;
+    return 0;
+}
+
+NI_CoordinateBlock* NI_CoordinateListAddBlock(NI_CoordinateList *list)
+{
+    NI_CoordinateBlock* block = NULL;
+    block = (NI_CoordinateBlock*)malloc(sizeof(NI_CoordinateBlock));
+    if (!block) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    block->coordinates = (maybelong*)malloc(list->block_size * list->rank *
+					  sizeof(maybelong));
+    if (!block->coordinates) {
+        PyErr_NoMemory();
+        goto exit;
+    }
+    block->next = list->blocks;
+    list->blocks = block;
+    block->size = 0;
+
+exit:
+    if (PyErr_Occurred()) {
+        if (block)
+            free(block);
+        return NULL;
+    }
+    return block;
+}
+
+NI_CoordinateBlock* NI_CoordinateListDeleteBlock(NI_CoordinateList *list)
+{
+    NI_CoordinateBlock* block = list->blocks;
+    if (block) {
+        list->blocks = block->next;
+        if (block->coordinates)
+            free(block->coordinates);
+        free(block);
+    }
+    return list->blocks;
+}
+
+void NI_FreeCoordinateList(NI_CoordinateList *list)
+{
+    if (list) {
+        NI_CoordinateBlock *block = list->blocks;
+        while (block) {
+            NI_CoordinateBlock *tmp = block;
+            block = block->next;
+            if (tmp->coordinates)
+                free(tmp->coordinates);
+            free(tmp);
+        }
+        list->blocks = NULL;
+        free(list);
+    }
+}

Added: branches/Interpolate1D/ndimage/ni_support.h
===================================================================
--- branches/Interpolate1D/ndimage/ni_support.h	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/ni_support.h	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,323 @@
+/* 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 NI_SUPPORT_H
+#define NI_SUPPORT_H
+
+#include "nd_image.h"
+#include <stdlib.h>
+#include <float.h>
+#include <limits.h>
+#include <assert.h>
+
+/* The different boundary conditions. The mirror condition is not used
+     by the python code, but C code is kept around in case we might wish
+     to add it. */
+typedef enum {
+    NI_EXTEND_FIRST = 0,
+    NI_EXTEND_NEAREST = 0,
+    NI_EXTEND_WRAP = 1,
+    NI_EXTEND_REFLECT = 2,
+    NI_EXTEND_MIRROR = 3,
+    NI_EXTEND_CONSTANT = 4,
+    NI_EXTEND_LAST = NI_EXTEND_CONSTANT,
+    NI_EXTEND_DEFAULT = NI_EXTEND_MIRROR
+} NI_ExtendMode;
+
+/******************************************************************/
+/* Iterators */
+/******************************************************************/
+
+/******************************************************************/
+/* Iterators */
+/******************************************************************/
+
+/* the iterator structure: */
+typedef struct {
+    int rank_m1;
+    maybelong dimensions[MAXDIM];
+    maybelong coordinates[MAXDIM];
+    maybelong strides[MAXDIM];
+    maybelong backstrides[MAXDIM];
+} NI_Iterator;
+
+/* initialize iterations over single array elements: */
+int NI_InitPointIterator(PyArrayObject*, NI_Iterator*);
+
+/* initialize iterations over an arbritrary sub-space: */
+int NI_SubspaceIterator(NI_Iterator*, UInt32);
+
+/* initialize iteration over array lines: */
+int NI_LineIterator(NI_Iterator*, int);
+
+/* reset an iterator */
+#define NI_ITERATOR_RESET(iterator)              \
+{                                                \
+    int _ii;                                       \
+    for(_ii = 0; _ii <= (iterator).rank_m1; _ii++) \
+        (iterator).coordinates[_ii] = 0;             \
+}
+
+/* go to the next point in a single array */
+#define NI_ITERATOR_NEXT(iterator, pointer)                         \
+{                                                                   \
+    int _ii;                                                          \
+    for(_ii = (iterator).rank_m1; _ii >= 0; _ii--)                    \
+        if ((iterator).coordinates[_ii] < (iterator).dimensions[_ii]) { \
+            (iterator).coordinates[_ii]++;                                \
+            pointer += (iterator).strides[_ii];                           \
+            break;                                                        \
+        } else {                                                        \
+            (iterator).coordinates[_ii] = 0;                              \
+            pointer -= (iterator).backstrides[_ii];                       \
+        }                                                               \
+}
+
+/* go to the next point in two arrays of the same size */
+#define NI_ITERATOR_NEXT2(iterator1, iterator2,  pointer1, pointer2)  \
+{                                                                     \
+    int _ii;                                                            \
+    for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--)                     \
+        if ((iterator1).coordinates[_ii] < (iterator1).dimensions[_ii]) { \
+            (iterator1).coordinates[_ii]++;                                 \
+            pointer1 += (iterator1).strides[_ii];                           \
+            pointer2 += (iterator2).strides[_ii];                           \
+            break;                                                          \
+        } else {                                                          \
+            (iterator1).coordinates[_ii] = 0;                               \
+            pointer1 -= (iterator1).backstrides[_ii];                       \
+            pointer2 -= (iterator2).backstrides[_ii];                       \
+        }                                                                 \
+}
+
+/* go to the next point in three arrays of the same size */
+#define NI_ITERATOR_NEXT3(iterator1, iterator2,  iterator3,           \
+                                                    pointer1, pointer2, pointer3)               \
+{                                                                     \
+    int _ii;                                                            \
+    for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--)                     \
+        if ((iterator1).coordinates[_ii] < (iterator1).dimensions[_ii]) { \
+            (iterator1).coordinates[_ii]++;                                 \
+            pointer1 += (iterator1).strides[_ii];                           \
+            pointer2 += (iterator2).strides[_ii];                           \
+            pointer3 += (iterator3).strides[_ii];                           \
+            break;                                                          \
+        } else {                                                          \
+            (iterator1).coordinates[_ii] = 0;                               \
+            pointer1 -= (iterator1).backstrides[_ii];                       \
+            pointer2 -= (iterator2).backstrides[_ii];                       \
+            pointer3 -= (iterator3).backstrides[_ii];                       \
+        }                                                                 \
+}
+
+/* go to an arbitrary point in a single array */
+#define NI_ITERATOR_GOTO(iterator, destination, base, pointer) \
+{                                                              \
+    int _ii;                                                     \
+    pointer = base;                                              \
+    for(_ii = (iterator).rank_m1; _ii >= 0; _ii--) {             \
+        pointer += destination[_ii] * (iterator).strides[_ii];     \
+        (iterator).coordinates[_ii] = destination[_ii];            \
+    }                                                            \
+}
+
+/******************************************************************/
+/* Line buffers */
+/******************************************************************/
+
+/* the linebuffer structure: */
+typedef struct {
+    double *buffer_data;
+    maybelong buffer_lines, line_length, line_stride;
+    maybelong size1, size2, array_lines, next_line;
+    NI_Iterator iterator;
+    char* array_data;
+    NumarrayType array_type;
+    NI_ExtendMode extend_mode;
+    double extend_value;
+} NI_LineBuffer;
+
+/* Get the next line being processed: */
+#define NI_GET_LINE(_buffer, _line)                                      \
+    ((_buffer).buffer_data + (_line) * ((_buffer).line_length +            \
+                                                                            (_buffer).size1 + (_buffer).size2))
+/* Allocate line buffer data */
+int NI_AllocateLineBuffer(PyArrayObject*, int, maybelong, maybelong,
+                                                    maybelong*, maybelong, double**);
+
+/* Initialize a line buffer */
+int NI_InitLineBuffer(PyArrayObject*, int, maybelong, maybelong, maybelong,
+                                            double*, NI_ExtendMode, double, NI_LineBuffer*);
+
+/* Extend a line in memory to implement boundary conditions: */
+int NI_ExtendLine(double*, maybelong, maybelong, maybelong, NI_ExtendMode, double);
+
+/* Copy a line from an array to a buffer: */
+int NI_ArrayToLineBuffer(NI_LineBuffer*, maybelong*, int*);
+
+/* Copy a line from a buffer to an array: */
+int NI_LineBufferToArray(NI_LineBuffer*);
+
+/******************************************************************/
+/* Multi-dimensional filter support functions */
+/******************************************************************/
+
+/* the filter iterator structure: */
+typedef struct {
+    maybelong strides[MAXDIM], backstrides[MAXDIM];
+    maybelong bound1[MAXDIM], bound2[MAXDIM];
+} NI_FilterIterator;
+
+/* Initialize a filter iterator: */
+int NI_InitFilterIterator(int, maybelong*, maybelong, maybelong*,
+                                                                                    maybelong*, NI_FilterIterator*);
+
+/* Calculate the offsets to the filter points, for all border regions and
+     the interior of the array: */
+int NI_InitFilterOffsets(PyArrayObject*, Bool*, maybelong*,
+                    maybelong*, NI_ExtendMode, maybelong**, maybelong*, maybelong**);
+
+/* Move to the next point in an array, possible changing the filter
+     offsets, to adapt to boundary conditions: */
+#define NI_FILTER_NEXT(iteratorf, iterator1, pointerf, pointer1)  \
+{                                                                 \
+    int _ii;                                                        \
+    for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--) {               \
+        maybelong _pp = (iterator1).coordinates[_ii];                 \
+        if (_pp < (iterator1).dimensions[_ii]) {                      \
+            if (_pp < (iteratorf).bound1[_ii] ||                        \
+                                                                    _pp >= (iteratorf).bound2[_ii]) \
+                pointerf += (iteratorf).strides[_ii];                     \
+            (iterator1).coordinates[_ii]++;                             \
+            pointer1 += (iterator1).strides[_ii];                       \
+            break;                                                      \
+        } else {                                                      \
+            (iterator1).coordinates[_ii] = 0;                           \
+            pointer1 -= (iterator1).backstrides[_ii];                   \
+            pointerf -= (iteratorf).backstrides[_ii];                   \
+        }                                                             \
+    }                                                               \
+}
+
+/* Move to the next point in two arrays, possible changing the pointer
+     to the filter offsets when moving into a different region in the
+     array: */
+#define NI_FILTER_NEXT2(iteratorf, iterator1, iterator2,    \
+                                                pointerf, pointer1, pointer2)       \
+{                                                           \
+    int _ii;                                                  \
+    for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--) {         \
+        maybelong _pp = (iterator1).coordinates[_ii];           \
+        if (_pp < (iterator1).dimensions[_ii]) {                \
+            if (_pp < (iteratorf).bound1[_ii] ||                  \
+                                                        _pp >= (iteratorf).bound2[_ii]) \
+                pointerf += (iteratorf).strides[_ii];               \
+            (iterator1).coordinates[_ii]++;                       \
+            pointer1 += (iterator1).strides[_ii];                 \
+            pointer2 += (iterator2).strides[_ii];                 \
+            break;                                                \
+        } else {                                                \
+            (iterator1).coordinates[_ii] = 0;                     \
+            pointer1 -= (iterator1).backstrides[_ii];             \
+            pointer2 -= (iterator2).backstrides[_ii];             \
+            pointerf -= (iteratorf).backstrides[_ii];             \
+        }                                                       \
+    }                                                         \
+}
+
+/* Move to the next point in three arrays, possible changing the pointer
+     to the filter offsets when moving into a different region in the
+     array: */
+#define NI_FILTER_NEXT3(iteratorf, iterator1, iterator2, iterator3,  \
+                                                pointerf, pointer1, pointer2, pointer3)      \
+{                                                                    \
+    int _ii;                                                           \
+    for(_ii = (iterator1).rank_m1; _ii >= 0; _ii--) {                  \
+        maybelong _pp = (iterator1).coordinates[_ii];                    \
+        if (_pp < (iterator1).dimensions[_ii]) {                         \
+            if (_pp < (iteratorf).bound1[_ii] ||                           \
+                                                                         _pp >= (iteratorf).bound2[_ii]) \
+                pointerf += (iteratorf).strides[_ii];                        \
+            (iterator1).coordinates[_ii]++;                                \
+            pointer1 += (iterator1).strides[_ii];                          \
+            pointer2 += (iterator2).strides[_ii];                          \
+            pointer3 += (iterator3).strides[_ii];                          \
+            break;                                                         \
+        } else {                                                         \
+            (iterator1).coordinates[_ii] = 0;                              \
+            pointer1 -= (iterator1).backstrides[_ii];                      \
+            pointer2 -= (iterator2).backstrides[_ii];                      \
+            pointer3 -= (iterator3).backstrides[_ii];                      \
+            pointerf -= (iteratorf).backstrides[_ii];                      \
+        }                                                                \
+    }                                                                  \
+}
+
+/* Move the pointer to the filter offsets according to the given
+    coordinates: */
+#define NI_FILTER_GOTO(iteratorf, iterator, fbase, pointerf) \
+{                                                            \
+    int _ii;                                                   \
+    maybelong _jj;                                             \
+    pointerf = fbase;                                          \
+    for(_ii = iterator.rank_m1; _ii >= 0; _ii--) {             \
+        maybelong _pp = iterator.coordinates[_ii];               \
+        maybelong b1 = (iteratorf).bound1[_ii];                  \
+        maybelong b2 = (iteratorf).bound2[_ii];                  \
+        if (_pp < b1) {                                          \
+                _jj = _pp;                                           \
+        } else if (_pp > b2 && b2 >= b1) {                       \
+                _jj = _pp + b1 - b2;                                 \
+        } else {                                                 \
+                _jj = b1;                                            \
+        }                                                        \
+        pointerf += (iteratorf).strides[_ii] * _jj;              \
+    }                                                          \
+}
+
+typedef struct {
+        maybelong *coordinates;
+        int size;
+        void *next;
+} NI_CoordinateBlock;
+
+typedef struct {
+        int block_size, rank;
+        void *blocks;
+} NI_CoordinateList;
+
+NI_CoordinateList* NI_InitCoordinateList(int, int);
+int NI_CoordinateListStealBlocks(NI_CoordinateList*, NI_CoordinateList*);
+NI_CoordinateBlock* NI_CoordinateListAddBlock(NI_CoordinateList*);
+NI_CoordinateBlock* NI_CoordinateListDeleteBlock(NI_CoordinateList*);
+void NI_FreeCoordinateList(NI_CoordinateList*);
+
+#endif

Added: branches/Interpolate1D/ndimage/register/Register_EXT.c
===================================================================
--- branches/Interpolate1D/ndimage/register/Register_EXT.c	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/register/Register_EXT.c	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,753 @@
+/* Python extension interface code */
+
+#include "Python.h"
+#include "numpy/arrayobject.h"
+
+static PyObject *Register_Histogram(PyObject *self, PyObject *args)
+{
+     /*
+       joint histogram memory is created in python to avoid memory leak problem 
+     */
+
+    int num;
+    int numM;
+    int nd;
+    int type;
+    int itype;
+    int nd_histo;
+    int nd_rotmatrix;
+    int nd_S;
+    npy_intp *dimsF;
+    npy_intp *dimsG;
+    npy_intp *dims_histo;
+    npy_intp *dims_rotmatrix;
+    npy_intp *dims_S;
+    unsigned char *imageG;
+    unsigned char *imageF;
+    double        *pHisto;
+    double        *M;
+    int           *S;
+    PyObject *imgArray1 = NULL;
+    PyObject *imgArray2 = NULL;
+    PyObject *rotArray  = NULL;
+    PyObject *SArray    = NULL;
+    PyObject *hArray    = NULL;
+	
+    if(!PyArg_ParseTuple(args, "OOOOO", &imgArray1, &imgArray2, &rotArray, &SArray, &hArray))
+	goto exit;
+
+    /* check in the Python code that F and G are the same dims, type */
+    imageF = (unsigned char *)PyArray_DATA(imgArray1);
+    imageG = (unsigned char *)PyArray_DATA(imgArray2);
+    nd     = PyArray_NDIM(imgArray1);
+    /* reads dims as 0 = layers, 1 = rows, 2 = cols */
+    dimsF  = PyArray_DIMS(imgArray1);
+    dimsG  = PyArray_DIMS(imgArray2);
+    type   = PyArray_TYPE(imgArray1);
+    num    = PyArray_SIZE(imgArray1);
+
+    M = (double *)PyArray_DATA(rotArray);
+    nd_rotmatrix   = PyArray_NDIM(rotArray);
+    dims_rotmatrix = PyArray_DIMS(rotArray);
+    numM           = PyArray_SIZE(rotArray);
+
+    S = (int *)PyArray_DATA(SArray);
+    nd_S   = PyArray_NDIM(SArray);
+    dims_S = PyArray_DIMS(SArray);
+
+    pHisto = (double *)PyArray_DATA(hArray);
+    nd_histo   = PyArray_NDIM(hArray);
+    dims_histo = PyArray_DIMS(hArray);
+    /* check to make sure this is 256x256  */
+
+    if(!NI_Histogram2D((int)dimsF[0], (int)dimsF[1], (int)dimsF[2], 
+                       (int)dimsG[0], (int)dimsG[1], (int)dimsG[2], 
+		       S, M, imageG, imageF, pHisto))
+	    goto exit;
+
+exit:
+
+    /* return the 2D histogram */
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue(""); 
+
+}
+
+
+static PyObject *Register_HistogramLite(PyObject *self, PyObject *args)
+{
+     /*
+       joint histogram memory is created in python to avoid memory leak problem 
+     */
+
+    int num;
+    int numG;
+    int nd;
+    int type;
+    int itype;
+    int nd_histo;
+    int nd_rotmatrix;
+    int nd_S;
+    npy_intp *dimsF;
+    npy_intp *dimsG;
+    npy_intp *dims_histo;
+    npy_intp *dims_rotmatrix;
+    npy_intp *dims_S;
+    unsigned char *imageG;
+    unsigned char *imageF;
+    double        *pHisto;
+    double        *M;
+    int           *S;
+    PyObject *imgArray1 = NULL;
+    PyObject *imgArray2 = NULL;
+    PyObject *rotArray  = NULL;
+    PyObject *SArray    = NULL;
+    PyObject *hArray    = NULL;
+	
+    if(!PyArg_ParseTuple(args, "OOOOO", &imgArray1, &imgArray2, &rotArray, &SArray, &hArray))
+	goto exit;
+
+    /* check in the Python code that F and G are the same dims, type */
+    imageF = (unsigned char *)PyArray_DATA(imgArray1);
+    imageG = (unsigned char *)PyArray_DATA(imgArray2);
+    /* reads dims as 0 = layers, 1 = rows, 2 = cols */
+    nd     = PyArray_NDIM(imgArray1);
+    dimsF  = PyArray_DIMS(imgArray1);
+    dimsG  = PyArray_DIMS(imgArray2);
+    type   = PyArray_TYPE(imgArray1);
+    num    = PyArray_SIZE(imgArray1);
+    numG   = PyArray_SIZE(imgArray2);
+
+    M = (double *)PyArray_DATA(rotArray);
+    nd_rotmatrix   = PyArray_NDIM(rotArray);
+    dims_rotmatrix = PyArray_DIMS(rotArray);
+
+    S = (int *)PyArray_DATA(SArray);
+    nd_S   = PyArray_NDIM(SArray);
+    dims_S = PyArray_DIMS(SArray);
+
+    pHisto = (double *)PyArray_DATA(hArray);
+    nd_histo   = PyArray_NDIM(hArray);
+    dims_histo = PyArray_DIMS(hArray);
+    /* check to make sure this is 256x256  */
+
+    if(!NI_Histogram2DLite((int)dimsF[0], (int)dimsF[1], (int)dimsF[2], 
+                           (int)dimsG[0], (int)dimsG[1], (int)dimsG[2], 
+		            S, M, imageG, imageF, pHisto))
+	    goto exit;
+
+exit:
+
+    /* return the 2D histogram */
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue(""); 
+
+}
+
+static PyObject *Register_VolumeResample(PyObject *self, PyObject *args)
+{
+
+    int num;
+    int nd;
+    int type;
+    int itype;
+    int mode;
+    int scale;
+    npy_intp *dimsF;
+    npy_intp *dimsG;
+    unsigned char *imageG;
+    unsigned char *imageF;
+    double        *Z;
+    PyObject *imgArray1 = NULL;
+    PyObject *imgArray2 = NULL;
+    PyObject *coordZoom = NULL;
+	
+    if(!PyArg_ParseTuple(args, "OOOii", &imgArray1, &imgArray2, &coordZoom, &scale, &mode))
+	goto exit;
+
+    /* check in the Python code that F and G are the same dims, type */
+    imageF = (unsigned char *)PyArray_DATA(imgArray1);
+    imageG = (unsigned char *)PyArray_DATA(imgArray2);
+    Z = (double *)PyArray_DATA(coordZoom);
+    /* reads dims as 0 = layers, 1 = rows, 2 = cols */
+    nd     = PyArray_NDIM(imgArray1);
+    dimsF  = PyArray_DIMS(imgArray1);
+    dimsG  = PyArray_DIMS(imgArray2);
+    type   = PyArray_TYPE(imgArray1);
+    num    = PyArray_SIZE(imgArray1);
+
+    if(!NI_VolumeResample((int)dimsF[0], (int)dimsF[1], (int)dimsF[2], 
+                         (int)dimsG[0], (int)dimsG[1], (int)dimsG[2], 
+		          scale, mode, imageG, imageF, Z))
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue(""); 
+
+}
+
+
+
+static PyObject *Register_CubicResample(PyObject *self, PyObject *args)
+{
+
+    int num;
+    int nd;
+    int type;
+    int itype;
+    int nd_rotmatrix;
+    int nd_S;
+    npy_intp *dimsF;
+    npy_intp *dimsG;
+    npy_intp *dims_rotmatrix;
+    npy_intp *dims_S;
+    unsigned char *imageG;
+    unsigned char *imageF;
+    double        *M;
+    int           *S;
+    PyObject *imgArray1 = NULL;
+    PyObject *imgArray2 = NULL;
+    PyObject *rotArray  = NULL;
+    PyObject *SArray    = NULL;
+	
+    if(!PyArg_ParseTuple(args, "OOOO", &imgArray1, &imgArray2, &rotArray, &SArray))
+	goto exit;
+
+    /* check in the Python code that F and G are the same dims, type */
+    imageF = (unsigned char *)PyArray_DATA(imgArray1);
+    imageG = (unsigned char *)PyArray_DATA(imgArray2);
+    /* reads dims as 0 = layers, 1 = rows, 2 = cols */
+    nd     = PyArray_NDIM(imgArray1);
+    dimsF  = PyArray_DIMS(imgArray1);
+    dimsG  = PyArray_DIMS(imgArray2);
+    type   = PyArray_TYPE(imgArray1);
+    num    = PyArray_SIZE(imgArray1);
+
+    M = (double *)PyArray_DATA(rotArray);
+    nd_rotmatrix   = PyArray_NDIM(rotArray);
+    dims_rotmatrix = PyArray_DIMS(rotArray);
+
+    S = (int *)PyArray_DATA(SArray);
+    nd_S   = PyArray_NDIM(SArray);
+    dims_S = PyArray_DIMS(SArray);
+
+    if(!NI_CubicResample((int)dimsF[0], (int)dimsF[1], (int)dimsF[2], 
+                         (int)dimsG[0], (int)dimsG[1], (int)dimsG[2], 
+		          S, M, imageG, imageF))
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue(""); 
+
+}
+
+
+static PyObject *Register_LinearResample(PyObject *self, PyObject *args)
+{
+
+    int num;
+    int nd;
+    int type;
+    int itype;
+    int nd_rotmatrix;
+    int nd_S;
+    npy_intp *dimsF;
+    npy_intp *dimsG;
+    npy_intp *dims_rotmatrix;
+    npy_intp *dims_S;
+    unsigned char *imageG;
+    unsigned char *imageF;
+    double        *M;
+    int           *S;
+    PyObject *imgArray1 = NULL;
+    PyObject *imgArray2 = NULL;
+    PyObject *rotArray  = NULL;
+    PyObject *SArray    = NULL;
+	
+    if(!PyArg_ParseTuple(args, "OOOO", &imgArray1, &imgArray2, &rotArray, &SArray))
+	goto exit;
+
+    /* check in the Python code that F and G are the same dims, type */
+    imageF = (unsigned char *)PyArray_DATA(imgArray1);
+    imageG = (unsigned char *)PyArray_DATA(imgArray2);
+    /* reads dims as 0 = layers, 1 = rows, 2 = cols */
+    nd     = PyArray_NDIM(imgArray1);
+    dimsF  = PyArray_DIMS(imgArray1);
+    dimsG  = PyArray_DIMS(imgArray2);
+    type   = PyArray_TYPE(imgArray1);
+    num    = PyArray_SIZE(imgArray1);
+
+    M = (double *)PyArray_DATA(rotArray);
+    nd_rotmatrix   = PyArray_NDIM(rotArray);
+    dims_rotmatrix = PyArray_DIMS(rotArray);
+
+    S = (int *)PyArray_DATA(SArray);
+    nd_S   = PyArray_NDIM(SArray);
+    dims_S = PyArray_DIMS(SArray);
+
+    if(!NI_LinearResample((int)dimsF[0], (int)dimsF[1], (int)dimsF[2], 
+                          (int)dimsG[0], (int)dimsG[1], (int)dimsG[2], 
+		           S, M, imageG, imageF))
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue(""); 
+
+}
+
+
+static PyObject *Register_ImageThreshold(PyObject *self, PyObject *args)
+{
+
+    /* set threshold from the volume integrated histogram */
+    int num;
+    int nd;
+    int type;
+    int itype;
+    int histogram_elements;
+    int	tindex;
+    npy_intp *dimsImage;
+    npy_intp *dimsHistogram;
+    unsigned short *image;
+    double *H;
+    double *IH;
+    double threshold;
+    PyObject *imgArray   = NULL;
+    PyObject *histogram  = NULL;
+    PyObject *ihistogram = NULL;
+	
+    if(!PyArg_ParseTuple(args, "OOOd", &imgArray, &histogram, &ihistogram, &threshold))
+	goto exit;
+
+    image = (unsigned short *)PyArray_DATA(imgArray);
+    /* reads dims as 0 = layers, 1 = rows, 2 = cols */
+    nd        = PyArray_NDIM(imgArray);
+    dimsImage = PyArray_DIMS(imgArray);
+    type      = PyArray_TYPE(imgArray);
+    num       = PyArray_SIZE(imgArray);
+
+    H  = (double *)PyArray_DATA(histogram);
+    IH = (double *)PyArray_DATA(ihistogram);
+    histogram_elements = PyArray_SIZE(histogram);
+
+    if(!NI_ImageThreshold((int)dimsImage[0], (int)dimsImage[1], (int)dimsImage[2], 
+		               image, H, IH, histogram_elements, threshold, &tindex))
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("i", tindex); 
+
+}
+
+
+static PyObject *Register_ResampleWithGradient(PyObject *self, PyObject *args)
+{
+
+    int num;
+    int nd;
+    int type;
+    int itype;
+    int nd_rotmatrix;
+    int nd_S;
+    npy_intp *dimsScale;
+    npy_intp *dimsOffset;
+    npy_intp *dimsS;
+    npy_intp *dimsD;
+    npy_intp *dims_rotmatrix;
+    npy_intp *dims_S;
+    unsigned char *imageS;
+    unsigned char *imageD;
+    double        *M;
+    int           *S;
+    double        *scale;
+    int           *offset;
+    double        *gradientX;
+    double        *gradientY;
+    double        *gradientZ;
+    PyObject *imgArrayS   = NULL;
+    PyObject *imgArrayD   = NULL;
+    PyObject *rotArray    = NULL;
+    PyObject *SArray      = NULL;
+    PyObject *scaleArray  = NULL;
+    PyObject *offsetArray = NULL;
+    PyObject *gradXArray  = NULL;
+    PyObject *gradYArray  = NULL;
+    PyObject *gradZArray  = NULL;
+	
+    if(!PyArg_ParseTuple(args, "OOOOOOOOO", &imgArrayS, &imgArrayD, &rotArray, &SArray, &scaleArray,
+			                    &offsetArray, &gradXArray, &gradYArray, &gradZArray))
+	goto exit;
+
+    /* check in the Python code that S and D are the same dims, type */
+    imageS = (unsigned char *)PyArray_DATA(imgArrayS);
+    imageD = (unsigned char *)PyArray_DATA(imgArrayD);
+    /* reads dims as 0 = layers, 1 = rows, 2 = cols */
+    nd     = PyArray_NDIM(imgArrayS);
+    dimsS  = PyArray_DIMS(imgArrayS);
+    dimsD  = PyArray_DIMS(imgArrayD);
+    type   = PyArray_TYPE(imgArrayS);
+    num    = PyArray_SIZE(imgArrayS);
+
+    M = (double *)PyArray_DATA(rotArray);
+    nd_rotmatrix   = PyArray_NDIM(rotArray);
+    dims_rotmatrix = PyArray_DIMS(rotArray);
+
+    S = (int *)PyArray_DATA(SArray);
+    nd_S   = PyArray_NDIM(SArray);
+    dims_S = PyArray_DIMS(SArray);
+
+    scale  = (double *)PyArray_DATA(scaleArray);
+    offset = (int *)PyArray_DATA(offsetArray);
+    dimsScale  = PyArray_DIMS(scaleArray);
+    dimsOffset = PyArray_DIMS(offsetArray);
+
+    gradientX = (double *)PyArray_DATA(gradXArray);
+    gradientY = (double *)PyArray_DATA(gradYArray);
+    gradientZ = (double *)PyArray_DATA(gradZArray);
+
+    if(!NI_ResampleWithGradient((int)dimsS[0], (int)dimsS[1], (int)dimsS[2], 
+                                (int)dimsD[0], (int)dimsD[1], (int)dimsD[2], 
+		                 S, M, imageD, imageS, scale, offset, gradientX,
+				 gradientY, gradientZ))
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue(""); 
+
+}
+
+
+static PyObject *Register_Find_Mask(PyObject *self, PyObject *args)
+{
+
+    int i;
+    int num;
+    int length;
+    double  *X;
+    double  *Y;
+    double  *Z;
+    int     *xLims;
+    int     *yLims;
+    int     *zLims;
+    int     *mask;
+    PyObject *MArray   = NULL;
+    PyObject *XArray   = NULL;
+    PyObject *YArray   = NULL;
+    PyObject *ZArray   = NULL;
+    PyObject *XLimits  = NULL;
+    PyObject *YLimits  = NULL;
+    PyObject *ZLimits  = NULL;
+	
+    if(!PyArg_ParseTuple(args, "OOOOOOO", &MArray, &XArray, &YArray, &ZArray, &XLimits, &YLimits, &ZLimits))
+	goto exit;
+
+    num   = PyArray_SIZE(XArray);
+    X     = (double *)PyArray_DATA(XArray);
+    Y     = (double *)PyArray_DATA(YArray);
+    Z     = (double *)PyArray_DATA(ZArray);
+    mask  = (int *)PyArray_DATA(MArray);
+    xLims = (int *)PyArray_DATA(XLimits);
+    yLims = (int *)PyArray_DATA(YLimits);
+    zLims = (int *)PyArray_DATA(ZLimits);
+
+    for(length = 0, i = 0; i < num; ++i){
+	if( ((X[i] >= xLims[0]) && (X[i] <= xLims[1])) &&
+	    ((Y[i] >= yLims[0]) && (Y[i] <= yLims[1])) &&
+	    ((Z[i] >= zLims[0]) && (Z[i] <= zLims[1])) ){
+	    mask[length++] = i;
+	}
+    } 
+
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("i", length); 
+
+}
+
+
+
+static PyObject *Register_Resample_Gradient_Coords(PyObject *self, PyObject *args)
+{
+
+    int num;
+    int size;
+    int nd;
+    int type;
+    int itype;
+    int nd_S;
+    npy_intp *dimsScale;
+    npy_intp *dimsOffset;
+    npy_intp *dimsS;
+    npy_intp *dimsD;
+    npy_intp *dims_S;
+    npy_intp *dims_Coords;
+    unsigned char *imageS;
+    unsigned char *imageD;
+    double        *X;
+    double        *Y;
+    double        *Z;
+    int           *S;
+    double        *scale;
+    int           *offset;
+    double        *gradientX;
+    double        *gradientY;
+    double        *gradientZ;
+    PyObject *imgArrayS    = NULL;
+    PyObject *imgArrayD    = NULL;
+    PyObject *SArray       = NULL;
+    PyObject *scaleArray   = NULL;
+    PyObject *offsetArray  = NULL;
+    PyObject *gradXArray   = NULL;
+    PyObject *gradYArray   = NULL;
+    PyObject *gradZArray   = NULL;
+    PyObject *coordXArray  = NULL;
+    PyObject *coordYArray  = NULL;
+    PyObject *coordZArray  = NULL;
+	
+    if(!PyArg_ParseTuple(args, "OOOOOOOOOOO", &coordZArray, &coordYArray, &coordXArray,
+                                &imgArrayS, &imgArrayD, &SArray, &scaleArray, &offsetArray,
+			        &gradXArray, &gradYArray, &gradZArray))
+	goto exit;
+
+    /* check in the Python code that S and D are the same dims, type */
+    imageS = (unsigned char *)PyArray_DATA(imgArrayS);
+    imageD = (unsigned char *)PyArray_DATA(imgArrayD);
+    /* reads dims as 0 = layers, 1 = rows, 2 = cols */
+    nd     = PyArray_NDIM(imgArrayS);
+    dimsS  = PyArray_DIMS(imgArrayS);
+    dimsD  = PyArray_DIMS(imgArrayD);
+    type   = PyArray_TYPE(imgArrayS);
+    num    = PyArray_SIZE(imgArrayS);
+
+    S = (int *)PyArray_DATA(SArray);
+    nd_S   = PyArray_NDIM(SArray);
+    dims_S = PyArray_DIMS(SArray);
+
+    scale  = (double *)PyArray_DATA(scaleArray);
+    offset = (int *)PyArray_DATA(offsetArray);
+    dimsScale  = PyArray_DIMS(scaleArray);
+    dimsOffset = PyArray_DIMS(offsetArray);
+
+    gradientX = (double *)PyArray_DATA(gradXArray);
+    gradientY = (double *)PyArray_DATA(gradYArray);
+    gradientZ = (double *)PyArray_DATA(gradZArray);
+
+    X = (double *)PyArray_DATA(coordXArray);
+    Y = (double *)PyArray_DATA(coordYArray);
+    Z = (double *)PyArray_DATA(coordZArray);
+
+    dims_Coords = PyArray_DIMS(coordXArray);
+    size = PyArray_SIZE(coordXArray);
+
+    if(!NI_Resample_Gradient_Coords(size, (int)dimsS[0], (int)dimsS[1], (int)dimsS[2], (int)dimsD[0], 
+			           (int)dimsD[1], (int)dimsD[2], S, X, Y, Z, imageD, imageS, scale, 
+				   offset, gradientX, gradientY, gradientZ))
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue(""); 
+
+}
+
+
+
+static PyObject *Register_Resample_Coords(PyObject *self, PyObject *args)
+{
+
+    int num;
+    int size;
+    int nd;
+    int type;
+    int itype;
+    int nd_S;
+    npy_intp *dimsScale;
+    npy_intp *dimsOffset;
+    npy_intp *dimsS;
+    npy_intp *dimsD;
+    npy_intp *dims_S;
+    npy_intp *dims_Coords;
+    unsigned char *imageS;
+    unsigned char *imageD;
+    double        *X;
+    double        *Y;
+    double        *Z;
+    int           *S;
+    double        *scale;
+    int           *offset;
+    PyObject *imgArrayS    = NULL;
+    PyObject *imgArrayD    = NULL;
+    PyObject *SArray       = NULL;
+    PyObject *scaleArray   = NULL;
+    PyObject *offsetArray  = NULL;
+    PyObject *coordXArray  = NULL;
+    PyObject *coordYArray  = NULL;
+    PyObject *coordZArray  = NULL;
+	
+    if(!PyArg_ParseTuple(args, "OOOOOOOO", &coordZArray, &coordYArray, &coordXArray,
+                                &imgArrayS, &imgArrayD, &SArray, &scaleArray, &offsetArray))
+	goto exit;
+
+    /* check in the Python code that S and D are the same dims, type */
+    imageS = (unsigned char *)PyArray_DATA(imgArrayS);
+    imageD = (unsigned char *)PyArray_DATA(imgArrayD);
+    /* reads dims as 0 = layers, 1 = rows, 2 = cols */
+    nd     = PyArray_NDIM(imgArrayS);
+    dimsS  = PyArray_DIMS(imgArrayS);
+    dimsD  = PyArray_DIMS(imgArrayD);
+    type   = PyArray_TYPE(imgArrayS);
+    num    = PyArray_SIZE(imgArrayS);
+
+    S = (int *)PyArray_DATA(SArray);
+    nd_S   = PyArray_NDIM(SArray);
+    dims_S = PyArray_DIMS(SArray);
+
+    scale  = (double *)PyArray_DATA(scaleArray);
+    offset = (int *)PyArray_DATA(offsetArray);
+    dimsScale  = PyArray_DIMS(scaleArray);
+    dimsOffset = PyArray_DIMS(offsetArray);
+
+    X = (double *)PyArray_DATA(coordXArray);
+    Y = (double *)PyArray_DATA(coordYArray);
+    Z = (double *)PyArray_DATA(coordZArray);
+
+    dims_Coords = PyArray_DIMS(coordXArray);
+    size = PyArray_SIZE(coordXArray);
+
+    if(!NI_Resample_Coords(size, (int)dimsS[0], (int)dimsS[1], (int)dimsS[2], (int)dimsD[0], 
+		           (int)dimsD[1], (int)dimsD[2], S, X, Y, Z, imageD, imageS, scale, offset)) 
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue(""); 
+
+}
+
+
+static PyObject *Register_Complete_Symmetry(PyObject *self, PyObject *args)
+{
+
+    int nx;
+    int ny;
+    int nz;
+    int ni;
+    double   *A;
+    PyObject *AlphaArray = NULL;
+
+    if(!PyArg_ParseTuple(args, "Oiiii", &AlphaArray, &nx, &ny, &nz, &ni))
+	goto exit;
+
+    A = (double *)PyArray_DATA(AlphaArray);
+
+    if(!NI_Complete_Symmetry(A, nx, ny, nz, ni)) 
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue(""); 
+
+}
+
+
+
+static PyObject *Register_LT_Tensor_Product(PyObject *self, PyObject *args)
+{
+    int M1;
+    int M2;
+    int rows;
+    int cur_row;
+    int coeff_1;
+    int coeff_2;
+    double   *A1;
+    double   *A2;
+    double   *B1;
+    double   *B2;
+    double   *Basis;
+    PyObject *AlphaArray1 = NULL;
+    PyObject *AlphaArray2 = NULL;
+    PyObject *BetaArray1  = NULL;
+    PyObject *BetaArray2  = NULL;
+    PyObject *BasisArray  = NULL;
+
+    if(!PyArg_ParseTuple(args, "OOOOOiiiiii", &AlphaArray1, &AlphaArray2, &BetaArray1, &BetaArray2, 
+		         &BasisArray, &M1, &M2, &rows, &cur_row, &coeff_1, &coeff_2))
+	goto exit;
+
+    A1    = (double *)PyArray_DATA(AlphaArray1);
+    A2    = (double *)PyArray_DATA(AlphaArray2);
+    B1    = (double *)PyArray_DATA(BetaArray1);
+    B2    = (double *)PyArray_DATA(BetaArray2);
+    Basis = (double *)PyArray_DATA(BasisArray);
+
+    if(!NI_LT_Tensor_Product(A1, A2, B1, B2, Basis, M1, M2, rows, cur_row, coeff_1, coeff_2)) 
+	    goto exit;
+
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue(""); 
+
+}
+
+
+
+static PyObject *Register_LT_Mrqcof(PyObject *self, PyObject *args)
+{
+
+    int M1;
+    double   wt;
+    double   value;
+    double   *A;
+    double   *B;
+    double   *V;
+    PyObject *AlphaArray = NULL;
+    PyObject *BetaArray  = NULL;
+    PyObject *VArray     = NULL;
+
+    if(!PyArg_ParseTuple(args, "OOOddi", &AlphaArray, &BetaArray, &VArray, &wt, &value, &M1))
+	goto exit;
+
+    A = (double *)PyArray_DATA(AlphaArray);
+    B = (double *)PyArray_DATA(BetaArray);
+    V = (double *)PyArray_DATA(VArray);
+
+    if(!NI_LT_Mrqcof(A, B, V, wt, value, M1)) 
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue(""); 
+
+}
+
+
+static PyMethodDef RegisterMethods[] =
+{
+    { "register_complete_symmetry",             Register_Complete_Symmetry,        METH_VARARGS, NULL },
+    { "register_lt_mrqcof",                     Register_LT_Mrqcof,                METH_VARARGS, NULL },
+    { "register_lt_tensor_product",             Register_LT_Tensor_Product,        METH_VARARGS, NULL },
+    { "register_find_mask",                     Register_Find_Mask,                METH_VARARGS, NULL },
+    { "register_resample_coords",               Register_Resample_Coords,          METH_VARARGS, NULL },
+    { "register_resample_gradient_coords",      Register_Resample_Gradient_Coords, METH_VARARGS, NULL },
+    { "register_resample_w_gradient",           Register_ResampleWithGradient,     METH_VARARGS, NULL },
+    { "register_histogram",                     Register_Histogram,                METH_VARARGS, NULL },
+    { "register_histogram_lite",                Register_HistogramLite,            METH_VARARGS, NULL },
+    { "register_linear_resample",               Register_LinearResample,           METH_VARARGS, NULL },
+    { "register_cubic_resample",                Register_CubicResample,            METH_VARARGS, NULL },
+    { "register_volume_resample",               Register_VolumeResample,           METH_VARARGS, NULL },
+    { "register_image_threshold",               Register_ImageThreshold,           METH_VARARGS, NULL },
+    {  NULL, NULL, 0, NULL},
+};
+
+PyMODINIT_FUNC init_register(void)
+{
+    Py_InitModule("_register", RegisterMethods);
+    import_array();
+}
+
+

Added: branches/Interpolate1D/ndimage/register/Register_IMPL.c
===================================================================
--- branches/Interpolate1D/ndimage/register/Register_IMPL.c	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/register/Register_IMPL.c	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,1369 @@
+#include<stdio.h>
+#include<stdlib.h>
+
+float tri_cubic_convolve(unsigned char *pVolume, int x, int y, int z, float xp, float yp,
+	                 float zp, int colsG, int rowsG, int layersG, int sliceSizeG){
+
+	int i, j, k;
+	int layerOffsets[4];
+	int rowOffsets[4];
+	float ps1, ps2, ps3;
+	float Y[4], NewRow[4], NewLayer[4];
+	float R, C, L, D, T;
+	float valueXYZ = 0.0;
+	float dataCube[4][4][4];
+	/*            [cols][rows][layers] */
+
+	rowOffsets[0]   = (y-1)*colsG;
+	rowOffsets[1]   = (y  )*colsG;
+	rowOffsets[2]   = (y+1)*colsG;
+	rowOffsets[3]   = (y+2)*colsG;
+
+	layerOffsets[0] = (z-1)*sliceSizeG;
+	layerOffsets[1] = (z  )*sliceSizeG;
+	layerOffsets[2] = (z+1)*sliceSizeG;
+	layerOffsets[3] = (z+2)*sliceSizeG;
+
+	/* get numerator for interpolation */
+	C = xp - (float)x;
+	R = yp - (float)y;
+	L = zp - (float)z;
+	D = (float)0.002;
+
+	/* get 4x4 window over all 4 layers */
+	for(i = 0; i < 4; ++i){
+	    for(j = 0; j < 4; ++j){
+		dataCube[0][j][i] = (float)pVolume[layerOffsets[i]+rowOffsets[j]+x-1];
+		dataCube[1][j][i] = (float)pVolume[layerOffsets[i]+rowOffsets[j]+x];
+		dataCube[2][j][i] = (float)pVolume[layerOffsets[i]+rowOffsets[j]+x+1];
+		dataCube[3][j][i] = (float)pVolume[layerOffsets[i]+rowOffsets[j]+x+2];
+	    }
+	}
+
+	for(i = 0; i < 4; ++i){
+	    /* interpolate 4 rows in all 4 layers */
+	    for(j = 0; j < 4; ++j){
+		if(C > D){
+		    Y[0] = dataCube[0][j][i];
+		    Y[1] = dataCube[1][j][i];
+		    Y[2] = dataCube[2][j][i];
+		    Y[3] = dataCube[3][j][i];
+		    ps1       = Y[2] - Y[0];
+		    ps2       = (float)2.0*(Y[0] - Y[1]) + Y[2] - Y[3];
+		    ps3       = -Y[0] + Y[1] - Y[2] + Y[3];
+		    NewRow[j] = Y[1]+C*(ps1+C*(ps2+C*ps3));
+		}
+		else{
+		    NewRow[j] = dataCube[1][j][i];
+		}
+	    }
+	    /* interpolate across 4 columns */
+	    if(R > D){
+		Y[0] = NewRow[0];
+		Y[1] = NewRow[1];
+		Y[2] = NewRow[2];
+		Y[3] = NewRow[3];
+		ps1  = Y[2] - Y[0];
+		ps2  = (float)2.0*(Y[0] - Y[1]) + Y[2] - Y[3];
+		ps3  = -Y[0] + Y[1] - Y[2] + Y[3];
+		T    = (Y[1]+R*(ps1+R*(ps2+R*ps3)));
+		NewLayer[i] = T;
+	    }
+	    else{
+		T = NewRow[1];
+		NewLayer[i] = T;
+	    } 
+	}
+	/* interpolate across 4 layers */
+	if(L > D){
+	    Y[0] = NewLayer[0];
+	    Y[1] = NewLayer[1];
+	    Y[2] = NewLayer[2];
+	    Y[3] = NewLayer[3];
+	    ps1  = Y[2] - Y[0];
+	    ps2  = (float)2.0*(Y[0] - Y[1]) + Y[2] - Y[3];
+	    ps3  = -Y[0] + Y[1] - Y[2] + Y[3];
+	    T    = (Y[1]+L*(ps1+L*(ps2+L*ps3)));
+	    valueXYZ = T;
+	}
+	else{
+	    T = NewLayer[1];
+	    valueXYZ = T;
+	} 
+
+	return(valueXYZ);
+
+}
+
+float trilinear_A(unsigned char *pVolume, int x, int y, int z, float dx, float dy, float dz, int dims[]){
+
+	// Vxyz for [0,1] values of x, y, z
+	int V000;
+	int V100;
+	int V010;
+	int V001;
+	int V011;
+	int V101;
+	int V110;
+	int V111;
+
+	int ptr_x0;
+	int ptr_y0;
+	int ptr_z0;
+
+	int ptr_x1;
+	int ptr_y1;
+	int ptr_z1;
+
+	float valueXYZ;
+
+	ptr_x0 = x;
+	ptr_y0 = y * dims[0];
+	ptr_z0 = z * dims[1];
+
+	ptr_x1 = ptr_x0 + 1;
+	ptr_y1 = ptr_y0 + dims[0];
+	ptr_z1 = ptr_z0 + dims[1];
+
+	V000 = pVolume[ptr_x0+ptr_y0+ptr_z0];
+	V100 = pVolume[ptr_x1+ptr_y0+ptr_z0];
+	V010 = pVolume[ptr_x0+ptr_y1+ptr_z0];
+	V001 = pVolume[ptr_x0+ptr_y0+ptr_z1];
+	V011 = pVolume[ptr_x0+ptr_y1+ptr_z1];
+	V101 = pVolume[ptr_x1+ptr_y0+ptr_z1];
+	V110 = pVolume[ptr_x1+ptr_y1+ptr_z0];
+	V111 = pVolume[ptr_x1+ptr_y1+ptr_z1];
+
+	// dx, dy, dz are increments in x, y, z
+	// dx = 0 is x = 1 as x, y and z are [0, 1] in range
+
+	valueXYZ = 
+		V000 * (1.0-dx) * (1.0 - dy) * (1.0 - dz) +
+		V100 * (dx)     * (1.0 - dy) * (1.0 - dz) +
+		V010 * (1.0-dx) * (dy)       * (1.0 - dz) +
+		V001 * (1.0-dx) * (1.0 - dy) * (dz)       +
+		V101 * (dx)     * (1.0 - dy) * (dz)       +
+		V011 * (1.0-dx) * (dy)       * (dz)       +
+		V110 * (dx)     * (dy)       * (1.0 - dz) +
+		V111 * (dx)     * (dy)       * (dz);
+
+
+	return(valueXYZ);
+
+}
+
+float trilinear_B(unsigned char *pVolume, float dx, float dy, float dz, int corners[]){
+
+	// Vxyz for [0,1] values of x, y, z
+	int V000;
+	int V100;
+	int V010;
+	int V001;
+	int V011;
+	int V101;
+	int V110;
+	int V111;
+
+	int ptr_x0 = corners[0];
+	int ptr_y0 = corners[1];
+	int ptr_z0 = corners[2];
+
+	int ptr_x1 = corners[3];
+	int ptr_y1 = corners[4];
+	int ptr_z1 = corners[5];
+
+	float valueXYZ;
+
+	V000 = pVolume[ptr_x0+ptr_y0+ptr_z0];
+	V100 = pVolume[ptr_x1+ptr_y0+ptr_z0];
+	V010 = pVolume[ptr_x0+ptr_y1+ptr_z0];
+	V001 = pVolume[ptr_x0+ptr_y0+ptr_z1];
+	V011 = pVolume[ptr_x0+ptr_y1+ptr_z1];
+	V101 = pVolume[ptr_x1+ptr_y0+ptr_z1];
+	V110 = pVolume[ptr_x1+ptr_y1+ptr_z0];
+	V111 = pVolume[ptr_x1+ptr_y1+ptr_z1];
+
+	// dx, dy, dz are increments in x, y, z
+	// dx = 0 is x = 1 as x, y and z are [0, 1] in range
+
+	valueXYZ = 
+		V000 * (1.0-dx) * (1.0 - dy) * (1.0 - dz) +
+		V100 * (dx)     * (1.0 - dy) * (1.0 - dz) +
+		V010 * (1.0-dx) * (dy)       * (1.0 - dz) +
+		V001 * (1.0-dx) * (1.0 - dy) * (dz)       +
+		V101 * (dx)     * (1.0 - dy) * (dz)       +
+		V011 * (1.0-dx) * (dy)       * (dz)       +
+		V110 * (dx)     * (dy)       * (1.0 - dz) +
+		V111 * (dx)     * (dy)       * (dz);
+
+
+	return(valueXYZ);
+
+}
+
+int NI_Histogram2D(int layersF, int rowsF, int colsF, int layersG, int rowsG, int colsG, 
+		   int *dimSteps, double *M, unsigned char *imageG, unsigned char *imageF, double *H)
+{
+
+	int status;
+	int seed;
+	int dimsF[3];
+	int dimsG[3];
+	int dims_F[2];
+	int dims_G[2];
+	int ivf, ivg;
+	float ran_x, ran_y, ran_z;
+	float vf, delta;
+	float x, y, z;
+	float dx, dy, dz;
+	float xp, yp, zp;
+	float rx, ry, rz;
+
+	dimsF[0] = colsF;
+	dimsF[1] = rowsF;
+	dimsF[2] = layersF;
+	dimsG[0] = colsG;
+	dimsG[1] = rowsG;
+	dimsG[2] = layersG;
+
+	dims_G[0] = dimsG[0];
+	dims_G[1] = dimsG[0]*dimsG[1];
+	dims_F[0] = dimsF[0];
+	dims_F[1] = dimsF[0]*dimsF[1];
+
+	seed = 1000;
+	srand(seed);
+
+	/* because of stochastic sampling, subtract 1 from upper bounds */
+	for(z = 0.0; z < layersG-dimSteps[2]-1; z += dimSteps[2]){
+	    for(y = 0.0; y < rowsG-dimSteps[1]-1; y += dimSteps[1]){
+	        for(x = 0.0; x < colsG-dimSteps[0]-1; x += dimSteps[0]){
+		    /* positive jitter the x, y, z values */
+		    ran_x = 1.0 * rand()/((float)RAND_MAX);
+		    ran_y = 1.0 * rand()/((float)RAND_MAX);
+		    ran_z = 1.0 * rand()/((float)RAND_MAX);
+		    dx = x + ran_x*dimSteps[0];
+		    dy = y + ran_y*dimSteps[1];
+		    dz = z + ran_z*dimSteps[2];
+
+		    /* get the 'from' coordinates */
+		    xp = M[0]*dx + M[1]*dy + M[2]*dz  + M[3];
+		    yp = M[4]*dx + M[5]*dy + M[6]*dz  + M[7];
+		    zp = M[8]*dx + M[9]*dy + M[10]*dz + M[11];
+		    /* clip the resample window */
+		    if((zp >= 0.0 && zp < layersF-dimSteps[2]) && 
+		       (yp >= 0.0 && yp < rowsF-dimSteps[1])   && 
+		       (xp >= 0.0 && xp < colsF-dimSteps[0])){
+		        /* resample the coordinates using a trilinear interpolation */
+			/* resample imageF using the rotated-jittered xyz coordinates */
+			rx = xp - (int)xp; 
+			ry = yp - (int)yp; 
+			rz = zp - (int)zp; 
+			//vf = trilinear_A(imageF, (int)dx, (int)dy, (int)dz, rx, ry, rz, dims_F);
+			vf = trilinear_A(imageF, (int)xp, (int)yp, (int)zp, rx, ry, rz, dims_F);
+			/* floor */
+			ivf = (int)vf;
+			delta = vf - ivf;
+			/* resample imageG using the jittered xyz coordinates */
+			rx = dx - (int)dx; 
+			ry = dy - (int)dy; 
+			rz = dz - (int)dz; 
+			ivg = (int)trilinear_A(imageG, (int)dx, (int)dy, (int)dz, rx, ry, rz, dims_G);
+			//ivg = (int)trilinear_A(imageG, (int)xp, (int)yp, (int)zp, rx, ry, rz, dims_G);
+			/* ivf will be < 255 as 8 bit data and trilinear doesn't ring */
+			H[ivf+256*ivg] += 1.0 - delta;
+			if(ivf < 255){
+			    H[ivf+1+256*ivg] += delta;
+			}
+		    }
+	        }
+	    }
+	}
+
+	status = 1;
+
+	return status;
+
+}
+
+
+int NI_Histogram2DLite(int layersF, int rowsF, int colsF, int layersG, int rowsG, int colsG,
+		       int *dimSteps, double *M, unsigned char *imageG, unsigned char *imageF, double *H)
+{
+
+	int i;
+	int status;
+	int sliceG;
+	int rowG;
+	int sliceSizeG;
+	int dimsF[3];
+	int dimsG[3];
+	int dims[2];
+	int ivf, ivg;
+	float vf, delta;
+	float x, y, z;
+	float xp, yp, zp;
+	float dx, dy, dz;
+
+	int ptr_x0;
+	int ptr_y0;
+	int ptr_z0;
+	int ptr_x1;
+	int ptr_y1;
+	int ptr_z1;
+	//
+	// Vxyz for [0,1] values of x, y, z
+	//
+	int V000;
+	int V100;
+	int V010;
+	int V001;
+	int V011;
+	int V101;
+	int V110;
+	int V111;
+	int g[64], f[64];
+	float valueXYZ;
+
+	//
+	// G is fixed; F is rotated
+	//
+	sliceSizeG = rowsG * colsG;
+	dimsF[0] = colsF;
+	dimsF[1] = rowsF;
+	dimsF[2] = layersF;
+	dimsG[0] = colsG;
+	dimsG[1] = rowsG;
+	dimsG[2] = layersG;
+
+	dims[0] = dimsF[0];
+	dims[1] = dimsF[0]*dimsF[1];
+
+	for(z = 0.0; z < layersG-dimSteps[2]-1; z += dimSteps[2]){
+	    sliceG = (int)z * sliceSizeG;
+	    for(y = 0.0; y < rowsG-dimSteps[1]-1; y += dimSteps[1]){
+		rowG = (int)y * colsG;
+	        for(x = 0.0; x < colsG-dimSteps[0]-1; x += dimSteps[0]){
+		    // get the 'from' coordinates 
+		    xp = M[0]*x + M[1]*y + M[2]*z  + M[3];
+		    yp = M[4]*x + M[5]*y + M[6]*z  + M[7];
+		    zp = M[8]*x + M[9]*y + M[10]*z + M[11];
+		    // clip the resample window 
+		    if((zp >= 0.0 && zp < layersF-dimSteps[2]) && 
+		       (yp >= 0.0 && yp < rowsF-dimSteps[1]) && 
+		       (xp >= 0.0 && xp < colsF-dimSteps[0])){
+
+			// corners of the 3D unit volume cube
+	    		ptr_z0 = (int)zp * dims[1];
+	    		ptr_z1 = ptr_z0 + dims[1];
+			ptr_y0 = (int)yp * dims[0];
+			ptr_y1 = ptr_y0 + dims[0];
+		    	ptr_x0 = (int)xp;
+		    	ptr_x1 = ptr_x0 + 1;
+			dx = xp - (int)xp; 
+			dy = yp - (int)yp; 
+			dz = zp - (int)zp; 
+
+			// imageG is not rotated. sample the given x,y,z
+			ivg = imageG[sliceG+rowG+(int)x];
+			// imageF IS rotated. sample the rotated xp,yp,zp
+			V000 = imageF[ptr_x0+ptr_y0+ptr_z0];
+			V100 = imageF[ptr_x1+ptr_y0+ptr_z0];
+			V010 = imageF[ptr_x0+ptr_y1+ptr_z0];
+			V001 = imageF[ptr_x0+ptr_y0+ptr_z1];
+			V011 = imageF[ptr_x0+ptr_y1+ptr_z1];
+			V101 = imageF[ptr_x1+ptr_y0+ptr_z1];
+			V110 = imageF[ptr_x1+ptr_y1+ptr_z0];
+			V111 = imageF[ptr_x1+ptr_y1+ptr_z1];
+			
+		        vf = V000 * (1.0-dx) * (1.0 - dy) * (1.0 - dz) +
+			     V100 * (dx)     * (1.0 - dy) * (1.0 - dz) +
+			     V010 * (1.0-dx) * (dy)       * (1.0 - dz) +
+			     V001 * (1.0-dx) * (1.0 - dy) * (dz)       +
+			     V101 * (dx)     * (1.0 - dy) * (dz)       +
+			     V011 * (1.0-dx) * (dy)       * (dz)       +
+			     V110 * (dx)     * (dy)       * (1.0 - dz) +
+			     V111 * (dx)     * (dy)       * (dz);
+
+			ivf = (int)(vf);
+			H[ivf+256*ivg] += 1.0;
+		    }
+	        }
+	    }
+	}
+
+	status = 1;
+
+	return status;
+
+}
+
+
+int NI_LinearResample(int layersF, int rowsF, int colsF, int layersG, int rowsG, int colsG,
+		       int *dimSteps, double *M, unsigned char *imageG, unsigned char *imageF)
+{
+
+	int i;
+	int status;
+	int sliceG;
+	int rowG;
+	int sliceSizeG;
+	int dimsF[3];
+	int dimsG[3];
+	int dims[2];
+	int ivf, ivg;
+	float vf, delta;
+	float x, y, z;
+	float xp, yp, zp;
+	float dx, dy, dz;
+
+	int ptr_x0;
+	int ptr_y0;
+	int ptr_z0;
+	int ptr_x1;
+	int ptr_y1;
+	int ptr_z1;
+	//
+	// Vxyz for [0,1] values of x, y, z
+	//
+	int V000;
+	int V100;
+	int V010;
+	int V001;
+	int V011;
+	int V101;
+	int V110;
+	int V111;
+	float valueXYZ;
+
+	//
+	// G is fixed; F is rotated
+	//
+	sliceSizeG = rowsG * colsG;
+	dimsF[0] = colsF;
+	dimsF[1] = rowsF;
+	dimsF[2] = layersF;
+	dimsG[0] = colsG;
+	dimsG[1] = rowsG;
+	dimsG[2] = layersG;
+
+	dims[0] = dimsF[0];
+	dims[1] = dimsF[0]*dimsF[1];
+
+	for(z = 0.0; z < layersG-dimSteps[2]-1; z += dimSteps[2]){
+	    sliceG = (int)z * sliceSizeG;
+	    for(y = 0.0; y < rowsG-dimSteps[1]-1; y += dimSteps[1]){
+		rowG = (int)y * colsG;
+	        for(x = 0.0; x < colsG-dimSteps[0]-1; x += dimSteps[0]){
+		    // get the 'from' coordinates 
+		    xp = M[0]*x + M[1]*y + M[2]*z  + M[3];
+		    yp = M[4]*x + M[5]*y + M[6]*z  + M[7];
+		    zp = M[8]*x + M[9]*y + M[10]*z + M[11];
+		    // clip the resample window 
+		    if((zp >= 0.0 && zp < layersF-dimSteps[2]) && 
+		       (yp >= 0.0 && yp < rowsF-dimSteps[1]) && 
+		       (xp >= 0.0 && xp < colsF-dimSteps[0])){
+
+			// corners of the 3D unit volume cube
+	    		ptr_z0 = (int)zp * dims[1];
+	    		ptr_z1 = ptr_z0 + dims[1];
+			ptr_y0 = (int)yp * dims[0];
+			ptr_y1 = ptr_y0 + dims[0];
+		    	ptr_x0 = (int)xp;
+		    	ptr_x1 = ptr_x0 + 1;
+			dx = xp - (int)xp; 
+			dy = yp - (int)yp; 
+			dz = zp - (int)zp; 
+
+			// imageF IS rotated. sample the rotated xp,yp,zp
+			// and stored in imageG
+			V000 = imageF[ptr_x0+ptr_y0+ptr_z0];
+			V100 = imageF[ptr_x1+ptr_y0+ptr_z0];
+			V010 = imageF[ptr_x0+ptr_y1+ptr_z0];
+			V001 = imageF[ptr_x0+ptr_y0+ptr_z1];
+			V011 = imageF[ptr_x0+ptr_y1+ptr_z1];
+			V101 = imageF[ptr_x1+ptr_y0+ptr_z1];
+			V110 = imageF[ptr_x1+ptr_y1+ptr_z0];
+			V111 = imageF[ptr_x1+ptr_y1+ptr_z1];
+			
+		        vf = V000 * (1.0-dx) * (1.0 - dy) * (1.0 - dz) +
+			     V100 * (dx)     * (1.0 - dy) * (1.0 - dz) +
+			     V010 * (1.0-dx) * (dy)       * (1.0 - dz) +
+			     V001 * (1.0-dx) * (1.0 - dy) * (dz)       +
+			     V101 * (dx)     * (1.0 - dy) * (dz)       +
+			     V011 * (1.0-dx) * (dy)       * (dz)       +
+			     V110 * (dx)     * (dy)       * (1.0 - dz) +
+			     V111 * (dx)     * (dy)       * (dz);
+
+			imageG[sliceG+rowG+(int)x] = (int)vf;
+
+		    }
+	        }
+	    }
+	}
+
+	status = 1;
+
+	return status;
+
+}
+
+
+
+int NI_VolumeResample(int layersS, int rowsS, int colsS, int layersD, int rowsD, int colsD,
+	              int scale, int mode, unsigned char *imageD, unsigned char *imageS, double *Z)
+{
+
+	int i;
+	int x, y, z;
+	int sliceSizeSrc;
+	int sliceSizeDst;
+	int status;
+	int ivf;
+	int xf, xg, yg, zg;
+	int g_slice, f_slice;
+	int g_row, f_row;
+	int g_slicesize, f_slicesize;
+	int itemp, sOffset, dOffset;
+	int XInt, YInt, ZInt;
+	float ps1, ps2, ps3;
+	float Y[4], tpoint, reSampler;
+	float XPrime, YPrime, ZPrime;
+	float C, R, L;
+	float *RLUT;
+	float *samples;
+
+	if(mode ==1){
+	    /* 
+	     * integer subsample
+	     */
+	    g_slicesize = rowsD * colsD;
+	    f_slicesize = rowsS * colsS;
+	    for(zg = 0; zg < layersD; ++zg){
+	        g_slice = zg * g_slicesize;
+	        f_slice = zg * scale * f_slicesize;
+	        for(yg = 0; yg < rowsD; ++yg){
+		    g_row = yg * colsD;
+		    f_row = yg * scale * colsS;
+	            for(xg = 0; xg < colsD; ++xg){
+		        xf = xg * scale;
+		        ivf = imageS[f_slice+f_row+xf];
+		        imageD[g_slice+g_row+xg] = ivf;
+	            }
+	        }
+	    }
+	}
+	else if(mode ==2){
+	    /*
+	     * fractional cubic convolution resample
+	     */
+
+	    /* first resample each column in all rows and all layers */
+
+	    sliceSizeSrc = colsS * rowsS;
+	    sliceSizeDst = colsD * rowsD;
+
+	    RLUT    = calloc(colsD, sizeof(float));
+	    samples = calloc(colsS+4, sizeof(float));
+	    reSampler = (float)1.0/Z[0];
+	    tpoint = (float)0.0;
+	    for(i = 0; i < colsD; ++i){
+	        RLUT[i] = tpoint;
+	        tpoint += reSampler;
+	    }
+
+	    for(z = 0; z < layersS; ++z){
+                sOffset = z * sliceSizeSrc;
+                dOffset = z * sliceSizeDst;
+	        for(y = 0; y < rowsS; ++y){
+	            for(x = 0; x < colsS; ++x){
+                        samples[x] = (float)imageS[sOffset+x];
+	            }
+	            for(x = 1; x < colsD; ++x){
+	                XPrime = RLUT[x];
+		        XInt   = (int)XPrime;
+		        C      = XPrime - (float)XInt;
+                        Y[0]   = samples[XInt-1];
+                        Y[1]   = samples[XInt];
+                        Y[2]   = samples[XInt+1];
+                        Y[3]   = samples[XInt+2];
+		        ps1    = Y[2] - Y[0];
+		        ps2    = (float)2.0*(Y[0] - Y[1]) + Y[2] - Y[3];
+		        ps3    = -Y[0] + Y[1] - Y[2] + Y[3];
+		        itemp  = (int)(Y[1]+C*(ps1+C*(ps2+C*ps3)));
+		        if(itemp < 0)   itemp = 0;
+		        if(itemp > 255) itemp = 255;
+                        imageD[dOffset+x] = itemp;
+	            }
+                    sOffset += colsS;
+                    dOffset += colsD;
+	        }
+	    }
+	    free(RLUT);
+	    free(samples);
+
+	    /* second resample each row in all columns and all layers */
+	    RLUT    = calloc(rowsD, sizeof(float));
+	    samples = calloc(rowsS+4, sizeof(float));
+	    reSampler = (float)1.0/Z[1];
+	    tpoint = (float)0.0;
+	    for(i = 0; i < rowsD; ++i){
+	        RLUT[i] = tpoint;
+	        tpoint += reSampler;
+	    }
+
+	    for(z = 0; z < layersS; ++z){
+                dOffset = z * sliceSizeDst;
+	        for(x = 0; x < colsD; ++x){
+	            for(y = 0; y < rowsS; ++y){
+                        samples[y] = (float)imageD[dOffset+x+y*colsD];
+	            }
+	            for(y = 1; y < rowsD; ++y){
+	                YPrime = RLUT[y];
+		        YInt   = (int)YPrime;
+		        R      = YPrime - (float)YInt;
+                        Y[0]   = samples[YInt-1];
+                        Y[1]   = samples[YInt];
+                        Y[2]   = samples[YInt+1];
+                        Y[3]   = samples[YInt+2];
+		        ps1    = Y[2] - Y[0];
+		        ps2    = (float)2.0*(Y[0] - Y[1]) + Y[2] - Y[3];
+		        ps3    = -Y[0] + Y[1] - Y[2] + Y[3];
+		        itemp  = (int)(Y[1]+R*(ps1+R*(ps2+R*ps3)));
+		        if(itemp < 0)   itemp = 0;
+		        if(itemp > 255) itemp = 255;
+                        imageD[dOffset+x+y*colsD] = itemp;
+	            }
+	        }
+	    }
+	    free(RLUT);
+	    free(samples);
+
+	    /* third resample each layers in all columns and all rows */
+	    RLUT    = calloc(layersD, sizeof(float));
+	    samples = calloc(layersS+4, sizeof(float));
+	    reSampler = (float)1.0/Z[2];
+	    tpoint = (float)0.0;
+	    for(i = 0; i < layersD; ++i){
+	        RLUT[i] = tpoint;
+	        tpoint += reSampler;
+	    }
+
+	    for(y = 0; y < rowsD; ++y){
+                dOffset = y * colsD;
+	        for(x = 0; x < colsD; ++x){
+	    	    for(z = 0; z < layersS; ++z){
+                        samples[z] = (float)imageD[dOffset+x+z*sliceSizeDst];
+		    }
+	    	    for(z = 1; z < layersD; ++z){
+	                ZPrime = RLUT[z];
+		        ZInt   = (int)ZPrime;
+		        L      = ZPrime - (float)ZInt;
+                        Y[0]   = samples[ZInt-1];
+                        Y[1]   = samples[ZInt];
+                        Y[2]   = samples[ZInt+1];
+                        Y[3]   = samples[ZInt+2];
+		        ps1    = Y[2] - Y[0];
+		        ps2    = (float)2.0*(Y[0] - Y[1]) + Y[2] - Y[3];
+		        ps3    = -Y[0] + Y[1] - Y[2] + Y[3];
+		        itemp  = (int)(Y[1]+R*(ps1+R*(ps2+R*ps3)));
+		        if(itemp < 0)   itemp = 0;
+		        if(itemp > 255) itemp = 255;
+                        imageD[dOffset+x+z*sliceSizeDst] = itemp;
+		    }
+		}
+	    }
+	    free(RLUT);
+	    free(samples);
+     	}
+
+	status = 1;
+
+	return status;
+
+}
+
+
+int NI_CubicResample(int layersF, int rowsF, int colsF, int layersG, int rowsG, int colsG,
+	             int *dimSteps, double *M, unsigned char *imageG, unsigned char *imageF)
+{
+
+	int i;
+	int status;
+	int sliceG;
+	int rowG;
+	int sliceSizeG;
+	int ivf;
+	float vf;
+	float x, y, z;
+	float xp, yp, zp;
+
+	sliceSizeG = rowsG * colsG;
+	for(z = 1.0; z < layersG-dimSteps[2]-2; z += dimSteps[2]){
+	    sliceG = (int)z * sliceSizeG;
+	    for(y = 1.0; y < rowsG-dimSteps[1]-2; y += dimSteps[1]){
+		rowG = (int)y * colsG;
+	        for(x = 1.0; x < colsG-dimSteps[0]-2; x += dimSteps[0]){
+		    // get the 'from' coordinates 
+		    xp = M[0]*x + M[1]*y + M[2]*z  + M[3];
+		    yp = M[4]*x + M[5]*y + M[6]*z  + M[7];
+		    zp = M[8]*x + M[9]*y + M[10]*z + M[11];
+		    // clip the resample window 
+		    if((zp >= 1.0 && zp < layersF-dimSteps[2]-2) && 
+		       (yp >= 1.0 && yp < rowsF-dimSteps[1]-2) && 
+		       (xp >= 1.0 && xp < colsF-dimSteps[0]-2)){
+			vf = tri_cubic_convolve(imageF, (int)xp, (int)yp, (int)zp, xp, yp,
+				          	zp, colsG, rowsG, layersG, sliceSizeG);
+			/* clip at hard edges */
+			if(vf < 0.0) vf = 0.0;
+			if(vf > 255.0) vf = 255.0;
+			imageG[sliceG+rowG+(int)x] = (int)vf;
+		    }
+	        }
+	    }
+	}
+
+	status = 1;
+
+	return status;
+
+}
+
+int NI_ImageThreshold(int layers, int rows, int cols, unsigned short *image, double *H,
+	               double *IH, int histogram_elements, double threshold, int *index)
+{
+
+	int i, j, k;
+	int status;
+	int ptr;
+	int value;
+	float sum;
+
+	for(i = 0; i < histogram_elements; ++i){
+	    H[i]  = 0;
+	    IH[i] = 0;
+	}
+	ptr = 0;
+	for(i = 0; i < layers; ++i){
+	    for(j = 0; j < rows; ++j){
+	        for(k = 0; k < cols; ++k){
+		    value = image[ptr++];
+		    ++H[value];
+	        }
+	    }
+	}
+
+	sum = 0.0;
+	for(i = 0; i < histogram_elements; ++i){
+	    sum += H[i];
+	}
+	/* normalize the volume histogram */
+	for(i = 0; i < histogram_elements; ++i){
+	    H[i] = H[i] / sum;
+	}
+
+	/* build the integrated histogram */
+	IH[0] = H[0];
+	for(i = 1; i < histogram_elements; ++i){
+	    IH[i] = IH[i-1] + H[i];
+	}
+
+	/* get the threshold crossing. this deals with the high amplitude outliers in the volume */
+	*index = histogram_elements-1;
+	for(i = 0; i < histogram_elements; ++i){
+	    if(IH[i] > threshold){
+	        *index = i;
+	        break;
+	    }
+	}
+
+	status = 1;
+
+	return status;
+
+}
+
+
+int NI_ResampleWithGradient(int layersS, int rowsS, int colsS, int layersD, int rowsD,
+		            int colsD, int *dimSteps, double *M, unsigned char *imageD,
+			    unsigned char *imageS, double *scale, int *offset, double *gradientX,
+			    double *gradientY, double *gradientZ)
+{
+
+	int i;
+	int seed;
+	int status;
+	int sliceD;
+	int rowD;
+	int sliceSizeD;
+	int dimsS[3];
+	int dimsD[3];
+	int dims[2];
+	float vs;
+	float x, y, z;
+	float xp, yp, zp;
+	float dx1, dy1, dz1;
+	float dx2, dy2, dz2;
+	float ran_x, ran_y, ran_z;
+	float dx, dy, dz;
+	double gradX, gradY, gradZ;
+
+	int ptr_x0;
+	int ptr_y0;
+	int ptr_z0;
+	int ptr_x1;
+	int ptr_y1;
+	int ptr_z1;
+	//
+	// Vxyz for [0,1] values of x, y, z
+	//
+	int V000;
+	int V100;
+	int V010;
+	int V001;
+	int V011;
+	int V101;
+	int V110;
+	int V111;
+	float valueXYZ;
+
+	sliceSizeD = rowsD * colsD;
+	dimsD[0] = colsD;
+	dimsD[1] = rowsD;
+	dimsD[2] = layersD;
+	dimsS[0] = colsS;
+	dimsS[1] = rowsS;
+	dimsS[2] = layersS;
+
+	dims[0] = dimsS[0];
+	dims[1] = dimsS[0]*dimsS[1];
+
+	seed = 1000;
+	srand(seed);
+
+	for(z = 0.0; z < layersD-dimSteps[2]-1; z += dimSteps[2]){
+	    sliceD = (int)z * sliceSizeD;
+	    for(y = 0.0; y < rowsD-dimSteps[1]-1; y += dimSteps[1]){
+		rowD = (int)y * colsD;
+	        for(x = 0.0; x < colsD-dimSteps[0]-1; x += dimSteps[0]){
+
+		    /* jitter the coordinates to prevent aliasing */
+		    ran_x = 1.0 * rand()/((float)RAND_MAX);
+		    ran_y = 1.0 * rand()/((float)RAND_MAX);
+		    ran_z = 1.0 * rand()/((float)RAND_MAX);
+
+		    dx = x + ran_x;
+		    dy = y + ran_y;
+		    dz = z + ran_z;
+
+		    // get the 'from' coordinates 
+		    xp = M[0]*dx + M[1]*dy + M[2]*dz  + M[3];
+		    yp = M[4]*dx + M[5]*dy + M[6]*dz  + M[7];
+		    zp = M[8]*dx + M[9]*dy + M[10]*dz + M[11];
+		    // clip the resample window 
+		    if((zp >= 0.0 && zp < layersS-dimSteps[2]) && 
+		       (yp >= 0.0 && yp < rowsS-dimSteps[1]) && 
+		       (xp >= 0.0 && xp < colsS-dimSteps[0])){
+
+			// corners of the 3D unit volume cube
+	    		ptr_z0 = (int)zp * dims[1];
+	    		ptr_z1 = ptr_z0 + dims[1];
+			ptr_y0 = (int)yp * dims[0];
+			ptr_y1 = ptr_y0 + dims[0];
+		    	ptr_x0 = (int)xp;
+		    	ptr_x1 = ptr_x0 + 1;
+
+			dx1 = xp - (int)xp; 
+			dy1 = yp - (int)yp; 
+			dz1 = zp - (int)zp; 
+			dx2 = 1.0 - dx1; 
+			dy2 = 1.0 - dy1; 
+			dz2 = 1.0 - dz1; 
+
+			V000 = imageS[ptr_x0+ptr_y0+ptr_z0];
+			V100 = imageS[ptr_x1+ptr_y0+ptr_z0];
+			V010 = imageS[ptr_x0+ptr_y1+ptr_z0];
+			V001 = imageS[ptr_x0+ptr_y0+ptr_z1];
+			V011 = imageS[ptr_x0+ptr_y1+ptr_z1];
+			V101 = imageS[ptr_x1+ptr_y0+ptr_z1];
+			V110 = imageS[ptr_x1+ptr_y1+ptr_z0];
+			V111 = imageS[ptr_x1+ptr_y1+ptr_z1];
+			
+		        vs = V000 * (dx2) * (dy2) * (dz2) +
+			     V100 * (dx1) * (dy2) * (dz2) +
+			     V010 * (dx2) * (dy1) * (dz2) +
+			     V001 * (dx2) * (dy2) * (dz1) +
+			     V101 * (dx1) * (dy2) * (dz1) +
+			     V011 * (dx2) * (dy1) * (dz1) +
+			     V110 * (dx1) * (dy1) * (dz2) +
+			     V111 * (dx1) * (dy1) * (dz1);
+
+			/* resampled voxel */
+			imageD[sliceD+rowD+(int)x] = (int)(vs*scale[(int)zp]) + offset[(int)zp];
+
+			/*
+			 * x gradient voxel. for no resample dz1, dy1 = 0.0 and
+			 * dy2, dz2 = 1.0 so gradX = V100 - V000
+			*/
+
+			/* d/d(dx1) = 1.0, d/d(dx2) = -1.0 */
+		        gradX = V000 * (-1.0) * (dy2) * (dz2) +
+			        V100 * (1.0)  * (dy2) * (dz2) +
+			        V010 * (-1.0) * (dy1) * (dz2) +
+			        V001 * (-1.0) * (dy2) * (dz1) +
+			        V101 * (1.0)  * (dy2) * (dz1) +
+			        V011 * (-1.0) * (dy1) * (dz1) +
+			        V110 * (1.0)  * (dy1) * (dz2) +
+			        V111 * (1.0)  * (dy1) * (dz1);
+
+			/* d/d(dy1) = 1.0, d/d(dy2) = -1.0 */
+		        gradY = V000 * (dx2) * (-1.0) * (dz2) +
+			        V100 * (dx1) * (-1.0) * (dz2) +
+			        V010 * (dx2) * (1.0)  * (dz2) +
+			        V001 * (dx2) * (-1.0) * (dz1) +
+			        V101 * (dx1) * (-1.0) * (dz1) +
+			        V011 * (dx2) * (1.0)  * (dz1) +
+			        V110 * (dx1) * (1.0)  * (dz2) +
+			        V111 * (dx1) * (1.0)  * (dz1);
+
+			/* d/d(dz1) = 1.0, d/d(dz2) = -1.0 */
+		        gradZ = V000 * (dx2) * (dy2) * (-1.0) +
+			        V100 * (dx1) * (dy2) * (-1.0) +
+			        V010 * (dx2) * (dy1) * (-1.0) +
+			        V001 * (dx2) * (dy2) * (1.0)  +
+			        V101 * (dx1) * (dy2) * (1.0)  +
+			        V011 * (dx2) * (dy1) * (1.0)  +
+			        V110 * (dx1) * (dy1) * (-1.0) +
+			        V111 * (dx1) * (dy1) * (1.0);
+
+			gradientX[sliceD+rowD+(int)x] = (gradX*scale[(int)zp]);
+			gradientY[sliceD+rowD+(int)x] = (gradY*scale[(int)zp]);
+			gradientZ[sliceD+rowD+(int)x] = (gradZ*scale[(int)zp]);
+
+		    }
+	        }
+	    }
+	}
+
+	status = 1;
+
+	return status;
+
+}
+
+
+int NI_Resample_Gradient_Coords(int size, int layersS, int rowsS, int colsS, int layersD, int rowsD,
+	                        int colsD, int *dimSteps, double *X, double *Y, double *Z,
+			        unsigned char *imageD, unsigned char *imageS, double *scale, 
+			        int *offset, double *gradientX, double *gradientY, double *gradientZ)
+{
+
+	int i;
+	int status;
+	int sliceSizeD;
+	int dimsS[3];
+	int dimsD[3];
+	int dims[2];
+	float vs;
+	float xp, yp, zp;
+	float dx1, dy1, dz1;
+	float dx2, dy2, dz2;
+	double gradX, gradY, gradZ;
+
+	int ptr_x0;
+	int ptr_y0;
+	int ptr_z0;
+	int ptr_x1;
+	int ptr_y1;
+	int ptr_z1;
+	//
+	// Vxyz for [0,1] values of x, y, z
+	//
+	int V000;
+	int V100;
+	int V010;
+	int V001;
+	int V011;
+	int V101;
+	int V110;
+	int V111;
+	float valueXYZ;
+
+	sliceSizeD = rowsD * colsD;
+	dimsD[0] = colsD;
+	dimsD[1] = rowsD;
+	dimsD[2] = layersD;
+	dimsS[0] = colsS;
+	dimsS[1] = rowsS;
+	dimsS[2] = layersS;
+
+	dims[0] = dimsS[0];
+	dims[1] = dimsS[0]*dimsS[1];
+
+	for(i = 0; i < size; ++i){
+	    // get the 'from' unrolled coordinates 
+	    zp = Z[i];
+	    yp = Y[i];
+	    xp = X[i];
+
+	    // clip the resample window 
+	    if((zp >= 0.0 && zp < layersS-dimSteps[2]) && 
+	       (yp >= 0.0 && yp < rowsS-dimSteps[1]) && 
+	       (xp >= 0.0 && xp < colsS-dimSteps[0])){
+
+	        // corners of the 3D unit volume cube
+	        ptr_z0 = (int)zp * dims[1];
+	        ptr_z1 = ptr_z0 + dims[1];
+	        ptr_y0 = (int)yp * dims[0];
+	        ptr_y1 = ptr_y0 + dims[0];
+	        ptr_x0 = (int)xp;
+	        ptr_x1 = ptr_x0 + 1;
+
+	        dx1 = xp - (int)xp; 
+	        dy1 = yp - (int)yp; 
+	        dz1 = zp - (int)zp; 
+	        dx2 = 1.0 - dx1; 
+	        dy2 = 1.0 - dy1; 
+	        dz2 = 1.0 - dz1; 
+
+	        V000 = imageS[ptr_x0+ptr_y0+ptr_z0];
+	        V100 = imageS[ptr_x1+ptr_y0+ptr_z0];
+	        V010 = imageS[ptr_x0+ptr_y1+ptr_z0];
+	        V001 = imageS[ptr_x0+ptr_y0+ptr_z1];
+	        V011 = imageS[ptr_x0+ptr_y1+ptr_z1];
+	        V101 = imageS[ptr_x1+ptr_y0+ptr_z1];
+	        V110 = imageS[ptr_x1+ptr_y1+ptr_z0];
+	        V111 = imageS[ptr_x1+ptr_y1+ptr_z1];
+			
+	        vs = V000 * (dx2) * (dy2) * (dz2) +
+	             V100 * (dx1) * (dy2) * (dz2) +
+	             V010 * (dx2) * (dy1) * (dz2) +
+	             V001 * (dx2) * (dy2) * (dz1) +
+	             V101 * (dx1) * (dy2) * (dz1) +
+	             V011 * (dx2) * (dy1) * (dz1) +
+	             V110 * (dx1) * (dy1) * (dz2) +
+	             V111 * (dx1) * (dy1) * (dz1);
+
+	        /* resampled voxel saved in the unrolled clipped volume */
+	        imageD[i] = (int)(vs*scale[(int)zp]) + offset[(int)zp];
+
+	        /*
+	         * x gradient voxel. for no resample dz1, dy1 = 0.0 and
+	         * dy2, dz2 = 1.0 so gradX = V100 - V000
+	        */
+
+	        /* d/d(dx1) = 1.0, d/d(dx2) = -1.0 */
+	        gradX = V000 * (-1.0) * (dy2) * (dz2) +
+	                V100 * (1.0)  * (dy2) * (dz2) +
+	                V010 * (-1.0) * (dy1) * (dz2) +
+	                V001 * (-1.0) * (dy2) * (dz1) +
+	                V101 * (1.0)  * (dy2) * (dz1) +
+	                V011 * (-1.0) * (dy1) * (dz1) +
+	                V110 * (1.0)  * (dy1) * (dz2) +
+	                V111 * (1.0)  * (dy1) * (dz1);
+
+	        /* d/d(dy1) = 1.0, d/d(dy2) = -1.0 */
+	        gradY = V000 * (dx2) * (-1.0) * (dz2) +
+	                V100 * (dx1) * (-1.0) * (dz2) +
+	                V010 * (dx2) * (1.0)  * (dz2) +
+	                V001 * (dx2) * (-1.0) * (dz1) +
+	                V101 * (dx1) * (-1.0) * (dz1) +
+	                V011 * (dx2) * (1.0)  * (dz1) +
+	                V110 * (dx1) * (1.0)  * (dz2) +
+	                V111 * (dx1) * (1.0)  * (dz1);
+
+	        /* d/d(dz1) = 1.0, d/d(dz2) = -1.0 */
+	        gradZ = V000 * (dx2) * (dy2) * (-1.0) +
+	                V100 * (dx1) * (dy2) * (-1.0) +
+	                V010 * (dx2) * (dy1) * (-1.0) +
+	                V001 * (dx2) * (dy2) * (1.0)  +
+	                V101 * (dx1) * (dy2) * (1.0)  +
+	                V011 * (dx2) * (dy1) * (1.0)  +
+	                V110 * (dx1) * (dy1) * (-1.0) +
+	                V111 * (dx1) * (dy1) * (1.0);
+
+	        /* gradients saved in the unrolled clipped gradient volume */
+	        gradientX[i] = (gradX*scale[(int)zp]);
+	        gradientY[i] = (gradY*scale[(int)zp]);
+	        gradientZ[i] = (gradZ*scale[(int)zp]);
+
+	    }
+
+	}
+
+	status = 1;
+
+	return status;
+
+}
+
+
+
+int NI_Resample_Coords(int size, int layersS, int rowsS, int colsS, int layersD, int rowsD,
+	               int colsD, int *dimSteps, double *X, double *Y, double *Z,
+		       unsigned char *imageD, unsigned char *imageS, double *scale, int *offset) 
+{
+
+	int i;
+	int status;
+	int sliceSizeD;
+	int dimsS[3];
+	int dimsD[3];
+	int dims[2];
+	float vs;
+	float xp, yp, zp;
+	float dx1, dy1, dz1;
+	float dx2, dy2, dz2;
+
+	int ptr_x0;
+	int ptr_y0;
+	int ptr_z0;
+	int ptr_x1;
+	int ptr_y1;
+	int ptr_z1;
+	//
+	// Vxyz for [0,1] values of x, y, z
+	//
+	int V000;
+	int V100;
+	int V010;
+	int V001;
+	int V011;
+	int V101;
+	int V110;
+	int V111;
+	float valueXYZ;
+
+	sliceSizeD = rowsD * colsD;
+	dimsD[0] = colsD;
+	dimsD[1] = rowsD;
+	dimsD[2] = layersD;
+	dimsS[0] = colsS;
+	dimsS[1] = rowsS;
+	dimsS[2] = layersS;
+
+	dims[0] = dimsS[0];
+	dims[1] = dimsS[0]*dimsS[1];
+
+	for(i = 0; i < size; ++i){
+	    // get the 'from' unrolled coordinates 
+	    zp = Z[i];
+	    yp = Y[i];
+	    xp = X[i];
+
+	    // clip the resample window 
+	    if((zp >= 0.0 && zp < layersS-dimSteps[2]) && 
+	       (yp >= 0.0 && yp < rowsS-dimSteps[1]) && 
+	       (xp >= 0.0 && xp < colsS-dimSteps[0])){
+
+	        // corners of the 3D unit volume cube
+	        ptr_z0 = (int)zp * dims[1];
+	        ptr_z1 = ptr_z0 + dims[1];
+	        ptr_y0 = (int)yp * dims[0];
+	        ptr_y1 = ptr_y0 + dims[0];
+	        ptr_x0 = (int)xp;
+	        ptr_x1 = ptr_x0 + 1;
+
+	        dx1 = xp - (int)xp; 
+	        dy1 = yp - (int)yp; 
+	        dz1 = zp - (int)zp; 
+	        dx2 = 1.0 - dx1; 
+	        dy2 = 1.0 - dy1; 
+	        dz2 = 1.0 - dz1; 
+
+	        V000 = imageS[ptr_x0+ptr_y0+ptr_z0];
+	        V100 = imageS[ptr_x1+ptr_y0+ptr_z0];
+	        V010 = imageS[ptr_x0+ptr_y1+ptr_z0];
+	        V001 = imageS[ptr_x0+ptr_y0+ptr_z1];
+	        V011 = imageS[ptr_x0+ptr_y1+ptr_z1];
+	        V101 = imageS[ptr_x1+ptr_y0+ptr_z1];
+	        V110 = imageS[ptr_x1+ptr_y1+ptr_z0];
+	        V111 = imageS[ptr_x1+ptr_y1+ptr_z1];
+			
+	        vs = V000 * (dx2) * (dy2) * (dz2) +
+	             V100 * (dx1) * (dy2) * (dz2) +
+	             V010 * (dx2) * (dy1) * (dz2) +
+	             V001 * (dx2) * (dy2) * (dz1) +
+	             V101 * (dx1) * (dy2) * (dz1) +
+	             V011 * (dx2) * (dy1) * (dz1) +
+	             V110 * (dx1) * (dy1) * (dz2) +
+	             V111 * (dx1) * (dy1) * (dz1);
+
+	        /* resampled voxel saved in the unrolled clipped volume */
+	        imageD[i] = (int)(vs*scale[(int)zp]) + offset[(int)zp];
+	    }
+
+	}
+
+	status = 1;
+
+	return status;
+
+}
+
+
+
+int NI_LT_Mrqcof(double *alpha, double *beta, double *V, double wt, double value, int M1){
+
+	int i, j;
+	double v1;
+	int status;
+
+	for(i = 0; i < M1; ++i){
+	    v1 = V[i];
+	    beta[i] = v1 * value * wt;
+	    for(j = 0; j <= i; ++j){
+		alpha[M1*i+j] = v1 * V[j];
+	    }
+	}
+
+	status = 1;
+
+	return status;
+
+}
+
+
+int NI_LT_Tensor_Product(double *alpha_1, double *alpha_2, double *beta_1, double *beta_2, double *basis,
+	                 int M1, int M2, int rows, int row_number, int coeff_1, int coeff_2){
+
+
+	//
+	// lower triangular tensor product
+	//
+
+	int i, j, k, m;
+	int loop3_outer, loop3_inner;
+	int status;
+	double wt1;
+	double wt2;
+	double *ptr1;
+	double *ptr2;
+
+	for(i = 0; i < coeff_1; ++i){
+	    wt1 = basis[rows*i + row_number];
+	    for(loop3_outer = 0; loop3_outer < 3; ++loop3_outer){
+		//
+		// spatial-spatial covariances
+		//
+		for(loop3_inner = 0; loop3_inner <= loop3_outer; ++loop3_inner){
+		    for(j = 0; j <= i; ++j){
+			//
+		        // outer product of basis array
+			//
+	    		wt2  = wt1 * basis[rows*j + row_number];
+			ptr1 = &alpha_1[coeff_2*(M1*(coeff_1*loop3_outer+i)+(coeff_1*loop3_inner)+j)];
+			ptr2 = &alpha_2[coeff_2*(M2*loop3_outer+loop3_inner)];
+			for(k = 0; k < coeff_2; ++k){
+			    for(m = 0; m <= k; ++m){
+				ptr1[M1*k+m] += (wt2 * ptr2[M2*k+m]);
+			    }
+			}
+		    }
+		    //
+		    // spatial-intensity covariances (single G volume assumed)
+		    //
+		    ptr1 = &alpha_1[coeff_2*(M1*coeff_1*3+(coeff_1*loop3_inner)+i)];
+		    ptr2 = &alpha_2[coeff_2*(M2*3+loop3_outer)];
+		    for(k = 0; k < coeff_2; ++k){
+			ptr1[M1+k] += (wt1 * ptr2[M2+k]);
+		    }
+		    //
+		    // spatial component of beta
+		    //
+		    for(k = 0; k < coeff_2; ++k){
+			beta_1[k+coeff_2*(coeff_1*loop3_outer+i)] += (wt1 * beta_2[coeff_2*loop3_outer+k]);
+		    }
+		}
+	    }
+	}
+
+	//
+	// intensity-intensity covariances
+	//
+	ptr1 = &alpha_1[coeff_2*(M1*coeff_1*3+(coeff_1*3))];
+	ptr2 = &alpha_2[coeff_2*(M2*3+3)];
+	for(k = 0; k < coeff_2; ++k){
+	    ptr1[k] += ptr2[k];
+	}
+
+	//
+	// intensity component of beta
+	//
+
+	beta_1[coeff_2*coeff_1*3] += beta_2[coeff_2*3];
+
+	status = 1;
+
+	return status;
+
+}
+
+
+
+int NI_Complete_Symmetry(double *Alpha, int nx, int ny, int nz, int ni4){
+
+	//
+	// complete symmetry of Alpha matrix over the 3D brain volume
+	//
+
+	int z1, z2;
+	int y1, y2;
+	int x1, x2;
+	int loop3_outer, loop3_inner;
+	int M1;
+	int status;
+	double *ptrx;
+	double *ptry;
+	double *ptrz;
+
+	M1 = 3*nx*ny*nz + ni4;
+
+	for(loop3_outer = 0; loop3_outer < 3; ++loop3_outer){
+	    for(loop3_inner = 0; loop3_inner <= loop3_outer; ++loop3_inner){
+		ptrz = &Alpha[nx*ny*nz*(M1*loop3_outer+loop3_inner)];
+		for(z1 = 0; z1 < nz; ++z1){
+		    for(z2 = 0; z2 <= z1; ++z2){
+			ptry = ptrz + nx*ny*(M1*z1 + z2);
+			for(y1 = 0; y1 < ny; ++y1){
+		            for(y2 = 0; y2 <= y1; ++y2){
+			        ptrx = ptry + nx*(M1*y1 + y2);
+		                for(x1 = 0; x1 <= nx; ++x1){
+		                    for(y2 = 0; y2 <= y1; ++y2){
+					ptrx[M1*x2+x1] = ptrx[M1*x1+x2];
+			            }
+			        }
+			    }
+			}
+			for(x1 = 0; x1 < nx*ny; ++x1){
+			    for(x2 = 0; x2 < x1; ++x2){
+				ptry[M1*x2+x1] = ptry[M1*x1+x2];
+			    }
+			}
+		    }
+		    for(x1 = 0; x1 < nx*ny*nz; ++x1){
+		        for(x2 = 0; x2 < x1; ++x2){
+			    ptrz[M1*x2+x1] = ptrz[M1*x1+x2];
+		        }
+		    }
+
+		}
+	    }
+	}
+
+	for(x1 = 0; x1 < nx*ny*nz*3+ni4; ++x1){
+	    for(x2 = 0; x2 < x1; ++x2){
+		Alpha[M1*x2+x1] = Alpha[M1*x1+x2];
+	    }
+	}
+
+
+	status = 1;
+
+	return status;
+
+}
+
+
+
+

Added: branches/Interpolate1D/ndimage/segment/Segmenter_EXT.c
===================================================================
--- branches/Interpolate1D/ndimage/segment/Segmenter_EXT.c	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/segment/Segmenter_EXT.c	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,682 @@
+#include "ndImage_Segmenter_structs.h"
+#include "Python.h"
+#include "numpy/arrayobject.h"
+
+static PyObject *Segmenter_EdgePreFilter(PyObject *self, PyObject *args)
+{
+
+    int lowThreshold;
+    int highThreshold;
+    int num;
+    int nd;
+    int type;
+    int aperature;
+    int half_taps;
+    npy_intp *dims;
+    unsigned short *fP1;
+    double *fP2;
+    double *pKernel;
+    PyObject *iArray = NULL;
+    PyObject *eArray = NULL;
+    PyObject *kernel = NULL;
+
+    //
+    // pass in 2D LPF coefficients
+    if(!PyArg_ParseTuple(args, "iiiOOO", &lowThreshold, &highThreshold, 
+			 &half_taps, &kernel, &iArray, &eArray))
+	    goto exit;
+
+    fP1  = (unsigned short *)PyArray_DATA(iArray);
+    nd   = PyArray_NDIM(iArray);
+    dims = PyArray_DIMS(iArray);
+    type = PyArray_TYPE(iArray);
+    num  = PyArray_SIZE(iArray);
+    fP2     = (double *)PyArray_DATA(eArray);
+    pKernel = (double *)PyArray_DATA(kernel);
+    aperature = PyArray_SIZE(kernel);
+
+    if(!PyArray_ISCONTIGUOUS(iArray) || !PyArray_ISCONTIGUOUS(eArray))
+	    goto exit;
+
+    
+    if(!NI_EdgePreFilter(num, (int)dims[0], (int)dims[1], lowThreshold, 
+		         highThreshold, aperature, half_taps, fP1, fP2, pKernel))
+		      
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("");
+
+}
+
+
+static PyObject *Segmenter_SobelImage(PyObject *self, PyObject *args)
+{
+
+    int num;
+    int nd;
+    int type;
+    npy_intp *dims;
+    double *fP1;
+    double *fP2;
+    double pAve;
+    int minValue;
+    int maxValue;
+    PyObject *iArray = NULL;
+    PyObject *eArray = NULL;
+
+    if(!PyArg_ParseTuple(args, "OO", &iArray, &eArray))
+	    goto exit;
+
+    fP1  = (double *)PyArray_DATA(iArray);
+    nd   = PyArray_NDIM(iArray);
+    dims = PyArray_DIMS(iArray);
+    type = PyArray_TYPE(iArray);
+    num  = PyArray_SIZE(iArray);
+    fP2  = (double *)PyArray_DATA(eArray);
+
+    if(!PyArray_ISCONTIGUOUS(iArray) || !PyArray_ISCONTIGUOUS(eArray))
+	    goto exit;
+
+    
+    if(!NI_SobelImage(num, (int)dims[0], (int)dims[1], fP1, fP2, &pAve, &minValue, &maxValue))
+		      
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("dii", pAve, minValue, maxValue);
+
+}
+
+
+static PyObject *Segmenter_SobelEdges(PyObject *self, PyObject *args)
+{
+
+    int num;
+    int nd;
+    int type;
+    npy_intp *dims;
+    double *fP1;
+    unsigned short *fP2;
+    double pAve;
+    int minValue;
+    int maxValue;
+    int mode;
+    double sobelLow;
+    PyObject *iArray = NULL;
+    PyObject *eArray = NULL;
+
+    if(!PyArg_ParseTuple(args, "OOdiiid", &iArray, &eArray, &pAve, &minValue, &maxValue, &mode,
+			                  &sobelLow))
+	    goto exit;
+
+    fP1  = (double *)PyArray_DATA(iArray);
+    nd   = PyArray_NDIM(iArray);
+    dims = PyArray_DIMS(iArray);
+    type = PyArray_TYPE(iArray);
+    num  = PyArray_SIZE(iArray);
+    fP2  = (unsigned short *)PyArray_DATA(eArray);
+
+    if(!PyArray_ISCONTIGUOUS(iArray) || !PyArray_ISCONTIGUOUS(eArray))
+	    goto exit;
+
+    
+    if(!NI_SobelEdge(num, (int)dims[0], (int)dims[1], fP1, fP2, mode, pAve, minValue, maxValue, sobelLow))
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("");
+
+}
+
+
+
+static PyObject *Segmenter_GetBlobs(PyObject *self, PyObject *args)
+{
+
+    int num;
+    int nd;
+    int type;
+    int mask;
+    npy_intp *dims;
+    unsigned short *fP1;
+    unsigned short *fP2;
+    int groups;
+    PyObject *iArray = NULL;
+    PyObject *eArray = NULL;
+
+    if(!PyArg_ParseTuple(args, "OOi", &iArray, &eArray, &mask))
+	    goto exit;
+
+    fP1  = (unsigned short *)PyArray_DATA(iArray);
+    nd   = PyArray_NDIM(iArray);
+    dims = PyArray_DIMS(iArray);
+    type = PyArray_TYPE(iArray);
+    num  = PyArray_SIZE(iArray);
+    fP2  = (unsigned short *)PyArray_DATA(eArray);
+
+    if(!PyArray_ISCONTIGUOUS(iArray) || !PyArray_ISCONTIGUOUS(eArray))
+	    goto exit;
+
+    
+    if(nd == 2){ 
+        if(!NI_GetBlobs2D(num, (int)dims[0], (int)dims[1], fP1, fP2, &groups, mask))
+	    goto exit;
+    }
+    else if(nd == 3){ 
+        if(!NI_GetBlobs3D(num, (int)dims[0], (int)dims[1], (int)dims[2], fP1, fP2, 
+			  &groups, mask))
+	    goto exit;
+    }
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("i", groups);
+
+}
+
+static PyObject *Segmenter_GetBlobRegions(PyObject *self, PyObject *args)
+{
+
+
+    int num;
+    int nd;
+    int type;
+    npy_intp *dims;
+    npy_intp *objNumber;
+    unsigned short *fP1;
+    PyObject  *iArray = NULL;
+    PyObject  *nArray = NULL;
+    objStruct *myData;
+
+    if(!PyArg_ParseTuple(args, "OO", &iArray, &nArray))
+	    goto exit;
+
+    if(!PyArray_ISCONTIGUOUS(iArray) || !PyArray_ISCONTIGUOUS(nArray))
+	    goto exit;
+
+    	//
+	//   PyArray_ContiguousFromObject or PyArray_ContiguousFromAny to be explored 
+	//   for non-contiguous
+	//
+
+	
+    // pointer to the edge-labeled image
+    nd   = PyArray_NDIM(iArray);
+    dims = PyArray_DIMS(iArray);
+    type = PyArray_TYPE(iArray);
+    num  = PyArray_SIZE(iArray);
+    fP1  = (unsigned short *)PyArray_DATA(iArray);
+
+    // the object descriptor array that was allocated from numpy
+    objNumber = PyArray_DIMS(nArray); // this is the number of labels in the edge image
+    myData = (objStruct*)PyArray_DATA(nArray);
+
+    /* need to pass in 2D/3D flag and mask. NI_GetBlobRegions will call
+     * 2D or 3D blob_extraction  */
+
+    if(nd == 2){ 
+        if(!NI_GetBlobRegions2D((int)dims[0], (int)dims[1], (int)objNumber[0], fP1, myData))
+	        goto exit;
+    }
+    else if(nd == 3){ 
+        if(!NI_GetBlobRegions3D((int)dims[0], (int)dims[1], (int)dims[2],
+			       	(int)objNumber[0], fP1, myData))
+	        goto exit;
+    }
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("");
+
+}
+
+
+static PyObject *Segmenter_ThinFilter(PyObject *self, PyObject *args)
+{
+
+    int number_masks;
+    int roi_rows;
+    int roi_cols;
+    int cols;
+    unsigned char *input;
+    unsigned char *cinput;
+    unsigned char *erosion;
+    unsigned char *dialation;
+    unsigned char *hmt;
+    unsigned char *copy;
+    unsigned short *j_mask;
+    unsigned short *k_mask;
+    PyObject  *jArray = NULL;
+    PyObject  *kArray = NULL;
+    PyObject  *iArray = NULL;
+    PyObject  *cArray = NULL;
+    PyObject  *eArray = NULL;
+    PyObject  *dArray = NULL;
+    PyObject  *hArray = NULL;
+    PyObject  *pArray = NULL;
+
+    if(!PyArg_ParseTuple(args, "OOiiiiOOOOOO", &jArray, &kArray, &number_masks, &roi_rows,
+			 &roi_cols, &cols, &iArray, &cArray, &eArray, &dArray, &hArray, &pArray))
+	    goto exit;
+
+
+    j_mask = (unsigned short *)PyArray_DATA(jArray);
+    k_mask = (unsigned short *)PyArray_DATA(kArray);
+
+    input     = (unsigned char *)PyArray_DATA(iArray);
+    cinput    = (unsigned char *)PyArray_DATA(cArray);
+    erosion   = (unsigned char *)PyArray_DATA(eArray);
+    dialation = (unsigned char *)PyArray_DATA(dArray);
+    hmt       = (unsigned char *)PyArray_DATA(hArray);
+    copy      = (unsigned char *)PyArray_DATA(pArray);
+
+    if(!PyArray_ISCONTIGUOUS(iArray))
+	    goto exit;
+
+    if(!NI_ThinMorphoFilter(roi_rows, roi_cols, cols, number_masks, j_mask, k_mask,
+		       input, cinput, erosion, dialation, hmt, copy))
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("");
+
+}
+
+
+static PyObject *Segmenter_CannyFilter(PyObject *self, PyObject *args)
+{
+
+    int num;
+    int nd;
+    int type;
+    int aperature;
+    npy_intp *dims;
+    double *fP1;
+    double *h_DG_image;
+    double *v_DG_image;
+    double *pKernel;
+    float aveXValue;
+    float aveYValue;
+    PyObject  *iArray = NULL;
+    PyObject  *hArray = NULL;
+    PyObject  *vArray = NULL;
+    PyObject  *kernel = NULL;
+
+    if(!PyArg_ParseTuple(args, "OOOOi", &iArray, &hArray, &vArray, &kernel, &aperature))
+	    goto exit;
+
+    fP1  = (double *)PyArray_DATA(iArray);
+    nd   = PyArray_NDIM(iArray);
+    dims = PyArray_DIMS(iArray);
+    type = PyArray_TYPE(iArray);
+    num  = PyArray_SIZE(iArray);
+
+    h_DG_image = (double *)PyArray_DATA(hArray);
+    v_DG_image = (double *)PyArray_DATA(vArray);
+    pKernel    = (double *)PyArray_DATA(kernel);
+
+    if(!PyArray_ISCONTIGUOUS(iArray))
+	    goto exit;
+
+    if(!NI_CannyFilter(num, (int)dims[0], (int)dims[1], fP1, h_DG_image,  
+	               v_DG_image, pKernel, aperature, &aveXValue, &aveYValue))
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("dd", aveXValue, aveYValue);
+
+}
+
+
+
+
+static PyObject *Segmenter_CannyNonMaxSupress(PyObject *self, PyObject *args)
+{
+
+    int num;
+    int nd;
+    int type;
+    int aperature;
+    int mode;
+    npy_intp *dims;
+    double *h_DG_image;
+    double *v_DG_image;
+    double *magnitude;
+    double aveXValue;
+    double aveYValue;
+    double aveMagnitude;
+    double canny_low;
+    double canny_high;
+    double canny_l;
+    double canny_h;
+    PyObject  *mArray = NULL;
+    PyObject  *hArray = NULL;
+    PyObject  *vArray = NULL;
+
+    if(!PyArg_ParseTuple(args, "OOOidddd", &hArray, &vArray, &mArray, &mode, &aveXValue,
+			                   &aveYValue, &canny_l, &canny_h))
+	    goto exit;
+
+    magnitude = (double *)PyArray_DATA(mArray);
+    nd   = PyArray_NDIM(mArray);
+    dims = PyArray_DIMS(mArray);
+    type = PyArray_TYPE(mArray);
+    num  = PyArray_SIZE(mArray);
+
+    h_DG_image = (double *)PyArray_DATA(hArray);
+    v_DG_image = (double *)PyArray_DATA(vArray);
+
+    if(!PyArray_ISCONTIGUOUS(mArray))
+	    goto exit;
+
+    if(!NI_CannyNonMaxSupress(num, (int)dims[0], (int)dims[1], magnitude, h_DG_image,  
+	                      v_DG_image, mode, aveXValue, aveYValue, &aveMagnitude,
+		              &canny_low, &canny_high, canny_l, canny_h))
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("ddd", aveMagnitude, canny_low, canny_high);
+
+}
+
+
+
+static PyObject *Segmenter_CannyHysteresis(PyObject *self, PyObject *args)
+{
+
+    int num;
+    int nd;
+    int type;
+    int aperature;
+    int mode;
+    npy_intp *dims;
+    double *magnitude;
+    unsigned short *hys_image;
+    double canny_low;
+    double canny_high;
+    PyObject  *mArray = NULL;
+    PyObject  *hArray = NULL;
+
+    if(!PyArg_ParseTuple(args, "OOdd", &mArray, &hArray, &canny_low, &canny_high)) 
+	    goto exit;
+
+    magnitude = (double *)PyArray_DATA(mArray);
+    nd   = PyArray_NDIM(mArray);
+    dims = PyArray_DIMS(mArray);
+    type = PyArray_TYPE(mArray);
+    num  = PyArray_SIZE(mArray);
+
+    hys_image = (unsigned short *)PyArray_DATA(hArray);
+
+    if(!PyArray_ISCONTIGUOUS(mArray))
+	    goto exit;
+
+    if(!NI_CannyHysteresis(num, (int)dims[0], (int)dims[1], magnitude, hys_image,  
+		           canny_low, canny_high))
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("");
+
+}
+
+
+static PyObject *Segmenter_BinaryEdge(PyObject *self, PyObject *args)
+{
+
+    int num;
+    int nd;
+    int type;
+    npy_intp *dims;
+    unsigned short *mask_image;
+    unsigned short *edge_image;
+    PyObject  *mArray = NULL;
+    PyObject  *eArray = NULL;
+
+    if(!PyArg_ParseTuple(args, "OO", &mArray, &eArray)) 
+	    goto exit;
+
+    mask_image = (unsigned short *)PyArray_DATA(mArray);
+    nd   = PyArray_NDIM(mArray);
+    dims = PyArray_DIMS(mArray);
+    type = PyArray_TYPE(mArray);
+    num  = PyArray_SIZE(mArray);
+    edge_image = (unsigned short *)PyArray_DATA(eArray);
+
+    if(!PyArray_ISCONTIGUOUS(mArray))
+	    goto exit;
+
+    if(!NI_BinaryEdge(num, (int)dims[0], (int)dims[1], mask_image, edge_image))  
+	    goto exit;
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("");
+
+}
+
+static PyObject *Segmenter_LawsTextureMetric(PyObject *self, PyObject *args)
+{
+
+    int i;
+    int num;
+    int nd;
+    int type;
+    int mode;
+    npy_intp *dims;
+    npy_intp *laws_dims;
+    float  *lawsImage;
+    double *src_image;
+    unsigned short *mask;
+    double *L7;
+    double *E7;
+    double *S7;
+    double *W7;
+    double *R7;
+    double *O7;
+    int number_kernels;
+    int kernel_size;
+    int filters;
+    LawsFilter7 lawsFilter;
+    PyObject *lArray = NULL;
+    PyObject *mArray = NULL;
+    PyObject *sArray = NULL;
+    PyObject *LArray = NULL;
+    PyObject *EArray = NULL;
+    PyObject *SArray = NULL;
+    PyObject *WArray = NULL;
+    PyObject *RArray = NULL;
+    PyObject *OArray = NULL;
+
+    if(!PyArg_ParseTuple(args, "OOOiiiOOOOOO", &mArray, &sArray, &lArray, &number_kernels, 
+			                       &kernel_size, &filters, &LArray, &EArray,
+					       &SArray, &WArray, &RArray, &OArray))
+	    goto exit;
+
+    src_image = (double*)PyArray_DATA(sArray);
+    nd   = PyArray_NDIM(sArray);
+    dims = PyArray_DIMS(sArray);
+    type = PyArray_TYPE(sArray);
+    num  = PyArray_SIZE(sArray);
+
+    laws_dims = PyArray_DIMS(lArray);
+    mask      = (unsigned short *)PyArray_DATA(mArray);
+    lawsImage = (float*)PyArray_DATA(lArray);
+    L7        = (double *)PyArray_DATA(LArray);
+    E7        = (double *)PyArray_DATA(EArray);
+    S7        = (double *)PyArray_DATA(SArray);
+    W7        = (double *)PyArray_DATA(WArray);
+    R7        = (double *)PyArray_DATA(RArray);
+    O7        = (double *)PyArray_DATA(OArray);
+
+    lawsFilter.numberKernels      = number_kernels;
+    lawsFilter.kernelLength       = kernel_size;
+    lawsFilter.numberFilterLayers = filters;
+    for(i = 0; i < kernel_size; ++i){
+        lawsFilter.lawsKernel[0][i] = L7[i];
+        lawsFilter.lawsKernel[1][i] = E7[i];
+        lawsFilter.lawsKernel[2][i] = S7[i];
+        lawsFilter.lawsKernel[3][i] = W7[i];
+        lawsFilter.lawsKernel[4][i] = R7[i];
+        lawsFilter.lawsKernel[5][i] = O7[i];
+    }
+
+    if(!PyArray_ISCONTIGUOUS(sArray)){
+            printf("PyArray_ISCONTIGUOUS error\n");
+	    goto exit;
+    }
+
+    if(!NI_LawsTexture(num, (int)dims[0], (int)dims[1], src_image, mask, lawsImage,   
+		             lawsFilter)){
+	    goto exit;
+    }
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("");
+
+}
+
+static PyObject *Segmenter_RoiCoOccurence(PyObject *self, PyObject *args)
+{
+    int num;
+    int nd;
+    int type;
+    int distance;
+    int orientation;
+    npy_intp *dims;
+    npy_intp *dims_cocm;
+    unsigned short *mask_image;
+    unsigned short *raw_image;
+    int *coc_matrix;
+    PyObject *mArray = NULL;
+    PyObject *rArray = NULL;
+    PyObject *cArray = NULL;
+
+    if(!PyArg_ParseTuple(args, "OOOii", &mArray, &rArray, &cArray, &distance, &orientation)) 
+	    goto exit;
+
+    mask_image = (unsigned short *)PyArray_DATA(mArray);
+    nd   = PyArray_NDIM(mArray);
+    dims = PyArray_DIMS(mArray);
+    type = PyArray_TYPE(mArray);
+    num  = PyArray_SIZE(mArray);
+    raw_image  = (unsigned short *)PyArray_DATA(rArray);
+    coc_matrix = (int *)PyArray_DATA(cArray);
+    dims_cocm  = PyArray_DIMS(cArray);
+
+    if(!PyArray_ISCONTIGUOUS(mArray) || !PyArray_ISCONTIGUOUS(rArray)){
+            printf("PyArray_ISCONTIGUOUS error\n");
+	    goto exit;
+    }
+
+    if(!NI_RoiCoOccurence(num, (int)dims[0], (int)dims[1], mask_image, raw_image,
+			  coc_matrix, distance, orientation))  
+	    goto exit;
+
+
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("");
+
+}
+
+static PyObject *Segmenter_GrowRegion(PyObject *self, PyObject *args)
+{
+
+
+    int num;
+    int nd;
+    int type;
+    int Label;
+    int N_connectivity; 
+    double low_threshold;
+    double high_threshold;
+    npy_intp *dims;
+    npy_intp *objNumber;
+    unsigned short *label;
+    double *section;
+    PyObject  *sArray = NULL;
+    PyObject  *lArray = NULL;
+    PyObject  *eArray = NULL;
+    PyObject  *nArray = NULL;
+    objStruct *expanded_ROI;
+    objStruct *newgrow_ROI;
+
+    if(!PyArg_ParseTuple(args, "OOOOddii", &sArray, &lArray, &eArray, &nArray, &low_threshold,
+			 &high_threshold, &Label, &N_connectivity)){
+            printf("PyArg_ParseTuple error\n");
+	    goto exit;
+    }
+
+    if(!PyArray_ISCONTIGUOUS(sArray) || !PyArray_ISCONTIGUOUS(lArray)){
+            printf("PyArray_ISCONTIGUOUS error\n");
+	    goto exit;
+    }
+
+    section = (double *)PyArray_DATA(sArray);
+    nd      = PyArray_NDIM(sArray);
+    dims    = PyArray_DIMS(sArray);
+    type    = PyArray_TYPE(sArray);
+    num     = PyArray_SIZE(sArray);
+
+    label        = (unsigned short *)PyArray_DATA(lArray);
+    expanded_ROI = (objStruct*)PyArray_DATA(eArray);
+    newgrow_ROI  = (objStruct*)PyArray_DATA(nArray);
+	
+    if(nd == 2){ 
+        if(!NI_GrowRegion2D((int)dims[0], (int)dims[1], section, label, expanded_ROI,
+			    newgrow_ROI, low_threshold, high_threshold, Label, N_connectivity))
+	    goto exit;
+    }
+    else if(nd == 3){ 
+        if(!NI_GrowRegion3D((int)dims[0], (int)dims[1], (int)dims[2], section, label,
+			    expanded_ROI, newgrow_ROI, low_threshold, high_threshold,
+			    Label, N_connectivity))
+	    goto exit;
+    }
+
+
+exit:
+
+    return PyErr_Occurred() ? NULL : (PyObject*)Py_BuildValue("");
+
+}
+
+static PyMethodDef SegmenterMethods[] =
+{
+    { "region_grow",          Segmenter_GrowRegion,         METH_VARARGS, NULL },
+    { "roi_co_occurence",     Segmenter_RoiCoOccurence,     METH_VARARGS, NULL },
+    { "binary_edge",          Segmenter_BinaryEdge,         METH_VARARGS, NULL },
+    { "laws_texture_metric",  Segmenter_LawsTextureMetric,  METH_VARARGS, NULL },
+    { "canny_hysteresis",     Segmenter_CannyHysteresis,    METH_VARARGS, NULL },
+    { "canny_nonmax_supress", Segmenter_CannyNonMaxSupress, METH_VARARGS, NULL },
+    { "canny_filter",         Segmenter_CannyFilter,        METH_VARARGS, NULL },
+    { "sobel_edges",          Segmenter_SobelEdges,         METH_VARARGS, NULL },
+    { "sobel_image",          Segmenter_SobelImage,         METH_VARARGS, NULL },
+    { "edge_prefilter",       Segmenter_EdgePreFilter,      METH_VARARGS, NULL },
+    { "get_blobs",            Segmenter_GetBlobs,           METH_VARARGS, NULL },
+    { "get_blob_regions",     Segmenter_GetBlobRegions,     METH_VARARGS, NULL },
+    { "thin_filter",          Segmenter_ThinFilter,         METH_VARARGS, NULL },
+    {  NULL, NULL, 0, NULL},
+};
+
+PyMODINIT_FUNC init_segment(void)
+{
+    Py_InitModule("_segment", SegmenterMethods);
+    import_array();
+}
+
+
+
+
+

Added: branches/Interpolate1D/ndimage/segment/Segmenter_IMPL.c
===================================================================
--- branches/Interpolate1D/ndimage/segment/Segmenter_IMPL.c	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/segment/Segmenter_IMPL.c	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,1671 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include "ndImage_Segmenter_structs.h"
+
+// these are for this standalone and come out with the full build
+//
+#define MAX(a, b) ((a) > (b) ? (a) : (b)) 
+#define FALSE 0
+#define TRUE  1
+
+
+int NI_EdgePreFilter(int num, int rows, int cols, int lowThreshold, int highThreshold,
+                     int aperature, int HalfFilterTaps, unsigned short *sImage, double *dImage,
+		     double *kernel){
+
+	int i, j, k, n, num1;
+    	int offset;
+	double sum, value;
+	double *buffer;
+	int max_buffer = MAX(rows, cols);
+	int status;
+
+	buffer = calloc(max_buffer+aperature+16, sizeof(double));
+
+	num1 = HalfFilterTaps;
+	offset = 0;
+	for(i = 0; i < rows; ++i){
+	    /* copy image row to local buffer  */
+	    for(j = 0; j < cols; ++j){
+		buffer[num1+j] = sImage[offset+j];
+	    }
+	    /* constant pad the ends of the buffer */
+	    for(j = 0; j < num1; ++j){
+		buffer[j] = buffer[num1];
+	    }
+	    for(j = cols+num1; j < cols+2*num1; ++j){
+		buffer[j] = buffer[cols-1+num1];
+	    }
+
+	    /* Perform Symmetric Convolution in the X dimension. */
+	    for(n = 0, j = num1; j < (cols+num1); ++j, ++n){
+	        sum = buffer[j] * kernel[num1];
+	        for(k = 1; k < num1; ++k){
+	            sum += kernel[num1-k] * (buffer[j+k] + buffer[j-k]);
+	        }
+	        dImage[offset+n] = sum;
+	    }
+	    offset += cols;
+	}
+
+	offset = 0;
+	for(i = 0; i < cols; ++i){
+	    /* copy image column to local buffer */
+	    offset = 0;
+	    for(j = 0; j < rows; ++j){
+            buffer[num1+j] = dImage[offset+i];
+	        offset += cols;
+	    }
+	    /* constant pad the ends of the buffer */
+	    for(j = 0; j < num1; ++j){
+		buffer[j] = buffer[num1];
+	    }
+	    for(j = rows+num1; j < rows+2*num1; ++j){
+	        buffer[j] = buffer[rows-1+num1];
+	    }
+
+	    /* Perform Symmetric Convolution in the Y dimension. */
+	    offset = 0;
+	    for(j = num1; j < (rows+num1); ++j){
+	        sum = buffer[j] * kernel[num1];
+	        for(k = 1; k < num1; ++k){
+	            sum += kernel[num1-k] * (buffer[j+k] + buffer[j-k]);
+	        }
+	        dImage[offset+i] = sum;
+	        offset += cols;
+	    }
+	}
+
+	/* threshold the image */
+	offset = 0;
+	for(i = 0; i < rows; ++i){
+	    for(j = 0; j < cols; ++j){
+		value = dImage[offset+j];
+		if(value < (float)lowThreshold)  value = (float)0.0;
+		if(value > (float)highThreshold) value = (float)0.0;
+		dImage[offset+j] = value;
+	    }
+	    offset += cols;
+	}
+
+	free(buffer);
+
+	status = 1;
+
+	return(status);
+
+}
+
+int NI_SobelImage(int samples, int rows, int cols, double *rawImage, double *edgeImage, double *pAve,
+	          int *minValue, int *maxValue){
+             
+	int i, j;
+	int p, m, n;
+	int offset;
+	int offsetM1;
+	int offsetP1;
+	int status;
+	int count = 0;
+
+	/*
+	// Sobel
+	*/
+	offset = cols;
+	*pAve = 0.0;
+	*minValue = 10000;
+	*maxValue = -10000;
+	for(i = 1; i < rows-1; ++i){
+	    offsetM1 = offset - cols;
+	    offsetP1 = offset + cols;
+	    for(j = 1; j < cols-1; ++j){
+	        n = 2*rawImage[offsetM1+j] + rawImage[offsetM1+j-1] + rawImage[offsetM1+j+1] -
+	            2*rawImage[offsetP1+j] - rawImage[offsetP1+j-1] - rawImage[offsetP1+j+1];
+	        m = 2*rawImage[offset+j-1] + rawImage[offsetM1+j-1] + rawImage[offsetP1+j-1] -
+	            2*rawImage[offset+j+1] - rawImage[offsetM1+j+1] - rawImage[offsetP1+j+1];
+	        p = (int)sqrt((float)(m*m) + (float)(n*n));
+		if(p > 0){
+		    *pAve += p;
+		    if(p > *maxValue) *maxValue = p;
+		    if(p < *minValue) *minValue = p;
+		    ++count;
+		}
+	        edgeImage[offset+j] = p;
+	    }
+	    offset += cols;
+	}
+	/* threshold based on ave */
+	*pAve /= count;
+
+	status = 1;
+
+	return(status);
+
+}
+
+
+int NI_BinaryEdge(int samples, int rows, int cols, unsigned short *labelImage, unsigned short *edgeImage){ 
+
+	int i, j, k;
+	int maxValue;
+	int offset;
+	int offsetM1;
+	int offsetP1;
+	int values3x3[8];
+	int status;
+
+	offset = cols;
+	for(i = 1; i < rows-1; ++i){
+	    offsetM1 = offset - cols;
+	    offsetP1 = offset + cols;
+	    for(j = 1; j < cols-1; ++j){
+		values3x3[0] = labelImage[offset+j] - labelImage[offset+j+1];
+		values3x3[1] = labelImage[offset+j] - labelImage[offsetM1+j+1];
+		values3x3[2] = labelImage[offset+j] - labelImage[offsetM1+j];
+		values3x3[3] = labelImage[offset+j] - labelImage[offsetM1+j-1];
+		values3x3[4] = labelImage[offset+j] - labelImage[offset+j-1];
+		values3x3[5] = labelImage[offset+j] - labelImage[offsetP1+j-1];
+		values3x3[6] = labelImage[offset+j] - labelImage[offsetP1+j];
+		values3x3[7] = labelImage[offset+j] - labelImage[offsetP1+j+1];
+		maxValue = -1;
+		for(k = 0; k < 8; ++k){
+		    maxValue = MAX(maxValue, values3x3[k]);
+		}
+	        edgeImage[offset+j] = maxValue;
+	    }
+	    offset += cols;
+	}
+
+	status = 1;
+
+	return(status);
+
+}
+
+int NI_SobelEdge(int samples, int rows, int cols, double *edgeImage, unsigned short *edges, 
+	         int mode, double pAve, int minValue, int maxValue, double sobelLow){
+
+	int i, j;
+	int offset;
+	int value;
+	int maxIndex;
+	int status;
+	int histogram[256];
+	float pThreshold;
+	double scale;
+	double step;
+
+	scale = 1.0 / maxValue;
+
+	step = 255.0/(maxValue-minValue);
+	for(i = 0; i < 256; ++i){
+	    histogram[i] = 0;
+	}
+	offset = 0;
+	for(i = 0; i < rows; ++i){
+	    for(j = 0; j < cols; ++j){
+		value = (int)(step*(edgeImage[offset+j]-minValue));
+	        ++histogram[value];
+	    }
+	    offset += cols;
+	}
+
+	if(mode == 1){
+	    /* based on the mean value of edge energy */
+	    pThreshold = (int)(sobelLow * (float)pAve);
+	}
+	else{
+	    /* based on the mode value of edge energy */
+	    pThreshold = (sobelLow * (minValue + ((float)maxIndex/step)));
+	}
+
+	offset = 0;
+	for(i = 0; i < rows; ++i){
+	    for(j = 0; j < cols; ++j){
+		if(edgeImage[offset+j] > pThreshold){
+		    edges[offset+j] = 1;
+		}
+		else{
+		    edges[offset+j] = 0;
+		}
+	    }
+	    offset += cols;
+	}
+
+	status = 1;
+	return(status);
+
+}
+
+int NI_GetBlobs3D(int samples, int layers, int rows, int cols, unsigned short *edges,
+	       	   unsigned short *connectedEdges, int *groups, int mask){ 
+
+	int  i, j, k, l, m;
+	int  lOffset, rOffset, Label;
+	int  lOffsetP, lOffsetN;
+	int  rOffsetP, rOffsetN;
+	int  Classes[4096];
+	int  dwImageSize, ptr;
+	bool NewLabel;
+	bool Change;
+	bool connected;
+	int  T[27];
+	int  *ccompImage;
+	int  layerSize;
+	int  count;
+	int  status;
+
+	layerSize   = rows * cols;
+	dwImageSize = layers * rows * cols;
+	ccompImage  = calloc(dwImageSize, sizeof(int ));
+
+	Label = 1;
+	for(i = 1; i < layers-1; ++i){
+	    lOffset  = i * layerSize;
+	    lOffsetP = lOffset+layerSize;
+	    lOffsetN = lOffset-layerSize;
+	    for(j = 1; j < rows-1; ++j){
+		rOffset = j * cols;
+		rOffsetP = rOffset+cols;
+		rOffsetN = rOffset-cols;
+		for(k = 1; k < cols-1; ++k){
+		    if(edges[lOffset+rOffset+k]){
+			/*
+			 check 3x3x3 connectivity
+			*/
+
+			T[0]  = edges[lOffset+rOffset+k];
+			T[1]  = edges[lOffset+rOffset+k+1];
+			T[2]  = edges[lOffset+rOffsetN+k+1];
+			T[3]  = edges[lOffset+rOffsetN+k];
+			T[4]  = edges[lOffset+rOffsetN+k-1];
+			T[5]  = edges[lOffset+rOffset+k-1];
+			T[6]  = edges[lOffset+rOffsetP+k-1];
+			T[7]  = edges[lOffset+rOffsetP+k];
+			T[8]  = edges[lOffset+rOffsetP+k+1];
+
+			T[9]  = edges[lOffsetN+rOffset+k];
+			T[10] = edges[lOffsetN+rOffset+k+1];
+			T[11] = edges[lOffsetN+rOffsetN+k+1];
+			T[12] = edges[lOffsetN+rOffsetN+k];
+			T[13] = edges[lOffsetN+rOffsetN+k-1];
+			T[14] = edges[lOffsetN+rOffset+k-1];
+			T[15] = edges[lOffsetN+rOffsetP+k-1];
+			T[16] = edges[lOffsetN+rOffsetP+k];
+			T[17] = edges[lOffsetN+rOffsetP+k+1];
+
+			T[18] = edges[lOffsetP+rOffset+k];
+			T[19] = edges[lOffsetP+rOffset+k+1];
+			T[20] = edges[lOffsetP+rOffsetN+k+1];
+			T[21] = edges[lOffsetP+rOffsetN+k];
+			T[22] = edges[lOffsetP+rOffsetN+k-1];
+			T[23] = edges[lOffsetP+rOffset+k-1];
+			T[24] = edges[lOffsetP+rOffsetP+k-1];
+			T[25] = edges[lOffsetP+rOffsetP+k];
+			T[26] = edges[lOffsetP+rOffsetP+k+1];
+
+			connected = FALSE;
+			if(mask == 1){
+			    count = 0;
+			    for(l = 1; l < 27; ++l){
+				count += T[l];
+			    }
+			    if(count){
+				connected = TRUE;
+			    }
+			}
+			else if(mask == 6){
+			    count = (T[2] + T[4] + T[6] + T[8] + T[9] + T[18]);
+			    if(count == 6){
+				connected = TRUE;
+			    }
+			}
+			else if(mask == 14){
+			    count = (T[2] + T[4] + T[6] + T[8] + T[9] + T[18] + T[11] +
+				     T[13] + T[15] + T[17] + T[20] + T[22] + T[24] + T[26]);
+			    if(count == 14){
+				connected = TRUE;
+			    }
+			}
+			else if(mask == 26){
+			    count = 0;
+			    for(l = 1; l < 27; ++l){
+				count += T[l];
+			    }
+			    if(count == 26){
+				connected = TRUE;
+			    }
+			}
+			if(connected){
+			    ccompImage[lOffset+rOffset+k] = Label++;
+			}
+		    }
+		}
+	    }
+	}
+
+
+	while(1){
+	Change = FALSE;
+	    /*
+	    // TOP-DOWN Pass for labeling
+	    */
+	    for(i = 1; i < layers-1; ++i){
+		lOffset  = i * layerSize;
+		lOffsetP = lOffset+layerSize;
+		lOffsetN = lOffset-layerSize;
+		for(j = 1; j < rows-1; ++j){
+		    rOffset = j * cols;
+		    rOffsetP = rOffset+cols;
+		    rOffsetN = rOffset-cols;
+		    for(k = 1; k < cols-1; ++k){
+			if(ccompImage[lOffset+rOffset+k] != 0){
+
+			    T[0]  = ccompImage[lOffset+rOffset+k];
+			    T[1]  = ccompImage[lOffset+rOffset+k+1];
+			    T[2]  = ccompImage[lOffset+rOffsetN+k+1];
+			    T[3]  = ccompImage[lOffset+rOffsetN+k];
+			    T[4]  = ccompImage[lOffset+rOffsetN+k-1];
+			    T[5]  = ccompImage[lOffset+rOffset+k-1];
+			    T[6]  = ccompImage[lOffset+rOffsetP+k-1];
+			    T[7]  = ccompImage[lOffset+rOffsetP+k];
+			    T[8]  = ccompImage[lOffset+rOffsetP+k+1];
+
+			    T[9]  = ccompImage[lOffsetN+rOffset+k];
+			    T[10] = ccompImage[lOffsetN+rOffset+k+1];
+			    T[11] = ccompImage[lOffsetN+rOffsetN+k+1];
+			    T[12] = ccompImage[lOffsetN+rOffsetN+k];
+			    T[13] = ccompImage[lOffsetN+rOffsetN+k-1];
+			    T[14] = ccompImage[lOffsetN+rOffset+k-1];
+			    T[15] = ccompImage[lOffsetN+rOffsetP+k-1];
+			    T[16] = ccompImage[lOffsetN+rOffsetP+k];
+			    T[17] = ccompImage[lOffsetN+rOffsetP+k+1];
+
+			    T[18] = ccompImage[lOffsetP+rOffset+k];
+			    T[19] = ccompImage[lOffsetP+rOffset+k+1];
+			    T[20] = ccompImage[lOffsetP+rOffsetN+k+1];
+			    T[21] = ccompImage[lOffsetP+rOffsetN+k];
+			    T[22] = ccompImage[lOffsetP+rOffsetN+k-1];
+			    T[23] = ccompImage[lOffsetP+rOffset+k-1];
+			    T[24] = ccompImage[lOffsetP+rOffsetP+k-1];
+			    T[25] = ccompImage[lOffsetP+rOffsetP+k];
+			    T[26] = ccompImage[lOffsetP+rOffsetP+k+1];
+						
+			    m = T[0];
+			    for(l = 1; l < 27; ++l){
+				if(T[l] != 0){
+				    if(T[l] < m) m = T[l];
+			        }
+			    }
+			    if(m != ccompImage[lOffset+rOffset+k]){
+				Change = TRUE;
+				ccompImage[lOffset+rOffset+k] = m;
+			    }
+			}
+		    }
+		}
+	    }
+	    /*
+	    // BOTTOM-UP Pass for labeling
+	    */
+	    for(i = layers-1; i > 0; --i){
+		lOffset  = i * layerSize;
+		lOffsetP = lOffset+layerSize;
+		lOffsetN = lOffset-layerSize;
+		for(j = rows-1; j > 0; --j){
+		    rOffset = j * cols;
+		    rOffsetP = rOffset+cols;
+		    rOffsetN = rOffset-cols;
+		    for(k = cols-1; k > 0; --k){
+			if(ccompImage[lOffset+rOffset+k] != 0){
+
+			    T[0]  = ccompImage[lOffset+rOffset+k];
+			    T[1]  = ccompImage[lOffset+rOffset+k+1];
+			    T[2]  = ccompImage[lOffset+rOffsetN+k+1];
+			    T[3]  = ccompImage[lOffset+rOffsetN+k];
+			    T[4]  = ccompImage[lOffset+rOffsetN+k-1];
+			    T[5]  = ccompImage[lOffset+rOffset+k-1];
+			    T[6]  = ccompImage[lOffset+rOffsetP+k-1];
+			    T[7]  = ccompImage[lOffset+rOffsetP+k];
+			    T[8]  = ccompImage[lOffset+rOffsetP+k+1];
+
+			    T[9]  = ccompImage[lOffsetN+rOffset+k];
+			    T[10] = ccompImage[lOffsetN+rOffset+k+1];
+			    T[11] = ccompImage[lOffsetN+rOffsetN+k+1];
+			    T[12] = ccompImage[lOffsetN+rOffsetN+k];
+			    T[13] = ccompImage[lOffsetN+rOffsetN+k-1];
+			    T[14] = ccompImage[lOffsetN+rOffset+k-1];
+			    T[15] = ccompImage[lOffsetN+rOffsetP+k-1];
+			    T[16] = ccompImage[lOffsetN+rOffsetP+k];
+			    T[17] = ccompImage[lOffsetN+rOffsetP+k+1];
+
+			    T[18] = ccompImage[lOffsetP+rOffset+k];
+			    T[19] = ccompImage[lOffsetP+rOffset+k+1];
+			    T[20] = ccompImage[lOffsetP+rOffsetN+k+1];
+			    T[21] = ccompImage[lOffsetP+rOffsetN+k];
+			    T[22] = ccompImage[lOffsetP+rOffsetN+k-1];
+			    T[23] = ccompImage[lOffsetP+rOffset+k-1];
+			    T[24] = ccompImage[lOffsetP+rOffsetP+k-1];
+			    T[25] = ccompImage[lOffsetP+rOffsetP+k];
+			    T[26] = ccompImage[lOffsetP+rOffsetP+k+1];
+						
+			    m = T[0];
+			    for(l = 1; l < 27; ++l){
+				if(T[l] != 0){
+				    if(T[l] < m) m = T[l];
+			        }
+			    }
+			    if(m != ccompImage[lOffset+rOffset+k]){
+				Change = TRUE;
+				ccompImage[lOffset+rOffset+k] = m;
+			    }
+			}
+		    }
+		}
+	    }
+
+	    if(!Change) break;
+
+	}   /* end while loop  */
+
+	Label      = 1;
+	Classes[0] = 0;
+	ptr        = 0;
+	for(i = 0; i < layers; ++i){
+	    for(j = 0; j < rows; ++j){
+		for(k = 0; k < cols; ++k){
+		    m =	ccompImage[ptr];
+		    ++ptr;
+		    if(m > 0){
+			NewLabel = TRUE;
+			for(l = 1; l < Label; ++l){
+			    if(Classes[l] == m) NewLabel = FALSE;
+			}
+			if(NewLabel){
+			    Classes[Label++] = m;
+			    if(Label > 4000){
+				return 0;
+			    }
+			}
+		    }
+		}
+	    }
+	}
+
+	*groups = Label;
+
+	ptr = 0;
+	for(i = 0; i < layers; ++i){
+	    for(j = 0; j < rows; ++j){
+		for(k = 0; k < cols; ++k){
+		    m =	ccompImage[ptr];
+		    for(l = 1; l < Label; ++l){
+			if(Classes[l] == m){
+			    connectedEdges[ptr] = l;
+			    break;
+			}
+		    }
+		    ++ptr;
+		}
+	    }
+	}
+
+	free(ccompImage);
+
+	status = 1;
+	return(status);
+
+}
+
+int NI_GetBlobs2D(int samples, int rows, int cols, unsigned short *edges, unsigned short *connectedEdges,
+	       	  int *groups, int mask){ 
+
+	int            i, j, k, l, m;
+	int            offset;
+	int            Label;
+	int            status;
+	int            Classes[4096];
+	bool           NewLabel;
+	bool           Change;
+	bool           connected;
+	int            count;
+	unsigned short T[12];
+
+	/*
+	// connected components labeling. pixels with 1, 4 or 8 connectedness. 
+	*/
+	Label  = 1;
+	offset = 0;
+	for(i = 0; i < rows; ++i){
+	    for(j = 0; j < cols; ++j){
+		connectedEdges[offset+j] = 0; 
+		if(edges[offset+j] == 1){
+		    connected = FALSE;
+		    if(mask == 1){
+			count = 0;
+			for(l = 1; l < 9; ++l){
+			    count += T[l];
+			}
+			if(count){
+			    connected = TRUE;
+			}
+		    }
+		    else if(mask == 4){
+			count = (T[2] + T[4] + T[6] + T[8]);
+			if(count == 4){
+			    connected = TRUE;
+			}
+		    }
+		    else if(mask == 8){
+			count = 0;
+			for(l = 1; l < 9; ++l){
+			    count += T[l];
+			}
+			if(count == 8){
+			    connected = TRUE;
+			}
+		    }
+		    if(connected){
+		        connectedEdges[offset+j] = Label++; 
+		    }
+		}
+	    }
+	    offset += cols;
+	}
+
+	while(1){
+	    Change = FALSE;
+	    /*
+	    // TOP-DOWN Pass for labeling
+	    */
+	    offset = cols;
+	    for(i = 1; i < rows-1; ++i){
+		for(j = 1; j < cols-1; ++j){
+		    if(connectedEdges[offset+j] != 0){
+			T[0] = connectedEdges[offset+j];
+			T[1] = connectedEdges[offset+j+1];
+			T[2] = connectedEdges[offset-cols+j+1];
+			T[3] = connectedEdges[offset-cols+j];
+			T[4] = connectedEdges[offset-cols+j-1];
+			T[5] = connectedEdges[offset+j-1];
+			T[6] = connectedEdges[offset+cols+j-1];
+			T[7] = connectedEdges[offset+cols+j];
+			T[8] = connectedEdges[offset+cols+j+1];
+			m = T[0];
+			for(l = 1; l < 9; ++l){
+			    if(T[l] != 0){
+				if(T[l] < m) m = T[l];
+			    }
+			}
+			if(m != connectedEdges[offset+j]){
+			    Change = TRUE;
+			    connectedEdges[offset+j] = m;
+			}
+		    }
+		}
+		offset += cols;
+	    }
+	    /*
+	    // BOTTOM-UP Pass for labeling
+	    */
+	    offset = (rows-1)*cols;
+	    for(i = (rows-1); i > 1; --i){
+		for(j = (cols-1); j > 1; --j){
+		    if(connectedEdges[offset+j] != 0){
+			T[0] = connectedEdges[offset+j];
+			T[1] = connectedEdges[offset+j+1];
+			T[2] = connectedEdges[offset-cols+j+1];
+			T[3] = connectedEdges[offset-cols+j];
+			T[4] = connectedEdges[offset-cols+j-1];
+			T[5] = connectedEdges[offset+j-1];
+			T[6] = connectedEdges[offset+cols+j-1];
+			T[7] = connectedEdges[offset+cols+j];
+			T[8] = connectedEdges[offset+cols+j+1];
+			m = T[0];
+			for(l = 1; l < 9; ++l){
+			    if(T[l] != 0){
+				if(T[l] < m) m = T[l];
+			    }
+			}
+			if(m != connectedEdges[offset+j]){
+			    Change = TRUE;
+			    connectedEdges[offset+j] = m;
+			}
+		    }
+		}
+		offset -= cols;
+	    }
+	    if(!Change) break;
+	}   /* end while loop */
+
+	Classes[0] = 0;
+	Label      = 1;
+	offset     = cols;
+	for(i = 1; i < (rows-1); ++i){
+	    for(j = 1; j < (cols-1); ++j){
+		m = connectedEdges[offset+j];
+		if(m > 0){
+		    NewLabel = TRUE;
+		    for(k = 1; k < Label; ++k){
+			if(Classes[k] == m) NewLabel = FALSE;
+		    }
+		    if(NewLabel){
+			Classes[Label++] = m;
+			if(Label > 4000){
+			    return 0; /* too many labeled regions. this is a pathology */
+			}
+		    }
+		}
+	    }
+	    offset += cols;
+	}
+
+	/*
+	// re-label the connected blobs in continuous label order
+	*/
+	offset = cols;
+	for(i = 1; i < (rows-1); ++i){
+	    for(j = 1; j < (cols-1); ++j){
+		m = connectedEdges[offset+j];
+		if(m > 0){
+		    for(k = 1; k < Label; ++k){
+			if(Classes[k] == m){
+			    connectedEdges[offset+j] = (unsigned short)k;
+			    break;
+			}
+		    }
+		}
+	    }
+	    offset += cols;
+	}
+
+	*groups = Label;
+
+	/*
+	// prune the isolated pixels
+	*/
+	offset  = 0;
+	for(i = 0; i < rows; ++i){
+	    for(j = 0; j < cols; ++j){
+		if(connectedEdges[offset+j] > (*groups)){
+		    connectedEdges[offset+j] = 0;
+		}	
+	    }
+	    offset  += cols;
+	}
+
+	status = 1;
+	return(status);
+
+}
+
+int NI_GetBlobRegions3D(int layers, int rows, int cols, int numberObjects, 
+                        unsigned short *labeledEdges, objStruct objectMetrics[]){
+
+
+	int status;
+	int i, j, k, l, m;
+	int offset;
+	int count;
+	int LowX;
+	int LowY;
+	int LowZ;
+	int HighX;
+	int HighY;
+	int HighZ;
+	int ptr;
+	float centerX;
+	float centerY;
+	float centerZ;
+
+	for(l = 1; l < numberObjects; ++l){
+	    offset     = cols;
+	    LowX       = 32767;
+	    LowY       = 32767;
+	    LowZ       = 32767;
+	    HighX      = 0;
+	    HighY      = 0;
+	    HighZ      = 0;
+	    count      = 0;
+	    centerX    = (float)0.0;
+	    centerY    = (float)0.0;
+	    centerZ    = (float)0.0;
+	    ptr        = 0;
+	    for(i = 0; i < layers; ++i){
+		for(j = 0; j < rows; ++j){
+		    for(k = 0; k < cols; ++k){
+		        m = labeledEdges[ptr++];
+			if(l == m){
+			    if(i < LowZ)   LowZ = i;
+			    if(j < LowY)   LowY = j;
+			    if(k < LowX)   LowX = k;
+			    if(i > HighZ) HighZ = i;
+			    if(j > HighY) HighY = j;
+			    if(k > HighX) HighX = k;
+	    		    centerX += (float)k;
+	    		    centerY += (float)j;
+	    		    centerZ += (float)i;
+	    		    ++count;
+			}
+		    }
+		}
+	    }
+	    /* the bounding box for the 2D blob */
+	    objectMetrics[l-1].Left   = LowX;
+	    objectMetrics[l-1].Right  = HighX;
+	    objectMetrics[l-1].Bottom = LowY;
+	    objectMetrics[l-1].Top    = HighY;
+	    objectMetrics[l-1].Front  = LowZ;
+	    objectMetrics[l-1].Back   = HighZ;
+	    objectMetrics[l-1].Mass   = count;
+	    objectMetrics[l-1].cX     = centerX/(float)count;
+	    objectMetrics[l-1].cY     = centerY/(float)count;
+	    objectMetrics[l-1].cZ     = centerZ/(float)count;
+	    objectMetrics[l-1].Label  = l;
+	}
+
+	status = numberObjects;
+
+	return(status);
+
+}
+
+int NI_GetBlobRegions2D(int rows, int cols, int numberObjects, unsigned short *labeledEdges,
+                        objStruct objectMetrics[]){
+
+	int i, j, k, m;
+	int count;
+	int LowX;
+	int LowY;
+	int HighX;
+	int HighY;
+	int status;
+	int ptr;
+	float centerX;
+	float centerY;
+
+	for(k = 1; k < numberObjects; ++k){
+	    LowX       = 32767;
+	    LowY       = 32767;
+	    HighX      = 0;
+	    HighY      = 0;
+	    count      = 0;
+	    centerX    = (float)0.0;
+	    centerY    = (float)0.0;
+	    ptr        = 0;
+	    for(i = 0; i < rows; ++i){
+		for(j = 0; j < cols; ++j){
+		    m = labeledEdges[ptr++];
+		    if(k == m){
+			if(i < LowY)   LowY = i;
+			if(j < LowX)   LowX = j;
+			if(i > HighY) HighY = i;
+			if(j > HighX) HighX = j;
+	    		centerX += (float)j;
+	    		centerY += (float)i;
+	    		++count;
+		    }
+		}
+	    }
+	    /* the bounding box for the 2D blob */
+	    objectMetrics[k-1].Left   = LowX;
+	    objectMetrics[k-1].Right  = HighX;
+	    objectMetrics[k-1].Bottom = LowY;
+	    objectMetrics[k-1].Top    = HighY;
+	    objectMetrics[k-1].Mass   = count;
+	    objectMetrics[k-1].cX     = centerX/(float)count;
+	    objectMetrics[k-1].cY     = centerY/(float)count;
+	    objectMetrics[k-1].Label  = k;
+	}
+
+	status = numberObjects;
+	return status;
+
+}
+
+
+int NI_ThinMorphoFilter(int regRows, int regColumns, int spadSize, int masks, unsigned short *J_mask, 
+	                 unsigned short *K_mask, unsigned char *Input, unsigned char *CInput, 
+	                 unsigned char *ErosionStage, unsigned char *DialationStage, 
+		         unsigned char *HMT, unsigned char *Copy){
+
+	int i, j, k, l, m, n, overlap, hit;
+	int LowValue1, HighValue1;   
+	int LowValue2, HighValue2;   
+	int Column, T, nloop;
+	int Offset;
+	int N, M;
+	int maskCols = 3;
+	int j_mask[3][3];
+	int k_mask[3][3];
+	int status;
+
+	N = regRows;
+	M = regColumns;
+
+	LowValue1  = 1;   
+	HighValue1 = 0;   
+
+	LowValue2  = 0;   
+	HighValue2 = 1;   
+
+	Offset = 0;
+	for(i = 0; i < N; ++i){
+	    for(j = 0; j < M; ++j){
+		Copy[Offset+j] = Input[Offset+j];
+	    }
+	    Offset += spadSize;
+	}
+
+	nloop = 0;
+	while(1){
+	    /* erode */
+	    Column = 0;
+	    for(n = 0; n < masks; ++n){
+		for(i = 0; i < 3; ++i){
+		    for(j = 0; j < 3; ++j){
+			j_mask[i][j] = J_mask[i+maskCols*(Column+j)];
+		    }
+		}
+		for(i = 0; i < 3; ++i){
+		    for(j = 0; j < 3; ++j){
+			k_mask[i][j] = K_mask[i+maskCols*(Column+j)];
+		    }
+		}
+		Column += 3;
+
+		Offset = spadSize;
+		for(i = 1; i < N-1; ++i){
+		    for(j = 1; j < M-1; ++j){
+			hit = LowValue1; 
+			for(k = -1; k < 2; ++k){
+			    for(l = -1; l < 2; ++l){
+				T = j_mask[k+1][l+1];
+				if(T == 1){
+				    overlap = T*Input[Offset+(k*spadSize)+j+l];
+				    if(overlap == HighValue1) hit = HighValue1;
+				}
+			    }
+			}
+			ErosionStage[Offset+j] = hit;
+		    }
+		    Offset += spadSize;
+		}
+
+		/* dialate */
+		Offset = 0;
+		for(i = 0; i < N; ++i){
+		    for(j = 0; j < M; ++j){
+			CInput[Offset+j] = (~Input[Offset+j]) & 0x1; 
+		    }
+		    Offset += spadSize;
+		}
+
+		Offset = spadSize;
+		for(i = 1; i < N-1; ++i){
+		    for(j = 1; j < M-1; ++j){
+			hit = LowValue1; 
+			for(k = -1; k < 2; ++k){
+			    for(l = -1; l < 2; ++l){
+				T = k_mask[k+1][l+1];
+				if(T == 1){
+				    overlap = T*CInput[Offset+(k*spadSize)+j+l];
+				    if(overlap == HighValue1) hit = HighValue1;
+			        }
+			    }
+			}
+			DialationStage[Offset+j] = hit;
+		    }
+		    Offset += spadSize;
+		}
+
+		/* form the HMT */
+		Offset = 0;
+		for(i = 0; i < N; ++i){
+		    for(j = 0; j < M; ++j){
+			m = (ErosionStage[Offset+j]*DialationStage[Offset+j]);
+			HMT[Offset+j] = m;
+		    }
+		    Offset += spadSize;
+		}
+
+		/* Thin for stage n */
+
+		Offset = 0;
+		for(i = 0; i < N; ++i){
+		    for(j = 0; j < M; ++j){
+			HMT[Offset+j] = (~HMT[Offset+j]) & 0x1; 
+		    }
+		    Offset += spadSize;
+		}
+
+		Offset = 0;
+		for (i = 0; i < N; ++i){
+		    for (j = 0; j < M; ++j){
+			m = (Input[Offset+j]*HMT[Offset+j]);
+			Input[Offset+j] = m;
+		    }
+		    Offset += spadSize;
+		}
+	    }
+
+	    /* check for no change */
+	    hit = 0;
+	    Offset = 0;
+	    for(i = 0; i < N; ++i){
+		for(j = 0; j < M; ++j){
+		    hit += abs(Copy[Offset+j]-Input[Offset+j]);
+		}
+		Offset += spadSize;
+	    }
+	    if(!hit) break;
+
+	    hit = 0;
+	    Offset = 0;
+	    for(i = 0; i < N; ++i){
+		for(j = 0; j < M; ++j){
+		    Copy[Offset+j] = Input[Offset+j];
+		    if(Input[Offset+j]) ++hit;
+		}
+		Offset += spadSize;
+	    }
+	    /* nloop is data dependent. */
+	    ++nloop;
+	}
+
+
+	status = 1;
+	return status;
+
+}
+
+
+int NI_CannyFilter(int samples, int rows, int cols, double *rawImage,
+		   double *hDGImage, double *vDGImage, double *dgKernel, 
+                   int gWidth, float *aveXValue, float *aveYValue){
+               
+
+	/*
+	// implements the derivative of Gaussian filter. kernel set by CannyEdges
+	*/
+	int i, j, k;
+	int ptr;
+	int mLength;
+	int count;
+	int status;
+	float *tBuffer = NULL;
+	double sum;
+
+	*aveXValue = (float)0.0;
+	*aveYValue = (float)0.0;	
+
+	mLength = MAX(rows, cols) + 64;
+	tBuffer = calloc(mLength, sizeof(float));
+
+	/*
+	// filter X 
+	*/
+	count = 0;
+	for(i = 0; i < rows; ++i){
+	    ptr = i * cols;
+	    for(j = gWidth; j < cols-gWidth; ++j){
+		sum = dgKernel[0] * rawImage[ptr+j];
+		for(k = 1; k < gWidth; ++k){
+		    sum += dgKernel[k] * (-rawImage[ptr+j+k] + rawImage[ptr+j-k]);
+		}
+		hDGImage[ptr+j] = (float)sum;
+		if(sum != (float)0.0){
+		    ++count;
+		    *aveXValue += (float)fabs(sum);
+		}
+	    }
+	}
+	if(count){
+	    *aveXValue /= (float)count;
+	}
+	/*
+	// filter Y 
+	*/
+	count = 0;
+	for(i = 0; i < cols; ++i){
+	    for(j = 0; j < rows; ++j){
+		ptr = j * cols;
+		tBuffer[j] = rawImage[ptr+i];
+	    }
+	    for(j = gWidth; j < rows-gWidth; ++j){
+		ptr = j * cols;
+		sum = dgKernel[0] * tBuffer[j];
+		for(k = 1; k < gWidth; ++k){
+		    sum += dgKernel[k] * (-tBuffer[j+k] + tBuffer[j-k]);
+		}
+		vDGImage[ptr+i] = sum;
+		if(sum != (float)0.0){
+		    ++count;
+		    *aveYValue += (float)fabs(sum);
+		}
+	    }
+	}
+	if(count){
+	    *aveYValue /= (float)count;
+	}
+
+	free(tBuffer);
+
+	status = 1;
+
+	return status;
+
+}
+
+double tmagnitude(double X, double Y){
+	return sqrt(X*X + Y*Y);
+}
+
+int NI_CannyNonMaxSupress(int num, int rows, int cols, double *magImage, double *hDGImage,
+	                  double *vDGImage, int mode, double aveXValue, double aveYValue,
+			  double *tAve, double *cannyLow, double *cannyHigh, 
+			  double cannyL, double cannyH){
+                   
+	int i, j;
+	int ptr, ptr_m1, ptr_p1;
+	float xSlope, ySlope, G1, G2, G3, G4, G, xC, yC;
+	float scale;
+	float maxValue = (float)0.0;
+	float minValue = (float)0.0;
+	int value;
+	int mValue;
+	int mIndex;
+	int count;
+	int status;
+	int histogram[256];
+	double step;
+
+	for(i = 1; i < rows-1; ++i){
+	    ptr = i * cols;
+	    ptr_m1 = ptr - cols;
+	    ptr_p1 = ptr + cols;
+	    for(j = 1; j < cols; ++j){
+		magImage[ptr+j] = (float)0.0;
+		xC = hDGImage[ptr+j];
+		yC = vDGImage[ptr+j];
+		if(!((fabs(xC) < aveXValue) && (fabs(yC) < aveYValue))){
+		    G = tmagnitude(xC, yC);
+		    if(fabs(yC) > fabs(xC)){
+		        /* vertical gradient */
+		        xSlope = (float)(fabs(xC) / fabs(yC));
+		        ySlope = (float)1.0;
+		        G2 = tmagnitude(hDGImage[ptr_m1+j], vDGImage[ptr_m1+j]);
+		        G4 = tmagnitude(hDGImage[ptr_p1+j], vDGImage[ptr_p1+j]);	
+		        if((xC*yC) > (float)0.0){
+			    G1 = tmagnitude(hDGImage[ptr_m1+j-1], vDGImage[ptr_m1+j-1]);
+			    G3 = tmagnitude(hDGImage[ptr_p1+j+1], vDGImage[ptr_p1+j+1]);
+		        }
+		        else{
+			    G1 = tmagnitude(hDGImage[ptr_m1+j+1], vDGImage[ptr_m1+j+1]);
+			    G3 = tmagnitude(hDGImage[ptr_p1+j-1], vDGImage[ptr_p1+j-1]);
+		        }
+		    }
+		    else{
+		        /* horizontal gradient */
+		        xSlope = (float)(fabs(yC) / fabs(xC));
+		        ySlope = (float)1.0;
+		        G2 = tmagnitude(hDGImage[ptr+j+1], vDGImage[ptr+j+1]);
+		        G4 = tmagnitude(hDGImage[ptr+j-1], vDGImage[ptr+j-1]);	
+		        if((xC*yC) > (float)0.0){
+			    G1 = tmagnitude(hDGImage[ptr_p1+j+1], vDGImage[ptr_p1+j+1]);
+			    G3 = tmagnitude(hDGImage[ptr_m1+j-1], vDGImage[ptr_m1+j-1]);
+		        }
+		        else{
+			    G1 = tmagnitude(hDGImage[ptr_m1+j+1], vDGImage[ptr_m1+j+1]);
+			    G3 = tmagnitude(hDGImage[ptr_p1+j-1], vDGImage[ptr_p1+j-1]);
+		        }
+		    }
+		    if((G > (xSlope*G1+(ySlope-xSlope)*G2))&&(G > (xSlope*G3+(ySlope-xSlope)*G4))){
+		        magImage[ptr+j] = G;	
+		    }
+		    if(magImage[ptr+j] > maxValue) maxValue = magImage[ptr+j];
+		    if(magImage[ptr+j] < minValue) minValue = magImage[ptr+j];
+		}
+	    }
+	}
+
+	scale = (float)1.0 / (maxValue-minValue);
+	ptr   = 0;
+	count = 0;
+	*tAve  = 0.0;
+	for(i = 0; i < rows; ++i){
+	    for(j = 0; j < cols; ++j){
+		magImage[ptr] = scale * (magImage[ptr]-minValue);
+		if(magImage[ptr] > 0.0){
+		    *tAve += magImage[ptr];
+		    ++count;
+		}
+		++ptr;
+	    }
+	}
+	*tAve /= (float)count;
+
+	step = 255.0;
+	for(i = 0; i < 256; ++i){
+	    histogram[i] = 0;
+	}
+	ptr = 0;
+	for(i = 0; i < rows; ++i){
+	    for(j = 0; j < cols; ++j){
+		value = (int)(step*(magImage[ptr]));
+	        ++histogram[value];
+		++ptr;
+	    }
+	}
+	/*
+	// now get the max after skipping the low values
+	*/
+	mValue = -1;
+	mIndex = 0;
+	for(i = 10; i < 256; ++i){
+	    if(histogram[i] > mValue){
+		mValue = histogram[i];
+		mIndex = i;
+	    }
+	}
+
+	if(mode == 1){
+	    /* based on the mean value of edge energy */
+	    *cannyLow  = ((cannyL)  * *tAve);
+	    *cannyHigh = ((cannyH) * *tAve);
+	}
+	else{
+	    /* based on the mode value of edge energy */
+	    *cannyLow  = ((cannyL)  * ((float)mIndex/step));
+	    *cannyHigh = ((cannyH) * ((float)mIndex/step));
+	}
+	status = 1;
+
+	return status;
+
+}
+
+int trace_Edge(int i, int j, int rows, int cols, double cannyLow, double *magImage,
+               unsigned short *hys_image){
+
+	int n, m;
+	int ptr;
+	int flag;
+
+	ptr = i * cols;
+	if(hys_image[ptr+j] == 0){
+	    /*
+	    // this point is above high threshold
+	    */
+	    hys_image[ptr+j] = 1;
+	    flag = 0;
+	    for(n = -1; n <= 1; ++n){
+		for(m = -1; m <= 1; ++m){
+		    if(n == 0 && m == 0) continue;
+		    if(((i+n) > 0) && ((j+m) > 0) && ((i+n) < rows) && ((j+m) < cols)){
+			ptr = (i+n) * cols;
+			if(magImage[ptr+j+m] > cannyLow){
+	    		    /*
+	    		    // this point is above low threshold
+	    		    */
+			    if(trace_Edge(i+n, j+m, rows, cols, cannyLow, magImage, hys_image)){
+				flag = 1;
+				break;
+			    }
+			}
+		    }
+		}
+		if(flag) break;
+	    }
+	    return(1);
+	}
+
+	return(0);
+
+}
+
+int NI_CannyHysteresis(int num, int rows, int cols, double *magImage, unsigned short *hys_image,
+		       double cannyLow, double cannyHigh){ 
+
+
+	int status;
+	int i, j;
+	int ptr;
+
+	for(i = 0; i < rows; ++i){
+	    ptr = i * cols;
+	    for(j = 0; j < cols; ++j){
+		if(magImage[ptr+j] > cannyHigh){
+		    trace_Edge(i, j, rows, cols, cannyLow, magImage, hys_image);
+		}
+	    }
+	}
+
+	status = 1;
+
+	return status;
+
+}
+
+float lawsConvolution(float *image, float *rowFilter, float *colFilter, int kernelSize){
+
+	int i, j;
+	int offset;
+	float result[7];
+	float sum;
+
+	/* filter rows */
+	for(i = 0; i < kernelSize; ++i){
+	    sum = (float)0.0;
+	    offset = i * kernelSize;
+	    for(j = 0; j < kernelSize; ++j){
+		sum += (rowFilter[j]*image[offset+j]);
+	    }
+	    result[i] = sum;
+	}
+
+	/* filter columns */
+	sum = (float)0.0;
+	for(j = 0; j < kernelSize; ++j){
+	    sum += (rowFilter[j]*result[j]);
+	}
+
+	return(sum);
+
+}
+
+void computeLaws(LawsFilter7 lawsFilter, int aperature, int srcRows, int srcCols, 
+                 unsigned short *MaskImage, float *lawsImage, double *sourceImage){
+
+	/*
+	// hard-wirred to Law's 7 kernels
+	*/
+	int i, j;
+	int lawsLayer;
+	int column, row;
+	int maskOffset[7];
+	int dataOffset[7];
+	float myImage[49];
+	int count;
+	int outerKernelNumber;
+	int innerKernelNumber;
+	int rowNumber;
+	int kernelSize = lawsFilter.kernelLength;
+	int fullMask   = kernelSize*kernelSize;
+	int layerStep  = srcRows*srcCols;
+	float *rowFilter;
+	float *colFilter;
+	float filterResult1;
+	float filterResult2;
+	float lawsLL=1.0;
+
+	for(i = aperature; i < srcRows-aperature; ++i){
+	    // get the row array offset for mask and data source. 
+	    for(row = -aperature; row <= aperature; ++row){
+		maskOffset[row+aperature] = (i+row)*srcCols;
+		dataOffset[row+aperature] = maskOffset[row+aperature];
+	    }
+	    for(j = aperature; j < srcCols-aperature; ++j){
+		/*
+		// get 7x7 segment and make sure have 100% mask coverage
+		*/
+		count = 0;
+		for(row = -aperature; row <= aperature; ++row){
+		    rowNumber = (row+aperature)*kernelSize;
+		    for(column = -aperature; column <= aperature; ++column){
+			if(MaskImage[maskOffset[row+aperature]+j+column]){
+			    myImage[rowNumber+column+aperature] = sourceImage[dataOffset[row+aperature]+j+column];
+			    ++count;
+			}
+		    }
+		}
+		if(count == fullMask){
+		    /*
+		    // 100% mask coverage. now do the Law's texture filters
+		    */
+		    lawsLayer = 0;
+		    for(outerKernelNumber = 0; outerKernelNumber < lawsFilter.numberKernels; ++outerKernelNumber){
+			/*
+			// outer loop pulls the i'th kernel. kernel 0 is the LP kernel
+			// the outer loop is the iso-kernel
+			*/
+			rowFilter = &lawsFilter.lawsKernel[outerKernelNumber][0];
+			colFilter = &lawsFilter.lawsKernel[outerKernelNumber][0];
+			filterResult1 = lawsConvolution(myImage, rowFilter, colFilter, kernelSize);
+			/* lawsLayer 0 is the LP and needs to be used to scale. */
+			if(outerKernelNumber){
+			    lawsImage[lawsLayer*layerStep + i*srcCols + j] = (float)2.0 * filterResult1;
+			}
+			else{
+			    lawsLL = filterResult1;
+			    lawsLL = (float)2.0 * filterResult1;
+			    lawsImage[lawsLayer*layerStep + i*srcCols + j] = (float)2.0 * filterResult1;
+			}
+			++lawsLayer;
+			/*
+			// now do the inner loop and get the column filters for the other laws kernels
+			*/
+			for(innerKernelNumber = outerKernelNumber+1;
+			                        innerKernelNumber < lawsFilter.numberKernels;
+			                        ++innerKernelNumber){
+			    colFilter = &lawsFilter.lawsKernel[innerKernelNumber][0];
+			    filterResult1 = lawsConvolution(myImage, rowFilter, colFilter, kernelSize);
+			    filterResult2 = lawsConvolution(myImage, colFilter, rowFilter, kernelSize);
+			    lawsImage[lawsLayer*layerStep + i*srcCols + j] = filterResult1 + filterResult2;
+			    ++lawsLayer;
+			}
+		    }
+		}
+	    }
+	}
+
+	return;
+
+}
+
+
+int NI_LawsTexture(int num, int rows, int cols, double *src_image, unsigned short *mask, 
+		   float *lawsImage, LawsFilter7 lawsFilter){
+
+	int status;
+	int number_kernels;
+	int kernel_size;
+	int filters;
+        int aperature;
+        number_kernels = lawsFilter.numberKernels;
+        kernel_size = lawsFilter.kernelLength;
+        filters = lawsFilter.numberFilterLayers;
+	aperature = (kernel_size-1)/2;
+
+	computeLaws(lawsFilter, aperature, rows, cols, mask, lawsImage, src_image);
+
+	status = 1;
+
+	return status;
+
+}
+
+
+int NI_RoiCoOccurence(int samples, int rows, int cols, unsigned short *labelImage,
+	              unsigned short *rawImage, int *cocMatrix, int distance, int orientation){ 
+
+	int i, j;
+	int offset;
+	int d_row;
+	int d_col;
+	int status;
+	int start_row;
+	int stop_row;
+	int start_col;
+	int stop_col;
+	int mask;
+	int pixel;
+	int d_mask_value;
+	int d_pixel_value;
+
+	/* built around 8 bit histograms */
+
+	offset = 0;
+	if(orientation == 90){
+	    start_row = 0;
+	    stop_row  = rows;
+	    start_col = 0;
+	    stop_col  = cols-distance;
+	    d_row     = 0;
+	    d_col     = distance;
+	}
+	else if(orientation == 180){
+	    start_row = 0;
+	    stop_row  = rows-distance;
+	    start_col = 0;
+	    stop_col  = cols;
+	    d_row     = cols*distance;
+	    d_col     = 0;
+	}
+	else if(orientation == 45){
+	    start_row = 0;
+	    stop_row  = rows-distance;
+	    start_col = distance;
+	    stop_col  = cols;
+	    d_row     = cols*distance;
+	    d_col     = -distance;
+	}
+	else if(orientation == 135){
+	    start_row = 0;
+	    stop_row  = rows-distance;
+	    start_col = 0;
+	    stop_col  = cols-distance;
+	    d_row     = cols*distance;
+	    d_col     = distance;
+	}
+
+	for(i = start_row; i < stop_row; ++i){
+	    for(j = start_col; j < stop_col; ++j){
+		mask = labelImage[offset+j];
+		if(mask){
+		    /* d rows away from current row */
+		    pixel = rawImage[offset+j];
+		    d_mask_value = labelImage[offset+d_row+j+d_col];
+		    if(d_mask_value){
+		        /* over the mask */
+		        d_pixel_value = rawImage[offset+d_row+j+d_col];
+			/* update the 2D joint histograms */
+	                ++cocMatrix[d_pixel_value*256+pixel];
+	                ++cocMatrix[d_pixel_value+pixel*256];
+		    }
+		}
+	    }
+	    offset += cols;
+	}
+
+	status = 1;
+
+	return(status);
+
+}
+
+int NI_GrowRegion2D(int rows, int cols, double *rawimage, unsigned short *label,
+                    objStruct *expanded_ROI, objStruct *newgrow_ROI, double low_threshold,
+                    double high_threshold, int Label, int N_connectivity){
+
+	int i, j, p, m;
+	int offset;
+	int offsetM, offsetP;
+	int status;
+	int T[8], count;
+	int LowX;
+	int LowY;
+	int HighX;
+	int HighY;
+	double value;
+	bool change;
+
+	while(1){
+	    change = FALSE;
+	    for(i = 1; i < rows-1; ++i){
+	        offset  = i * cols;
+	        offsetM = offset - cols;
+	        offsetP = offset + cols;
+	        for(j = 1; j < cols-1; ++j){
+	            m = label[offset+j];
+		    if(!m){
+			/* un-labeled pixel */
+	                value = rawimage[offset+j];
+	                if((value > low_threshold) && (value < high_threshold)){
+			    /* check for N-connectivity */
+			    T[0] = label[offset+j+1];
+			    T[1] = label[offsetM+j+1];
+			    T[2] = label[offsetM+j];
+			    T[3] = label[offsetM+j-1];
+			    T[4] = label[offset+j-1];
+			    T[5] = label[offsetP+j-1];
+			    T[6] = label[offsetP+j];
+			    T[7] = label[offsetP+j+1];
+			    count = 0;
+	        	    for(p = 0; p < 8; ++p){
+			        if(T[p] == Label){
+			            ++count;
+			        }
+			    }	
+			    if(count > N_connectivity){
+	            		label[offset+j] = Label;
+	    			change = TRUE;
+			    } 
+			}	
+		    }
+	        }
+	    }
+	    if(!change) break;
+	}
+
+	/* get new bounding box */
+	newgrow_ROI->Left   = expanded_ROI->Left + LowX;
+	newgrow_ROI->Right  = newgrow_ROI->Left + (HighX-LowX);
+	newgrow_ROI->Bottom = expanded_ROI->Bottom + LowY;
+	newgrow_ROI->Top    = expanded_ROI->Bottom + (HighY-LowY);
+	newgrow_ROI->Mass   = count;
+
+	status = 1;
+
+	return(status);
+
+}
+
+int NI_GrowRegion3D(int layers, int rows, int cols, double *rawimage, unsigned short *label,
+                    objStruct *expanded_ROI, objStruct *newgrow_ROI, double low_threshold,
+		    double high_threshold, int Label, int N_connectivity){
+
+	int i, j, k, m, p;
+	int offset;
+	int ptr;
+	int lOffset,  rOffset;
+	int lOffsetP, lOffsetN;
+	int rOffsetP, rOffsetN;
+	int layerSize;
+	int status;
+	int T[26], count;
+	int LowX;
+	int LowY;
+	int LowZ;
+	int HighX;
+	int HighY;
+	int HighZ;
+	float centerX;
+	float centerY;
+	float centerZ;
+	double value;
+	bool change;
+
+	layerSize = rows * cols;
+	while(1){
+	    change = FALSE;
+	    for(i = 1; i < layers-1; ++i){
+	        lOffset  = i * layerSize;
+	        lOffsetP = lOffset+layerSize;
+	        lOffsetN = lOffset-layerSize;
+	        for(j = 1; j < rows-1; ++j){
+		    rOffset = j * cols;
+		    rOffsetP = rOffset+cols;
+		    rOffsetN = rOffset-cols;
+		    for(k = 1; k < cols-1; ++k){
+		        m = label[lOffset+rOffset+k];
+		        if(!m){
+			    /* un-labeled voxel */
+	                    value = rawimage[lOffset+rOffset+k];
+	                    if((value > low_threshold) && (value < high_threshold)){
+			        /* check for N-connectivity */
+			        T[0]  = label[lOffset+rOffset+k+1];
+			        T[1]  = label[lOffset+rOffsetN+k+1];
+			        T[2]  = label[lOffset+rOffsetN+k];
+			        T[3]  = label[lOffset+rOffsetN+k-1];
+			        T[4]  = label[lOffset+rOffset+k-1];
+			        T[5]  = label[lOffset+rOffsetP+k-1];
+			        T[6]  = label[lOffset+rOffsetP+k];
+			        T[7]  = label[lOffset+rOffsetP+k+1];
+
+			        T[8]  = label[lOffsetN+rOffset+k];
+			        T[9]  = label[lOffsetN+rOffset+k+1];
+			        T[10] = label[lOffsetN+rOffsetN+k+1];
+			        T[11] = label[lOffsetN+rOffsetN+k];
+			        T[12] = label[lOffsetN+rOffsetN+k-1];
+			        T[13] = label[lOffsetN+rOffset+k-1];
+			        T[14] = label[lOffsetN+rOffsetP+k-1];
+			        T[15] = label[lOffsetN+rOffsetP+k];
+			        T[16] = label[lOffsetN+rOffsetP+k+1];
+
+			        T[17] = label[lOffsetP+rOffset+k];
+			        T[18] = label[lOffsetP+rOffset+k+1];
+			        T[19] = label[lOffsetP+rOffsetN+k+1];
+			        T[20] = label[lOffsetP+rOffsetN+k];
+			        T[21] = label[lOffsetP+rOffsetN+k-1];
+			        T[22] = label[lOffsetP+rOffset+k-1];
+			        T[23] = label[lOffsetP+rOffsetP+k-1];
+			        T[24] = label[lOffsetP+rOffsetP+k];
+			        T[25] = label[lOffsetP+rOffsetP+k+1];
+
+			        count = 0;
+	        	        for(p = 0; p < 26; ++p){
+			            if(T[p] == Label){
+			                ++count;
+				    }
+			        }	
+			        if(count > N_connectivity){
+		        	    label[lOffset+rOffset+k]= Label;
+	    			    change = TRUE;
+			        } 
+			    } 
+		        }
+		    }
+	        }
+	    }
+	    if(!change) break;
+	}
+
+        LowX       = 32767;
+	LowY       = 32767;
+	LowZ       = 32767;
+	HighX      = 0;
+	HighY      = 0;
+	HighZ      = 0;
+	count      = 0;
+	centerX    = (float)0.0;
+	centerY    = (float)0.0;
+	centerZ    = (float)0.0;
+	ptr        = 0;
+	count      = 0;
+	for(i = 0; i < layers; ++i){
+	    for(j = 0; j < rows; ++j){
+	        for(k = 0; k < cols; ++k){
+		    m = label[ptr++];
+		    if(m == Label){
+		        if(i < LowZ)   LowZ = i;
+		        if(j < LowY)   LowY = j;
+		        if(k < LowX)   LowX = k;
+		        if(i > HighZ) HighZ = i;
+		        if(j > HighY) HighY = j;
+		        if(k > HighX) HighX = k;
+	    	        centerX += (float)k;
+	    	        centerY += (float)j;
+	    	        centerZ += (float)i;
+	    	        ++count;
+		    }
+		}
+	    }
+	}
+
+	newgrow_ROI->Left   = expanded_ROI->Left + LowX;
+	newgrow_ROI->Right  = newgrow_ROI->Left + (HighX-LowX);
+	newgrow_ROI->Bottom = expanded_ROI->Bottom + LowY;
+	newgrow_ROI->Top    = newgrow_ROI->Bottom + (HighY-LowY);
+	newgrow_ROI->Front  = expanded_ROI->Front + LowZ;
+	newgrow_ROI->Back   = expanded_ROI->Front + (HighZ-LowZ);
+	newgrow_ROI->Mass   = count;
+
+	status = 1;
+
+	return(status);
+
+}
+
+

Added: branches/Interpolate1D/ndimage/segment/ndImage_Segmenter_structs.h
===================================================================
--- branches/Interpolate1D/ndimage/segment/ndImage_Segmenter_structs.h	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage/segment/ndImage_Segmenter_structs.h	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,29 @@
+#ifndef V1_STRUCTSH
+#define V1_STRUCTSH
+
+#define bool unsigned char
+
+typedef struct{
+    int numberKernels;
+    int kernelLength;
+    int numberFilterLayers;
+    float lawsKernel[6][7];
+    char name[7];
+}LawsFilter7;
+
+typedef struct{
+    // filled in GetObjectStats 
+    int Left;
+    int Right;
+    int Top;
+    int Bottom;
+    int Front;
+    int Back;
+    int Label;
+    int Mass;
+    float cX;
+    float cY;
+    float cZ;
+}objStruct;
+
+#endif

Added: branches/Interpolate1D/ndimage_wrapper.py
===================================================================
--- branches/Interpolate1D/ndimage_wrapper.py	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/ndimage_wrapper.py	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,146 @@
+""" ND Interpolation wrapping using code from NDImage"""
+
+from numpy import array, arange, NaN
+import numpy as np
+import _nd_image
+
+class InterpolateNd:
+    def __init__(self, data, starting_coords =None, spacings = None, 
+                        order=3, out=NaN):
+        """ data = array or list of lists
+            starting_coords = None, list, 1D array or 2D (nx1) array
+            spacings = None, list, 1D array or 2D (nx1) array
+            out = string in 'nearest', 'wrap', 'reflect', 'mirror', 'constant'
+                        or just NaN
+        """
+        
+        # FIXME : include spline filtering
+        
+        if order < 0 or order > 5:
+            raise RuntimeError, 'spline order not supported'
+        
+        # checking format of input
+        data = array(data)
+        
+        # for proper processing later, starting_coords and spacings must be of shape (data.ndim, 1)
+        if starting_coords == None:
+            starting_coords = np.zeros(( data.ndim, 1 ))
+        else:
+            starting_coords = array(starting_coords)
+            assert starting_coords.size == data.ndim, "There must be one element of \
+                            starting_coords per data dimension.  Size mismatch."
+            starting_coords = reshape(starting_coords, (data.ndim, 1))
+        if spacings == None:
+            spacings = np.zeros(( data.ndim, 1 ))
+        else:
+            spacings = array(spacings)
+            assert starting_coords.size == data.ndim, "There must be one element of \
+                            starting_coords per data dimension"
+            spacings = reshape(spacings, (data.ndim, 1))
+        
+        # storing relevant data
+        self._data_array = data
+        self.ndim = data.ndim
+        self._shape = np.shape(data)
+        self._spacings = spacings
+        self._min_coords = starting_coords
+        self._max_coords = self._min_coords + self._shape*self._spacings
+        self.out = out
+        self.order = order
+        
+    def __call__(self, coordinates):
+        """ coordinates is an n x L array, where n is the dimensionality of the data
+            and L is number of points.  That is, each column of coordinates
+            indicates a point at which to interpolate.
+        """
+        
+        # format checking
+        coordinates = array(coordinates)
+        if coordinates.ndim == 1: # passed in a single point
+            coordinates = np.reshape(coordinates, ( self.ndim, 1))
+        assert coordinates.ndim == 2, "Coordinates must be 1 or 2 dimensional"
+        n, num_points = coordinates.shape
+        assert n == self.ndim, "The first dimension of the input \
+                must be as long as the dimensionality of the space"
+        
+        # converting from points in ND space to array indices
+        indices = (coordinates - self._min_coords)/self._spacings
+        
+        if self.out in ['nearest', 'wrap', 'reflect', 'mirror', 'constant']:
+            # out of bounds can be performed by _interpolate_array_entry
+            result = self._interpolate_array_entry(self._data_array, indices, self.order, out = self.out)
+        else:
+            # need to return NaN when entry is out of bounds
+            in_bounds_mask = self._index_in_bounds(indices)
+            in_bounds = indices[:, in_bounds_mask]
+            out_bounds = indices[:, ~in_bounds_mask]
+            
+            result = np.zeros(num_points)
+            result[in_bounds_mask] = \
+                self._interpolate_array_entry(self._data_array, indices[:,in_bounds_mask], self.order)
+            result[~in_bounds_mask] = NaN
+            
+        return result
+        
+    
+    def _interpolate_array_entry(self, data_array, indices, order, out='nearest'):
+        """ indices is nxL matrix, where n is data_array.ndim
+            returns array of length L giving interpolated entries.
+        """
+        
+        extrap_code_register = { 'nearest':0,
+                                        'wrap': 1,
+                                        'reflect':2,
+                                        'mirror':3,
+                                        'constant':4,
+                                        }
+        
+        n, L = np.shape(indices)
+        
+        output = np.zeros( L , dtype=np.float64 ) # place to store the data
+
+        # geometric transform takes data_array, interpolates its values at indices, and
+        # stores those values in output.  Other parameters give details of interpolation method.
+        _nd_image.geometric_transform(data_array, None, indices, None, None, \
+               output, order, extrap_code_register[out], 0.0, None, None)
+               
+        return output
+        
+    def _index_in_bounds(self, indices):
+        """ return an array of bools saying which
+            points are in interpolation bounds
+        """
+        shape_as_column_vec = np.reshape(self._shape, (self.ndim, 1))
+        
+        # entry is 1 if that coordinate of a point is in its bounds
+        index_in_bounds = (0 <= indices) & \
+                                    (indices <= shape_as_column_vec)
+        
+        # for each point, number of coordinates that are in bounds
+        num_indices_in_bounds = np.sum(index_in_bounds, axis=0)
+        
+        # True if each coordinate for the point is in bounds
+        return num_indices_in_bounds == self.ndim
+        
+    def _coord_in_bounds(self, coordinates):
+        """ return an array of bools saying which
+            points are in interpolation bounds
+        """
+        # entry is 1 if that coordinate of a point is in its bounds
+        coord_in_bounds = (self._min_coords <= coordinates) & \
+                                    (coordinates <= self._max_coords)
+        
+        # for each point, number of coordinates that are in bounds
+        num_coords_in_bounds = np.sum(coord_in_bounds, axis=0)
+        
+        # True if each coordinate for the point is in bounds
+        return num_coords_in_bounds == self.ndim
+        
+    
+        
+    
+        
+        
+        
+    
+    
\ No newline at end of file


Property changes on: branches/Interpolate1D/ndimage_wrapper.py
___________________________________________________________________
Name: svn:executable
   + *

Modified: branches/Interpolate1D/setup.py
===================================================================
--- branches/Interpolate1D/setup.py	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/setup.py	2008-08-05 19:07:52 UTC (rev 4601)
@@ -1,5 +1,7 @@
 #!/usr/bin/env python
 
+from numpy import get_include
+
 import os
 from os.path import join
 
@@ -11,23 +13,35 @@
 
     # C++ extension for several basic interpolation types
     config.add_extension('_interpolate',
-                         ['_interpolate.cpp'],
-                         include_dirs = ['.'],
-                         depends = ['interpolate.h'])
+                        ['_interpolate.cpp'],
+                        include_dirs = ['.'],
+                        depends = ['interpolate.h'])
 
     # used by dfitpack extension
     config.add_library('_fitpack',
-                       sources=[join('fitpack', '*.f')],
+                        sources=[join('fitpack', '*.f')],
                       )
 
     # Fortran routines (collectively "FITPACK" for spline interpolation)
     config.add_extension('_dfitpack',
-                         sources=['_fitpack.pyf'],
-                         libraries=['_fitpack'],
+                        sources=['_fitpack.pyf'],
+                        libraries=['_fitpack'],
                         )
                         
+    # ND Image routines for ND interpolation
+    config.add_extension('_nd_image',
+                        sources=["ndimage/nd_image.c",
+                                    "ndimage/ni_filters.c",
+                                    "ndimage/ni_fourier.c",
+                                    "ndimage/ni_interpolation.c",
+                                    "ndimage/ni_measure.c",
+                                    "ndimage/ni_morphology.c",
+                                    "ndimage/ni_support.c"],
+                        include_dirs=['ndimage']+[get_include()],
+                        )
+                        
     # FIXME : add documentation files
-    # config.add_data_dir(
+    config.add_data_dir('docs')
 
     return config
 

Added: branches/Interpolate1D/tests/test_ndimage.py
===================================================================
--- branches/Interpolate1D/tests/test_ndimage.py	2008-08-04 20:27:24 UTC (rev 4600)
+++ branches/Interpolate1D/tests/test_ndimage.py	2008-08-05 19:07:52 UTC (rev 4601)
@@ -0,0 +1,56 @@
+""" module for testing ndimage_wrapper
+"""
+
+# hack to test on Field's computer
+import sys
+sys.path.append('c:/home/python/Interpolate1d')
+
+import unittest
+import time
+from numpy import arange, allclose, ones
+import numpy as np
+import ndimage_wrapper as nd
+
+class Test (unittest.TestCase):
+    
+    def assertAllclose(self, x, y):
+        self.assert_(np.allclose(x, y))
+    
+    def test_linear(self):
+        boring_data = np.ones((5,5,5))
+        interp = nd.InterpolateNd(boring_data, order = 1)
+        self.assertAllclose( interp(np.array([[2.3], [1.0], [3.9]])) , 1.0 )
+        
+    def test_data_is_list(self):
+        boring_data = [ [1.0, 1.0, 1.0],
+                              [1.0, 1.0, 1.0],
+                              [1.0, 1.0, 1.0]]
+        interp = nd.InterpolateNd(boring_data, order = 1)
+        self.assertAllclose( interp(np.array([[1.3], [1.0]])) , 1.0 )
+        
+    def test_coords_is_1d(self):
+        boring_data = np.ones((5,5,5))
+        interp = nd.InterpolateNd(boring_data, order = 1)
+        self.assertAllclose( interp(np.array([2.3, 1.0, 3.9])) , 1.0 )
+        
+    def test_coords_is_list(self):
+        boring_data = np.ones((5,5,5))
+        interp = nd.InterpolateNd(boring_data, order = 1)
+        self.assertAllclose( interp([2.3, 1.0, 3.9]) , 1.0 )
+        
+    def runTest(self):
+        test_list = [method_name for method_name in dir(self) if method_name.find('test')==0]
+        for test_name in test_list:
+            exec("self.%s()" % test_name)
+            
+    def test_order2(self):
+        boring_data = np.ones((5,5,5))
+        interp = nd.InterpolateNd(boring_data, order = 2)
+        self.assertAllclose( interp(np.array([[2.3], [1.0], [3.9]])) , 1.0 )
+        
+    def test_out(self):
+        pass
+        
+        
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file




More information about the Scipy-svn mailing list