[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, ¶meters, &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,
+ ¢er_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