[Scipy-svn] r4634 - in trunk/scipy/ndimage/src: . register segment
scipy-svn at scipy.org
scipy-svn at scipy.org
Sat Aug 9 15:29:49 EDT 2008
Author: cdavid
Date: 2008-08-09 14:29:36 -0500 (Sat, 09 Aug 2008)
New Revision: 4634
Modified:
trunk/scipy/ndimage/src/nd_image.c
trunk/scipy/ndimage/src/nd_image.h
trunk/scipy/ndimage/src/ni_filters.c
trunk/scipy/ndimage/src/ni_filters.h
trunk/scipy/ndimage/src/ni_fourier.c
trunk/scipy/ndimage/src/ni_fourier.h
trunk/scipy/ndimage/src/ni_interpolation.c
trunk/scipy/ndimage/src/ni_interpolation.h
trunk/scipy/ndimage/src/ni_measure.c
trunk/scipy/ndimage/src/ni_measure.h
trunk/scipy/ndimage/src/ni_morphology.c
trunk/scipy/ndimage/src/ni_morphology.h
trunk/scipy/ndimage/src/ni_support.c
trunk/scipy/ndimage/src/ni_support.h
trunk/scipy/ndimage/src/register/Register_EXT.c
trunk/scipy/ndimage/src/register/Register_IMPL.c
trunk/scipy/ndimage/src/segment/Segmenter_EXT.c
trunk/scipy/ndimage/src/segment/Segmenter_IMPL.c
trunk/scipy/ndimage/src/segment/ndImage_Segmenter_structs.h
Log:
Use unix endline in ndimage (windows EOL break some unix compilers.).
Modified: trunk/scipy/ndimage/src/nd_image.c
===================================================================
--- trunk/scipy/ndimage/src/nd_image.c 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/nd_image.c 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,1320 +1,1320 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define ND_IMPORT_ARRAY
-#include "nd_image.h"
-#undef ND_IMPORT_ARRAY
-#include "ni_support.h"
-#include "ni_filters.h"
-#include "ni_fourier.h"
-#include "ni_morphology.h"
-#include "ni_interpolation.h"
-#include "ni_measure.h"
-
-typedef struct {
- PyObject *function;
- PyObject *extra_arguments;
- PyObject *extra_keywords;
-} NI_PythonCallbackData;
-
-/* Convert an input array of any type, not necessarily contiguous */
-static int
-NI_ObjectToInputArray(PyObject *object, PyArrayObject **array)
-{
- *array = NA_InputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
- return *array ? 1 : 0;
-}
-
-/* Convert an input array of any type, not necessarily contiguous */
-static int
-NI_ObjectToOptionalInputArray(PyObject *object, PyArrayObject **array)
-{
- if (object == Py_None) {
- *array = NULL;
- return 1;
- } else {
- *array = NA_InputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
- return *array ? 1 : 0;
- }
-}
-
-/* Convert an output array of any type, not necessarily contiguous */
-static int
-NI_ObjectToOutputArray(PyObject *object, PyArrayObject **array)
-{
- *array = NA_OutputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
- return *array ? 1 : 0;
-}
-
-/* Convert an output array of any type, not necessarily contiguous */
-static int
-NI_ObjectToOptionalOutputArray(PyObject *object, PyArrayObject **array)
-{
- if (object == Py_None) {
- *array = NULL;
- return 1;
- } else {
- *array = NA_OutputArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
- return *array ? 1 : 0;
- }
-}
-
-/* Convert an input/output array of any type, not necessarily contiguous */
-static int
-NI_ObjectToIoArray(PyObject *object, PyArrayObject **array)
-{
- *array = NA_IoArray(object, tAny, NPY_ALIGNED|NPY_NOTSWAPPED);
- return *array ? 1 : 0;
-}
-
-/* Convert an Long sequence */
-static maybelong
-NI_ObjectToLongSequenceAndLength(PyObject *object, maybelong **sequence)
-{
- long *pa, ii;
- PyArrayObject *array = NA_InputArray(object, PyArray_LONG, NPY_CARRAY);
- maybelong length = PyArray_SIZE(array);
-
- *sequence = (maybelong*)malloc(length * sizeof(maybelong));
- if (!*sequence) {
- PyErr_NoMemory();
- Py_XDECREF(array);
- return -1;
- }
- pa = (long*)PyArray_DATA(array);
- for(ii = 0; ii < length; ii++)
- (*sequence)[ii] = pa[ii];
- Py_XDECREF(array);
- return length;
-}
-
-static int
-NI_ObjectToLongSequence(PyObject *object, maybelong **sequence)
-{
- return NI_ObjectToLongSequenceAndLength(object, sequence) >= 0;
-}
-
-/*********************************************************************/
-/* wrapper functions: */
-/*********************************************************************/
-
-static PyObject *Py_Correlate1D(PyObject *obj, PyObject *args)
-{
- PyArrayObject *input = NULL, *output = NULL, *weights = NULL;
- int axis, mode;
- long origin;
- double cval;
-
- if (!PyArg_ParseTuple(args, "O&O&iO&idl", NI_ObjectToInputArray, &input,
- NI_ObjectToInputArray, &weights, &axis,
- NI_ObjectToOutputArray, &output, &mode, &cval, &origin))
- goto exit;
- if (!NI_Correlate1D(input, weights, axis, output,
- (NI_ExtendMode)mode, cval, origin))
- goto exit;
-exit:
- Py_XDECREF(input);
- Py_XDECREF(weights);
- Py_XDECREF(output);
- return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_Correlate(PyObject *obj, PyObject *args)
-{
- PyArrayObject *input = NULL, *output = NULL, *weights = NULL;
- maybelong *origin = NULL;
- int mode;
- double cval;
-
- if (!PyArg_ParseTuple(args, "O&O&O&idO&", NI_ObjectToInputArray, &input,
- NI_ObjectToInputArray, &weights, NI_ObjectToOutputArray, &output,
- &mode, &cval, NI_ObjectToLongSequence, &origin))
- goto exit;
- if (!NI_Correlate(input, weights, output, (NI_ExtendMode)mode, cval,
- origin))
- goto exit;
-exit:
- Py_XDECREF(input);
- Py_XDECREF(weights);
- Py_XDECREF(output);
- if (origin)
- free(origin);
- return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_UniformFilter1D(PyObject *obj, PyObject *args)
-{
- PyArrayObject *input = NULL, *output = NULL;
- int axis, mode;
- long filter_size, origin;
- double cval;
-
- if (!PyArg_ParseTuple(args, "O&liO&idl", NI_ObjectToInputArray, &input,
- &filter_size, &axis, NI_ObjectToOutputArray, &output,
- &mode, &cval, &origin))
- goto exit;
- if (!NI_UniformFilter1D(input, filter_size, axis, output,
- (NI_ExtendMode)mode, cval, origin))
- goto exit;
-exit:
- Py_XDECREF(input);
- Py_XDECREF(output);
- return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_MinOrMaxFilter1D(PyObject *obj, PyObject *args)
-{
- PyArrayObject *input = NULL, *output = NULL;
- int axis, mode, minimum;
- long filter_size, origin;
- double cval;
-
- if (!PyArg_ParseTuple(args, "O&liO&idli", NI_ObjectToInputArray, &input,
- &filter_size, &axis, NI_ObjectToOutputArray, &output,
- &mode, &cval, &origin, &minimum))
- goto exit;
- if (!NI_MinOrMaxFilter1D(input, filter_size, axis, output,
- (NI_ExtendMode)mode, cval, origin, minimum))
- goto exit;
-exit:
- Py_XDECREF(input);
- Py_XDECREF(output);
- return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_MinOrMaxFilter(PyObject *obj, PyObject *args)
-{
- PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
- PyArrayObject *structure = NULL;
- maybelong *origin = NULL;
- int mode, minimum;
- double cval;
-
- if (!PyArg_ParseTuple(args, "O&O&O&O&idO&i", NI_ObjectToInputArray,
- &input, NI_ObjectToInputArray, &footprint,
- NI_ObjectToOptionalInputArray, &structure,
- NI_ObjectToOutputArray, &output, &mode, &cval,
- NI_ObjectToLongSequence, &origin, &minimum))
- goto exit;
- if (!NI_MinOrMaxFilter(input, footprint, structure, output,
- (NI_ExtendMode)mode, cval, origin, minimum))
- goto exit;
-exit:
- Py_XDECREF(input);
- Py_XDECREF(footprint);
- Py_XDECREF(structure);
- Py_XDECREF(output);
- if (origin)
- free(origin);
- return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_RankFilter(PyObject *obj, PyObject *args)
-{
- PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
- maybelong *origin = NULL;
- int mode, rank;
- double cval;
-
- if (!PyArg_ParseTuple(args, "O&iO&O&idO&", NI_ObjectToInputArray,
- &input, &rank, NI_ObjectToInputArray, &footprint,
- NI_ObjectToOutputArray, &output, &mode, &cval,
- NI_ObjectToLongSequence, &origin))
- goto exit;
- if (!NI_RankFilter(input, rank, footprint, output, (NI_ExtendMode)mode,
- cval, origin))
- goto exit;
-exit:
- Py_XDECREF(input);
- Py_XDECREF(footprint);
- Py_XDECREF(output);
- if (origin)
- free(origin);
- return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static int Py_Filter1DFunc(double *iline, maybelong ilen,
- double *oline, maybelong olen, void *data)
-{
- PyArrayObject *py_ibuffer = NULL, *py_obuffer = NULL;
- PyObject *rv = NULL, *args = NULL, *tmp = NULL;
- maybelong ii;
- double *po = NULL;
- NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
-
- py_ibuffer = NA_NewArray(iline, PyArray_DOUBLE, 1, &ilen);
- py_obuffer = NA_NewArray(NULL, PyArray_DOUBLE, 1, &olen);
- if (!py_ibuffer || !py_obuffer)
- goto exit;
- tmp = Py_BuildValue("(OO)", py_ibuffer, py_obuffer);
- if (!tmp)
- goto exit;
- args = PySequence_Concat(tmp, cbdata->extra_arguments);
- if (!args)
- goto exit;
- rv = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
- if (!rv)
- goto exit;
- po = (double*)PyArray_DATA(py_obuffer);
- for(ii = 0; ii < olen; ii++)
- oline[ii] = po[ii];
-exit:
- Py_XDECREF(py_ibuffer);
- Py_XDECREF(py_obuffer);
- Py_XDECREF(rv);
- Py_XDECREF(args);
- Py_XDECREF(tmp);
- return PyErr_Occurred() ? 0 : 1;
-}
-
-static PyObject *Py_GenericFilter1D(PyObject *obj, PyObject *args)
-{
- PyArrayObject *input = NULL, *output = NULL;
- PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
- void *func = Py_Filter1DFunc, *data = NULL;
- NI_PythonCallbackData cbdata;
- int axis, mode;
- long origin, filter_size;
- double cval;
-
- if (!PyArg_ParseTuple(args, "O&OliO&idlOO", NI_ObjectToInputArray,
- &input, &fnc, &filter_size, &axis, NI_ObjectToOutputArray,
- &output, &mode, &cval, &origin, &extra_arguments, &extra_keywords))
- goto exit;
- if (!PyTuple_Check(extra_arguments)) {
- PyErr_SetString(PyExc_RuntimeError,
- "extra_arguments must be a tuple");
- goto exit;
- }
- if (!PyDict_Check(extra_keywords)) {
- PyErr_SetString(PyExc_RuntimeError,
- "extra_keywords must be a dictionary");
- goto exit;
- }
- if (PyCObject_Check(fnc)) {
- func = PyCObject_AsVoidPtr(fnc);
- data = PyCObject_GetDesc(fnc);
- } else if (PyCallable_Check(fnc)) {
- cbdata.function = fnc;
- cbdata.extra_arguments = extra_arguments;
- cbdata.extra_keywords = extra_keywords;
- data = (void*)&cbdata;
- } else {
- PyErr_SetString(PyExc_RuntimeError,
- "function parameter is not callable");
- goto exit;
- }
- if (!NI_GenericFilter1D(input, func, data, filter_size, axis, output,
- (NI_ExtendMode)mode, cval, origin))
- goto exit;
-exit:
- Py_XDECREF(input);
- Py_XDECREF(output);
- return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static int Py_FilterFunc(double *buffer, maybelong filter_size,
- double *output, void *data)
-{
- PyArrayObject *py_buffer = NULL;
- PyObject *rv = NULL, *args = NULL, *tmp = NULL;
- NI_PythonCallbackData *cbdata = (NI_PythonCallbackData*)data;
-
- py_buffer = NA_NewArray(buffer, PyArray_DOUBLE, 1, &filter_size);
- if (!py_buffer)
- goto exit;
- tmp = Py_BuildValue("(O)", py_buffer);
- if (!tmp)
- goto exit;
- args = PySequence_Concat(tmp, cbdata->extra_arguments);
- if (!args)
- goto exit;
- rv = PyObject_Call(cbdata->function, args, cbdata->extra_keywords);
- if (!rv)
- goto exit;
- *output = PyFloat_AsDouble(rv);
-exit:
- Py_XDECREF(py_buffer);
- Py_XDECREF(rv);
- Py_XDECREF(args);
- Py_XDECREF(tmp);
- return PyErr_Occurred() ? 0 : 1;
-}
-
-static PyObject *Py_GenericFilter(PyObject *obj, PyObject *args)
-{
- PyArrayObject *input = NULL, *output = NULL, *footprint = NULL;
- PyObject *fnc = NULL, *extra_arguments = NULL, *extra_keywords = NULL;
- void *func = Py_FilterFunc, *data = NULL;
- NI_PythonCallbackData cbdata;
- int mode;
- maybelong *origin = NULL;
- double cval;
-
- if (!PyArg_ParseTuple(args, "O&OO&O&idO&OO", NI_ObjectToInputArray,
- &input, &fnc, NI_ObjectToInputArray, &footprint,
- NI_ObjectToOutputArray, &output, &mode, &cval,
- NI_ObjectToLongSequence, &origin,
- &extra_arguments, &extra_keywords))
- goto exit;
- if (!PyTuple_Check(extra_arguments)) {
- PyErr_SetString(PyExc_RuntimeError,
- "extra_arguments must be a tuple");
- goto exit;
- }
- if (!PyDict_Check(extra_keywords)) {
- PyErr_SetString(PyExc_RuntimeError,
- "extra_keywords must be a dictionary");
- goto exit;
- }
- if (PyCObject_Check(fnc)) {
- func = PyCObject_AsVoidPtr(fnc);
- data = PyCObject_GetDesc(fnc);
- } else if (PyCallable_Check(fnc)) {
- cbdata.function = fnc;
- cbdata.extra_arguments = extra_arguments;
- cbdata.extra_keywords = extra_keywords;
- data = (void*)&cbdata;
- } else {
- PyErr_SetString(PyExc_RuntimeError,
- "function parameter is not callable");
- goto exit;
- }
- if (!NI_GenericFilter(input, func, data, footprint, output,
- (NI_ExtendMode)mode, cval, origin))
- goto exit;
-exit:
- Py_XDECREF(input);
- Py_XDECREF(output);
- Py_XDECREF(footprint);
- if (origin)
- free(origin);
- return PyErr_Occurred() ? NULL : Py_BuildValue("");
-}
-
-static PyObject *Py_FourierFilter(PyObject *obj, PyObject *args)
-{
- PyArrayObject *input = NULL, *output = NULL, *parameters = NULL;
- int axis, filter_type;
- long n;
-
- if (!PyArg_ParseTuple(args, "O&O&liO&i", NI_ObjectToInputArray, &input,
- NI_ObjectToInputArray, ¶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();
-}
+/* 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();
+}
Modified: trunk/scipy/ndimage/src/nd_image.h
===================================================================
--- trunk/scipy/ndimage/src/nd_image.h 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/nd_image.h 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,278 +1,278 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef ND_IMAGE_H
-#define ND_IMAGE_H
-
-#include "Python.h"
-
-#ifndef ND_IMPORT_ARRAY
-#define NO_IMPORT_ARRAY
-#endif
-
-#include <numpy/noprefix.h>
-#undef NO_IMPORT_ARRAY
-
-/* Eventually get rid of everything below this line */
-
-typedef enum
-{
- tAny=-1,
- tBool=PyArray_BOOL,
- tInt8=PyArray_INT8,
- tUInt8=PyArray_UINT8,
- tInt16=PyArray_INT16,
- tUInt16=PyArray_UINT16,
- tInt32=PyArray_INT32,
- tUInt32=PyArray_UINT32,
- tInt64=PyArray_INT64,
- tUInt64=PyArray_UINT64,
- tFloat32=PyArray_FLOAT32,
- tFloat64=PyArray_FLOAT64,
- tComplex64=PyArray_COMPLEX64,
- tComplex128=PyArray_COMPLEX128,
- tObject=PyArray_OBJECT, /* placeholder... does nothing */
- tMaxType=PyArray_NTYPES,
- tDefault=PyArray_FLOAT64,
- tLong=PyArray_LONG,
-} NumarrayType;
-
-#define NI_MAXDIM NPY_MAXDIMS
-
-typedef npy_intp maybelong;
-#define MAXDIM NPY_MAXDIMS
-
-#define HAS_UINT64 1
-
-
-
-#ifdef ND_IMPORT_ARRAY
-
-/* Numarray Helper Functions */
-
-static PyArrayObject*
-NA_InputArray(PyObject *a, NumarrayType t, int requires)
-{
- PyArray_Descr *descr;
- if (t == tAny) descr = NULL;
- else descr = PyArray_DescrFromType(t);
- return (PyArrayObject *) \
- PyArray_CheckFromAny(a, descr, 0, 0, requires, NULL);
-}
-
-/* satisfies ensures that 'a' meets a set of requirements and matches
-the specified type.
-*/
-static int
-satisfies(PyArrayObject *a, int requirements, NumarrayType t)
-{
- int type_ok = (a->descr->type_num == t) || (t == tAny);
-
- if (PyArray_ISCARRAY(a))
- return type_ok;
- if (PyArray_ISBYTESWAPPED(a) && (requirements & NPY_NOTSWAPPED))
- return 0;
- if (!PyArray_ISALIGNED(a) && (requirements & NPY_ALIGNED))
- return 0;
- if (!PyArray_ISCONTIGUOUS(a) && (requirements & NPY_CONTIGUOUS))
- return 0;
- if (!PyArray_ISWRITEABLE(a) && (requirements & NPY_WRITEABLE))
- return 0;
- if (requirements & NPY_ENSURECOPY)
- return 0;
- return type_ok;
-}
-
-static PyArrayObject *
-NA_OutputArray(PyObject *a, NumarrayType t, int requires)
-{
- PyArray_Descr *dtype;
- PyArrayObject *ret;
-
- if (!PyArray_Check(a) || !PyArray_ISWRITEABLE(a)) {
- PyErr_Format(PyExc_TypeError,
- "NA_OutputArray: only writeable arrays work for output.");
- return NULL;
- }
-
- if (satisfies((PyArrayObject *)a, requires, t)) {
- Py_INCREF(a);
- return (PyArrayObject *)a;
- }
- if (t == tAny) {
- dtype = PyArray_DESCR(a);
- Py_INCREF(dtype);
- }
- else {
- dtype = PyArray_DescrFromType(t);
- }
- ret = (PyArrayObject *)PyArray_Empty(PyArray_NDIM(a), PyArray_DIMS(a),
- dtype, 0);
- ret->flags |= NPY_UPDATEIFCOPY;
- ret->base = a;
- PyArray_FLAGS(a) &= ~NPY_WRITEABLE;
- Py_INCREF(a);
- return ret;
-}
-
-/* NA_IoArray is a combination of NA_InputArray and NA_OutputArray.
-
-Unlike NA_OutputArray, if a temporary is required it is initialized to a copy
-of the input array.
-
-Unlike NA_InputArray, deallocating any resulting temporary array results in a
-copy from the temporary back to the original.
-*/
-static PyArrayObject *
-NA_IoArray(PyObject *a, NumarrayType t, int requires)
-{
- PyArrayObject *shadow = NA_InputArray(a, t, requires | NPY_UPDATEIFCOPY );
-
- if (!shadow) return NULL;
-
- /* Guard against non-writable, but otherwise satisfying requires.
- In this case, shadow == a.
- */
- if (!PyArray_ISWRITEABLE(shadow)) {
- PyErr_Format(PyExc_TypeError,
- "NA_IoArray: I/O array must be writable array");
- PyArray_XDECREF_ERR(shadow);
- return NULL;
- }
-
- return shadow;
-}
-
-#define NUM_LITTLE_ENDIAN 0
-#define NUM_BIG_ENDIAN 1
-
-static int
-NA_ByteOrder(void)
-{
- unsigned long byteorder_test;
- byteorder_test = 1;
- if (*((char *) &byteorder_test))
- return NUM_LITTLE_ENDIAN;
- else
- return NUM_BIG_ENDIAN;
-}
-
-/* ignores bytestride */
-static PyArrayObject *
-NA_NewAllFromBuffer(int ndim, maybelong *shape, NumarrayType type,
- PyObject *bufferObject, maybelong byteoffset, maybelong bytestride,
- int byteorder, int aligned, int writeable)
-{
- PyArrayObject *self = NULL;
- PyArray_Descr *dtype;
-
- if (type == tAny)
- type = tDefault;
-
- dtype = PyArray_DescrFromType(type);
- if (dtype == NULL) return NULL;
-
- if (byteorder != NA_ByteOrder()) {
- PyArray_Descr *temp;
- temp = PyArray_DescrNewByteorder(dtype, PyArray_SWAP);
- Py_DECREF(dtype);
- if (temp == NULL) return NULL;
- dtype = temp;
- }
-
- if (bufferObject == Py_None || bufferObject == NULL) {
- self = (PyArrayObject *) \
- PyArray_NewFromDescr(&PyArray_Type, dtype,
- ndim, shape, NULL, NULL,
- 0, NULL);
- }
- else {
- npy_intp size = 1;
- int i;
- PyArrayObject *newself;
- PyArray_Dims newdims;
- for(i=0; i<ndim; i++) {
- size *= shape[i];
- }
- self = (PyArrayObject *) \
- PyArray_FromBuffer(bufferObject, dtype,
- size, byteoffset);
- if (self == NULL) return self;
- newdims.len = ndim;
- newdims.ptr = shape;
- newself = (PyArrayObject *) \
- PyArray_Newshape(self, &newdims, PyArray_CORDER);
- Py_DECREF(self);
- self = newself;
- }
-
- return self;
-}
-
-static PyArrayObject *
-NA_NewAll(int ndim, maybelong *shape, NumarrayType type,
- void *buffer, maybelong byteoffset, maybelong bytestride,
- int byteorder, int aligned, int writeable)
-{
- PyArrayObject *result = NA_NewAllFromBuffer(
- ndim, shape, type, Py_None,
- byteoffset, bytestride,
- byteorder, aligned, writeable);
- if (result) {
- if (!PyArray_Check((PyObject *) result)) {
- PyErr_Format( PyExc_TypeError,
- "NA_NewAll: non-NumArray result");
- result = NULL;
- } else {
- if (buffer) {
- memcpy(result->data, buffer, PyArray_NBYTES(result));
- } else {
- memset(result->data, 0, PyArray_NBYTES(result));
- }
- }
- }
- return result;
-}
-
-/* Create a new numarray which is initially a C_array, or which
-references a C_array: aligned, !byteswapped, contiguous, ...
-Call with buffer==NULL to allocate storage.
-*/
-static PyArrayObject *
-NA_NewArray(void *buffer, NumarrayType type, int ndim, maybelong *shape)
-{
- return (PyArrayObject *) NA_NewAll(ndim, shape, type, buffer, 0, 0,
- NA_ByteOrder(), 1, 1);
-}
-
-#endif /* ND_IMPORT_ARRAY */
-
-#endif /* ND_IMAGE_H */
+/* Copyright (C) 2003-2005 Peter J. Verveer
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ND_IMAGE_H
+#define ND_IMAGE_H
+
+#include "Python.h"
+
+#ifndef ND_IMPORT_ARRAY
+#define NO_IMPORT_ARRAY
+#endif
+
+#include <numpy/noprefix.h>
+#undef NO_IMPORT_ARRAY
+
+/* Eventually get rid of everything below this line */
+
+typedef enum
+{
+ tAny=-1,
+ tBool=PyArray_BOOL,
+ tInt8=PyArray_INT8,
+ tUInt8=PyArray_UINT8,
+ tInt16=PyArray_INT16,
+ tUInt16=PyArray_UINT16,
+ tInt32=PyArray_INT32,
+ tUInt32=PyArray_UINT32,
+ tInt64=PyArray_INT64,
+ tUInt64=PyArray_UINT64,
+ tFloat32=PyArray_FLOAT32,
+ tFloat64=PyArray_FLOAT64,
+ tComplex64=PyArray_COMPLEX64,
+ tComplex128=PyArray_COMPLEX128,
+ tObject=PyArray_OBJECT, /* placeholder... does nothing */
+ tMaxType=PyArray_NTYPES,
+ tDefault=PyArray_FLOAT64,
+ tLong=PyArray_LONG,
+} NumarrayType;
+
+#define NI_MAXDIM NPY_MAXDIMS
+
+typedef npy_intp maybelong;
+#define MAXDIM NPY_MAXDIMS
+
+#define HAS_UINT64 1
+
+
+
+#ifdef ND_IMPORT_ARRAY
+
+/* Numarray Helper Functions */
+
+static PyArrayObject*
+NA_InputArray(PyObject *a, NumarrayType t, int requires)
+{
+ PyArray_Descr *descr;
+ if (t == tAny) descr = NULL;
+ else descr = PyArray_DescrFromType(t);
+ return (PyArrayObject *) \
+ PyArray_CheckFromAny(a, descr, 0, 0, requires, NULL);
+}
+
+/* satisfies ensures that 'a' meets a set of requirements and matches
+the specified type.
+*/
+static int
+satisfies(PyArrayObject *a, int requirements, NumarrayType t)
+{
+ int type_ok = (a->descr->type_num == t) || (t == tAny);
+
+ if (PyArray_ISCARRAY(a))
+ return type_ok;
+ if (PyArray_ISBYTESWAPPED(a) && (requirements & NPY_NOTSWAPPED))
+ return 0;
+ if (!PyArray_ISALIGNED(a) && (requirements & NPY_ALIGNED))
+ return 0;
+ if (!PyArray_ISCONTIGUOUS(a) && (requirements & NPY_CONTIGUOUS))
+ return 0;
+ if (!PyArray_ISWRITEABLE(a) && (requirements & NPY_WRITEABLE))
+ return 0;
+ if (requirements & NPY_ENSURECOPY)
+ return 0;
+ return type_ok;
+}
+
+static PyArrayObject *
+NA_OutputArray(PyObject *a, NumarrayType t, int requires)
+{
+ PyArray_Descr *dtype;
+ PyArrayObject *ret;
+
+ if (!PyArray_Check(a) || !PyArray_ISWRITEABLE(a)) {
+ PyErr_Format(PyExc_TypeError,
+ "NA_OutputArray: only writeable arrays work for output.");
+ return NULL;
+ }
+
+ if (satisfies((PyArrayObject *)a, requires, t)) {
+ Py_INCREF(a);
+ return (PyArrayObject *)a;
+ }
+ if (t == tAny) {
+ dtype = PyArray_DESCR(a);
+ Py_INCREF(dtype);
+ }
+ else {
+ dtype = PyArray_DescrFromType(t);
+ }
+ ret = (PyArrayObject *)PyArray_Empty(PyArray_NDIM(a), PyArray_DIMS(a),
+ dtype, 0);
+ ret->flags |= NPY_UPDATEIFCOPY;
+ ret->base = a;
+ PyArray_FLAGS(a) &= ~NPY_WRITEABLE;
+ Py_INCREF(a);
+ return ret;
+}
+
+/* NA_IoArray is a combination of NA_InputArray and NA_OutputArray.
+
+Unlike NA_OutputArray, if a temporary is required it is initialized to a copy
+of the input array.
+
+Unlike NA_InputArray, deallocating any resulting temporary array results in a
+copy from the temporary back to the original.
+*/
+static PyArrayObject *
+NA_IoArray(PyObject *a, NumarrayType t, int requires)
+{
+ PyArrayObject *shadow = NA_InputArray(a, t, requires | NPY_UPDATEIFCOPY );
+
+ if (!shadow) return NULL;
+
+ /* Guard against non-writable, but otherwise satisfying requires.
+ In this case, shadow == a.
+ */
+ if (!PyArray_ISWRITEABLE(shadow)) {
+ PyErr_Format(PyExc_TypeError,
+ "NA_IoArray: I/O array must be writable array");
+ PyArray_XDECREF_ERR(shadow);
+ return NULL;
+ }
+
+ return shadow;
+}
+
+#define NUM_LITTLE_ENDIAN 0
+#define NUM_BIG_ENDIAN 1
+
+static int
+NA_ByteOrder(void)
+{
+ unsigned long byteorder_test;
+ byteorder_test = 1;
+ if (*((char *) &byteorder_test))
+ return NUM_LITTLE_ENDIAN;
+ else
+ return NUM_BIG_ENDIAN;
+}
+
+/* ignores bytestride */
+static PyArrayObject *
+NA_NewAllFromBuffer(int ndim, maybelong *shape, NumarrayType type,
+ PyObject *bufferObject, maybelong byteoffset, maybelong bytestride,
+ int byteorder, int aligned, int writeable)
+{
+ PyArrayObject *self = NULL;
+ PyArray_Descr *dtype;
+
+ if (type == tAny)
+ type = tDefault;
+
+ dtype = PyArray_DescrFromType(type);
+ if (dtype == NULL) return NULL;
+
+ if (byteorder != NA_ByteOrder()) {
+ PyArray_Descr *temp;
+ temp = PyArray_DescrNewByteorder(dtype, PyArray_SWAP);
+ Py_DECREF(dtype);
+ if (temp == NULL) return NULL;
+ dtype = temp;
+ }
+
+ if (bufferObject == Py_None || bufferObject == NULL) {
+ self = (PyArrayObject *) \
+ PyArray_NewFromDescr(&PyArray_Type, dtype,
+ ndim, shape, NULL, NULL,
+ 0, NULL);
+ }
+ else {
+ npy_intp size = 1;
+ int i;
+ PyArrayObject *newself;
+ PyArray_Dims newdims;
+ for(i=0; i<ndim; i++) {
+ size *= shape[i];
+ }
+ self = (PyArrayObject *) \
+ PyArray_FromBuffer(bufferObject, dtype,
+ size, byteoffset);
+ if (self == NULL) return self;
+ newdims.len = ndim;
+ newdims.ptr = shape;
+ newself = (PyArrayObject *) \
+ PyArray_Newshape(self, &newdims, PyArray_CORDER);
+ Py_DECREF(self);
+ self = newself;
+ }
+
+ return self;
+}
+
+static PyArrayObject *
+NA_NewAll(int ndim, maybelong *shape, NumarrayType type,
+ void *buffer, maybelong byteoffset, maybelong bytestride,
+ int byteorder, int aligned, int writeable)
+{
+ PyArrayObject *result = NA_NewAllFromBuffer(
+ ndim, shape, type, Py_None,
+ byteoffset, bytestride,
+ byteorder, aligned, writeable);
+ if (result) {
+ if (!PyArray_Check((PyObject *) result)) {
+ PyErr_Format( PyExc_TypeError,
+ "NA_NewAll: non-NumArray result");
+ result = NULL;
+ } else {
+ if (buffer) {
+ memcpy(result->data, buffer, PyArray_NBYTES(result));
+ } else {
+ memset(result->data, 0, PyArray_NBYTES(result));
+ }
+ }
+ }
+ return result;
+}
+
+/* Create a new numarray which is initially a C_array, or which
+references a C_array: aligned, !byteswapped, contiguous, ...
+Call with buffer==NULL to allocate storage.
+*/
+static PyArrayObject *
+NA_NewArray(void *buffer, NumarrayType type, int ndim, maybelong *shape)
+{
+ return (PyArrayObject *) NA_NewAll(ndim, shape, type, buffer, 0, 0,
+ NA_ByteOrder(), 1, 1);
+}
+
+#endif /* ND_IMPORT_ARRAY */
+
+#endif /* ND_IMAGE_H */
Modified: trunk/scipy/ndimage/src/ni_filters.c
===================================================================
--- trunk/scipy/ndimage/src/ni_filters.c 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/ni_filters.c 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,888 +1,888 @@
-/* Copyright (C) 2003-2005 Peter J. Verveer
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * 2. Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * 3. The name of the author may not be used to endorse or promote
- * products derived from this software without specific prior
- * written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
- * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
- * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "ni_support.h"
-#include "ni_filters.h"
-#include <stdlib.h>
-#include <math.h>
-
-#define BUFFER_SIZE 256000
-
-int NI_Correlate1D(PyArrayObject *input, PyArrayObject *weights,
- int axis, PyArrayObject *output, NI_ExtendMode mode,
- double cval, maybelong origin)
-{
- int symmetric = 0, ii, jj, more;
- maybelong ll, lines, length, size1, size2, filter_size;
- double *ibuffer = NULL, *obuffer = NULL;
- Float64 *fw;
- NI_LineBuffer iline_buffer, oline_buffer;
-
- /* test for symmetry or anti-symmetry: */
- filter_size = weights->dimensions[0];
- size1 = filter_size / 2;
- size2 = filter_size - size1 - 1;
- fw = (void *)PyArray_DATA(weights);
- if (filter_size & 0x1) {
- symmetric = 1;
- for(ii = 1; ii <= filter_size / 2; ii++) {
- if (fabs(fw[ii + size1] - fw[size1 - ii]) > DBL_EPSILON) {
- symmetric = 0;
- break;
- }
- }
- if (symmetric == 0) {
- symmetric = -1;
- for(ii = 1; ii <= filter_size / 2; ii++) {
- if (fabs(fw[size1 + ii] + fw[size1 - ii]) > DBL_EPSILON) {
- symmetric = 0;
- break;
- }
- }
- }
- }
- /* allocate and initialize the line buffers: */
- lines = -1;
- if (!NI_AllocateLineBuffer(input, axis, size1 + origin, size2 - origin,
- &lines, BUFFER_SIZE, &ibuffer))
- goto exit;
- if (!NI_AllocateLineBuffer(output, axis, 0, 0, &lines, BUFFER_SIZE,
- &obuffer))
- goto exit;
- if (!NI_InitLineBuffer(input, axis, size1 + origin, size2 - origin,
- lines, ibuffer, mode, cval, &iline_buffer))
- goto exit;
- if (!NI_InitLineBuffer(output, axis, 0, 0, lines, obuffer, mode, 0.0,
- &oline_buffer))
- goto exit;
- length = input->nd > 0 ? input->dimensions[axis] : 1;
- fw += size1;
- /* iterate over all the array lines: */
- do {
- /* copy lines from array to buffer: */
- if (!NI_ArrayToLineBuffer(&iline_buffer, &lines, &more))
- goto exit;
- /* iterate over the lines in the buffers: */
- for(ii = 0; ii < lines; ii++) {
- /* get lines: */
- double *iline = NI_GET_LINE(iline_buffer, ii) + size1;
- double *oline = NI_GET_LINE(oline_buffer, ii);
- /* the correlation calculation: */
- if (symmetric > 0) {
- for(ll = 0; ll < length; ll++) {
- oline[ll] = iline[0] * fw[0];
- for(jj = -size1 ; jj < 0; jj++)
- oline[ll] += (iline[jj] + iline[-jj]) * fw[jj];
- ++iline;
- }
- } else if (symmetric < 0) {
- for(ll = 0; ll < length; ll++) {
- oline[ll] = iline[0] * fw[0];
- for(jj = -size1 ; jj < 0; jj++)
- oline[ll] += (iline[jj] - iline[-jj]) * fw[jj];
- ++iline;
- }
- } else {
- for(ll = 0; ll < length; ll++) {
- oline[ll] = iline[size2] * fw[size2];
- for(jj = -size1; jj < size2; jj++)
- oline[ll] += iline[jj] * fw[jj];
- ++iline;
- }
- }
- }
- /* copy lines from buffer to array: */
- if (!NI_LineBufferToArray(&oline_buffer))
- goto exit;
- } while(more);
-exit:
- if (ibuffer) free(ibuffer);
- if (obuffer) free(obuffer);
- return PyErr_Occurred() ? 0 : 1;
-}
-
-#define CASE_CORRELATE_POINT(_pi, _weights, _offsets, _filter_size, \
- _cvalue, _type, _res, _mv) \
-case t ## _type: \
-{ \
- maybelong _ii, _offset; \
- for(_ii = 0; _ii < _filter_size; _ii++) { \
- _offset = _offsets[_ii]; \
- if (_offset == _mv) \
- _res += _weights[_ii] * _cvalue; \
- else \
- _res += _weights[_ii] * (double)*(_type*)(_pi + _offset); \
- } \
-} \
-break
-
-#define CASE_FILTER_OUT(_po, _tmp, _type) \
-case t ## _type: \
- *(_type*)_po = (_type)_tmp; \
- break
-
-int NI_Correlate(PyArrayObject* input, PyArrayObject* weights,
- PyArrayObject* output, NI_ExtendMode mode,
- double cvalue, maybelong *origins)
-{
- Bool *pf = NULL;
- maybelong fsize, jj, kk, filter_size = 0, border_flag_value;
- maybelong *offsets = NULL, *oo, size;
- NI_FilterIterator fi;
- NI_Iterator ii, io;
- char *pi, *po;
- Float64 *pw;
- Float64 *ww = NULL;
- int ll;
-
- /* get the the footprint: */
- fsize = 1;
- for(ll = 0; ll < weights->nd; ll++)
- fsize *= weights->dimensions[ll];
- pw = (Float64*)PyArray_DATA(weights);
- pf = (Bool*)malloc(fsize * sizeof(Bool));
- if (!pf) {
- PyErr_NoMemory();
- goto exit;
- }
- for(jj = 0; jj < fsize; jj++) {
- if (fabs(pw[jj]) > DBL_EPSILON) {
- pf[jj] = 1;
- ++filter_size;
- } else {
- pf[jj] = 0;
- }
- }
- /* copy the weights to contiguous memory: */
- ww = (Float64*)malloc(filter_size * sizeof(Float64));
- if (!ww) {
- PyErr_NoMemory();
- goto exit;
- }
- jj = 0;
- for(kk = 0; kk < fsize; kk++) {
- if (pf[kk]) {
- ww[jj++] = pw[kk];
- }
- }
- /* initialize filter offsets: */
- if (!NI_InitFilterOffsets(input, pf, weights->dimensions, origins,
- mode, &offsets, &border_flag_value, NULL))
- goto exit;
- /* initialize filter iterator: */
- if (!NI_InitFilterIterator(input->nd, weights->dimensions, filter_size,
- input->dimensions, origins, &fi))
- goto exit;
- /* initialize input element iterator: */
- if (!NI_InitPointIterator(input, &ii))
- goto exit;
- /* initialize output element iterator: */
- if (!NI_InitPointIterator(output, &io))
- goto 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;
-}
+/* 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;
+}
Modified: trunk/scipy/ndimage/src/ni_filters.h
===================================================================
--- trunk/scipy/ndimage/src/ni_filters.h 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/ni_filters.h 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,54 +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
+/* 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
Modified: trunk/scipy/ndimage/src/ni_fourier.c
===================================================================
--- trunk/scipy/ndimage/src/ni_fourier.c 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/ni_fourier.c 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,548 +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;
-}
+/* 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;
+}
Modified: trunk/scipy/ndimage/src/ni_fourier.h
===================================================================
--- trunk/scipy/ndimage/src/ni_fourier.h 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/ni_fourier.h 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,40 +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
+/* 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
Modified: trunk/scipy/ndimage/src/ni_interpolation.c
===================================================================
--- trunk/scipy/ndimage/src/ni_interpolation.c 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/ni_interpolation.c 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,966 +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;
-}
+/* 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;
+}
Modified: trunk/scipy/ndimage/src/ni_interpolation.h
===================================================================
--- trunk/scipy/ndimage/src/ni_interpolation.h 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/ni_interpolation.h 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,43 +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
+/* 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
Modified: trunk/scipy/ndimage/src/ni_measure.c
===================================================================
--- trunk/scipy/ndimage/src/ni_measure.c 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/ni_measure.c 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,1197 +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;
-}
+/* 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;
+}
Modified: trunk/scipy/ndimage/src/ni_measure.h
===================================================================
--- trunk/scipy/ndimage/src/ni_measure.h 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/ni_measure.h 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,59 +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
+/* 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
Modified: trunk/scipy/ndimage/src/ni_morphology.c
===================================================================
--- trunk/scipy/ndimage/src/ni_morphology.c 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/ni_morphology.c 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,955 +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;
-}
+/* 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;
+}
Modified: trunk/scipy/ndimage/src/ni_morphology.h
===================================================================
--- trunk/scipy/ndimage/src/ni_morphology.h 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/ni_morphology.h 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,46 +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
+/* 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
Modified: trunk/scipy/ndimage/src/ni_support.c
===================================================================
--- trunk/scipy/ndimage/src/ni_support.c 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/ni_support.c 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,751 +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);
- }
-}
+/* 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);
+ }
+}
Modified: trunk/scipy/ndimage/src/ni_support.h
===================================================================
--- trunk/scipy/ndimage/src/ni_support.h 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/ni_support.h 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,323 +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
+/* 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
Modified: trunk/scipy/ndimage/src/register/Register_EXT.c
===================================================================
--- trunk/scipy/ndimage/src/register/Register_EXT.c 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/register/Register_EXT.c 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,753 +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();
-}
-
-
+/* 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();
+}
+
+
Modified: trunk/scipy/ndimage/src/register/Register_IMPL.c
===================================================================
--- trunk/scipy/ndimage/src/register/Register_IMPL.c 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/register/Register_IMPL.c 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,1369 +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;
-
-}
-
-
-
-
+#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;
+
+}
+
+
+
+
Modified: trunk/scipy/ndimage/src/segment/Segmenter_EXT.c
===================================================================
--- trunk/scipy/ndimage/src/segment/Segmenter_EXT.c 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/segment/Segmenter_EXT.c 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,682 +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();
-}
-
-
-
-
-
+#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();
+}
+
+
+
+
+
Modified: trunk/scipy/ndimage/src/segment/Segmenter_IMPL.c
===================================================================
--- trunk/scipy/ndimage/src/segment/Segmenter_IMPL.c 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/segment/Segmenter_IMPL.c 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,1671 +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);
-
-}
-
-
+#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);
+
+}
+
+
Modified: trunk/scipy/ndimage/src/segment/ndImage_Segmenter_structs.h
===================================================================
--- trunk/scipy/ndimage/src/segment/ndImage_Segmenter_structs.h 2008-08-09 02:31:58 UTC (rev 4633)
+++ trunk/scipy/ndimage/src/segment/ndImage_Segmenter_structs.h 2008-08-09 19:29:36 UTC (rev 4634)
@@ -1,29 +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
+#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
More information about the Scipy-svn
mailing list