1745 lines
43 KiB
C
Executable File
1745 lines
43 KiB
C
Executable File
// Copyright (c) 2005-2008 ASCLEPIOS Project, INRIA Sophia-Antipolis (France)
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of the ImageIO Library, and as been adapted for
|
|
// CGAL (www.cgal.org).
|
|
// You can redistribute it and/or modify it under the terms of the
|
|
// GNU Lesser General Public License as published by the Free Software Foundation;
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// Licensees holding a valid commercial license may use this file in
|
|
// accordance with the commercial license agreement provided with the software.
|
|
//
|
|
// These files are provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// $URL$
|
|
// $Id$
|
|
// SPDX-License-Identifier: LGPL-3.0+
|
|
//
|
|
//
|
|
// Author(s) : ASCLEPIOS Project (INRIA Sophia-Antipolis), Laurent Rineau
|
|
|
|
/*************************************************************************
|
|
* recbuffer.c - tools for recursive filtering of 3D and 2D image buffers
|
|
*
|
|
* $Id$
|
|
*
|
|
* Copyright©INRIA 1999
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* recursive filtering of a buffer (a [1,2,3]D array)
|
|
* according that the filtering is separable
|
|
*
|
|
*
|
|
*
|
|
* AUTHOR:
|
|
* Gregoire Malandain (greg@sophia.inria.fr)
|
|
*
|
|
* CREATION DATE:
|
|
* June, 9 1998
|
|
*
|
|
* Copyright Gregoire Malandain, INRIA
|
|
*
|
|
* ADDITIONS, CHANGES
|
|
*
|
|
* * Jul 6 1999 (Gregoire Malandain)
|
|
* a bug in RecursiveFilterOnBuffer (*&%^@$^ cut and paste)
|
|
*
|
|
*/
|
|
|
|
#ifdef CGAL_HEADER_ONLY
|
|
#define CGAL_INLINE_FUNCTION inline
|
|
#else
|
|
#define CGAL_INLINE_FUNCTION
|
|
#endif
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
|
|
#include <CGAL/ImageIO/convert.h>
|
|
|
|
#ifdef CGAL_HEADER_ONLY
|
|
|
|
inline int& get_static_verbose_recbuffer()
|
|
{
|
|
static int _VERBOSE_ = 0;
|
|
return _VERBOSE_;
|
|
}
|
|
|
|
#else // CGAL_HEADER_ONLY
|
|
|
|
static int _VERBOSE_ = 0;
|
|
|
|
inline int& get_static_verbose_recbuffer()
|
|
{ return _VERBOSE_; }
|
|
|
|
#endif // CGAL_HEADER_ONLY
|
|
|
|
|
|
#define EXIT_ON_FAILURE 0
|
|
#define EXIT_ON_SUCCESS 1
|
|
|
|
/*
|
|
*
|
|
* Gradient modulus
|
|
*
|
|
*
|
|
*/
|
|
CGAL_INLINE_FUNCTION
|
|
int GradientModulus( void *bufferIn,
|
|
bufferType typeIn,
|
|
void *bufferOut,
|
|
bufferType typeOut,
|
|
int *bufferDims,
|
|
int *borderLengths,
|
|
float *filterCoefs,
|
|
recursiveFilterType filterType )
|
|
{
|
|
const char *proc = "GradientModulus";
|
|
float *auxBuf = NULL;
|
|
float *tmpBuf = NULL, *grdBuf = NULL;
|
|
int sizeAuxBuf = 0;
|
|
derivativeOrder derivatives[3];
|
|
int i;
|
|
|
|
|
|
sizeAuxBuf = bufferDims[0] * bufferDims[1] * bufferDims[2];
|
|
if ( typeOut != CGAL_FLOAT || bufferIn == bufferOut )
|
|
sizeAuxBuf *= 2;
|
|
|
|
|
|
/* allocation des buffers de calcul
|
|
*/
|
|
auxBuf = (float*)malloc( sizeAuxBuf * sizeof(float) );
|
|
if ( auxBuf == NULL ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, "%s: unable to allocate auxiliary buffer\n", proc );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
tmpBuf = auxBuf;
|
|
if ( typeOut != CGAL_FLOAT || bufferIn == bufferOut ) {
|
|
grdBuf = tmpBuf;
|
|
grdBuf += bufferDims[0] * bufferDims[1] * bufferDims[2];
|
|
} else {
|
|
grdBuf = (float*)bufferOut;
|
|
}
|
|
|
|
/* cas 2D
|
|
*/
|
|
if ( bufferDims[2] == 1 ) {
|
|
|
|
derivatives[0] = DERIVATIVE_1;
|
|
derivatives[1] = DERIVATIVE_0;
|
|
derivatives[2] = NODERIVATIVE;
|
|
if ( RecursiveFilterOnBuffer( bufferIn, typeIn, (void*)grdBuf, CGAL_FLOAT,
|
|
bufferDims, borderLengths, derivatives,
|
|
filterCoefs, filterType ) != EXIT_ON_SUCCESS ) {
|
|
if ( _VERBOSE_ )
|
|
fprintf( stderr, "%s: unable to compute X derivative (2D)\n", proc );
|
|
free( auxBuf );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
derivatives[0] = DERIVATIVE_0;
|
|
derivatives[1] = DERIVATIVE_1;
|
|
derivatives[2] = NODERIVATIVE;
|
|
if ( RecursiveFilterOnBuffer( bufferIn, typeIn, (void*)tmpBuf, CGAL_FLOAT,
|
|
bufferDims, borderLengths, derivatives,
|
|
filterCoefs, filterType ) != EXIT_ON_SUCCESS ) {
|
|
if ( _VERBOSE_ )
|
|
fprintf( stderr, "%s: unable to compute Y derivative (2D)\n", proc );
|
|
free( auxBuf );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
sizeAuxBuf = bufferDims[0] * bufferDims[1] * bufferDims[2];
|
|
for ( i = 0; i < sizeAuxBuf; i++ )
|
|
grdBuf[i] = (float)sqrt( grdBuf[i]*grdBuf[i] + tmpBuf[i]*tmpBuf[i] );
|
|
|
|
} else {
|
|
|
|
derivatives[0] = NODERIVATIVE;
|
|
derivatives[1] = NODERIVATIVE;
|
|
derivatives[2] = DERIVATIVE_0;
|
|
if ( RecursiveFilterOnBuffer( bufferIn, typeIn, (void*)tmpBuf, CGAL_FLOAT,
|
|
bufferDims, borderLengths, derivatives,
|
|
filterCoefs, filterType ) != EXIT_ON_SUCCESS ) {
|
|
if ( _VERBOSE_ )
|
|
fprintf( stderr, "%s: unable to compute Z smoothing (3D)\n", proc );
|
|
free( auxBuf );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
derivatives[0] = DERIVATIVE_1;
|
|
derivatives[1] = DERIVATIVE_0;
|
|
derivatives[2] = NODERIVATIVE;
|
|
if ( RecursiveFilterOnBuffer( (void*)tmpBuf, CGAL_FLOAT, (void*)grdBuf, CGAL_FLOAT,
|
|
bufferDims, borderLengths, derivatives,
|
|
filterCoefs, filterType ) != EXIT_ON_SUCCESS ) {
|
|
if ( _VERBOSE_ )
|
|
fprintf( stderr, "%s: unable to compute X derivative (3D)\n", proc );
|
|
free( auxBuf );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
derivatives[0] = DERIVATIVE_0;
|
|
derivatives[1] = DERIVATIVE_1;
|
|
derivatives[2] = NODERIVATIVE;
|
|
if ( RecursiveFilterOnBuffer( (void*)tmpBuf, CGAL_FLOAT, (void*)tmpBuf, CGAL_FLOAT,
|
|
bufferDims, borderLengths, derivatives,
|
|
filterCoefs, filterType ) != EXIT_ON_SUCCESS ) {
|
|
if ( _VERBOSE_ )
|
|
fprintf( stderr, "%s: unable to compute Y derivative (3D)\n", proc );
|
|
free( auxBuf );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
sizeAuxBuf = bufferDims[0] * bufferDims[1] * bufferDims[2];
|
|
for ( i = 0; i < sizeAuxBuf; i++ )
|
|
grdBuf[i] = grdBuf[i]*grdBuf[i] + tmpBuf[i]*tmpBuf[i];
|
|
|
|
derivatives[0] = DERIVATIVE_0;
|
|
derivatives[1] = DERIVATIVE_0;
|
|
derivatives[2] = DERIVATIVE_1;
|
|
if ( RecursiveFilterOnBuffer( bufferIn, typeIn, (void*)tmpBuf, CGAL_FLOAT,
|
|
bufferDims, borderLengths, derivatives,
|
|
filterCoefs, filterType ) != EXIT_ON_SUCCESS ) {
|
|
if ( _VERBOSE_ )
|
|
fprintf( stderr, "%s: unable to compute Z derivative (3D)\n", proc );
|
|
free( auxBuf );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
for ( i = 0; i < sizeAuxBuf; i++ )
|
|
grdBuf[i] = (float)sqrt( grdBuf[i] + tmpBuf[i]*tmpBuf[i] );
|
|
|
|
}
|
|
|
|
if ( grdBuf != bufferOut )
|
|
ConvertBuffer( grdBuf, CGAL_FLOAT, bufferOut, typeOut,
|
|
bufferDims[0]*bufferDims[1]*bufferDims[2] );
|
|
free( auxBuf );
|
|
return( EXIT_ON_SUCCESS );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
*
|
|
* Laplacian
|
|
*
|
|
*
|
|
*/
|
|
CGAL_INLINE_FUNCTION
|
|
int Laplacian_2D ( void *bufferIn,
|
|
bufferType typeIn,
|
|
void *bufferOut,
|
|
bufferType typeOut,
|
|
int *bufferDims,
|
|
int *borderLengths,
|
|
float *filterCoefs,
|
|
recursiveFilterType filterType )
|
|
{
|
|
const char *proc = "Laplacian_2D";
|
|
float *theXX = NULL;
|
|
float *theYY = NULL;
|
|
|
|
derivativeOrder XXderiv[3] = { DERIVATIVE_2, SMOOTHING, NODERIVATIVE };
|
|
derivativeOrder YYderiv[3] = { SMOOTHING, DERIVATIVE_2, NODERIVATIVE };
|
|
int sliceDims[3];
|
|
int z, i, dimxXdimy;
|
|
|
|
void *sliceOut = NULL;
|
|
|
|
|
|
|
|
/*
|
|
* We check the buffers' dimensions.
|
|
*/
|
|
if ( (bufferDims[0] <= 0) || (bufferDims[1] <= 0) || (bufferDims[2] <= 0) ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Fatal error in %s: improper buffer's dimension.\n", proc );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
/*
|
|
* test of the coefficients
|
|
*/
|
|
if ( (filterCoefs[0] < 0.0) || (filterCoefs[1] < 0.0) ||
|
|
(filterCoefs[2] < 0.0) ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Error in %s: negative coefficient's value.\n", proc );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
dimxXdimy = bufferDims[0] * bufferDims[1];
|
|
sliceDims[0] = bufferDims[0];
|
|
sliceDims[1] = bufferDims[1];
|
|
sliceDims[2] = 1;
|
|
|
|
|
|
if ( typeOut == CGAL_FLOAT ) {
|
|
theXX = (float*)malloc( dimxXdimy * sizeof( float ) );
|
|
} else {
|
|
theXX = (float*)malloc( 2 * dimxXdimy * sizeof( float ) );
|
|
}
|
|
|
|
if ( theXX == NULL ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to allocate auxiliary buffer.\n" );
|
|
}
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
if ( typeOut != CGAL_FLOAT ) {
|
|
theYY = theXX;
|
|
theYY += dimxXdimy;
|
|
}
|
|
|
|
|
|
|
|
for ( z=0; z<bufferDims[2]; z++ ) {
|
|
|
|
if ( typeOut == CGAL_FLOAT ) {
|
|
theYY = ((float*)bufferOut) + z * dimxXdimy;
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( bufferIn, typeIn, theXX, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
XXderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute X^2 derivative.\n" );
|
|
}
|
|
free( theXX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( bufferIn, typeIn, theYY, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
YYderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Y^2 derivative.\n" );
|
|
}
|
|
free( theXX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
for ( i=0; i<dimxXdimy; i++ ) theYY[i] += theXX[i];
|
|
if ( typeOut != CGAL_FLOAT ) {
|
|
switch ( typeOut ) {
|
|
case CGAL_UCHAR :
|
|
sliceOut = (((u8*)bufferOut) + z * dimxXdimy);
|
|
break;
|
|
case CGAL_SCHAR :
|
|
sliceOut = (((s8*)bufferOut) + z * dimxXdimy);
|
|
break;
|
|
case CGAL_SSHORT :
|
|
sliceOut = (((s16*)bufferOut) + z * dimxXdimy);
|
|
break;
|
|
case CGAL_DOUBLE :
|
|
sliceOut = (((r64*)bufferOut) + z * dimxXdimy);
|
|
break;
|
|
default :
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Error in %s: such output type not handled.\n", proc );
|
|
free( theXX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
ConvertBuffer( theYY, CGAL_FLOAT, sliceOut, typeOut, dimxXdimy );
|
|
}
|
|
}
|
|
|
|
return( EXIT_ON_SUCCESS );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CGAL_INLINE_FUNCTION
|
|
int Laplacian ( void *bufferIn,
|
|
bufferType typeIn,
|
|
void *bufferOut,
|
|
bufferType typeOut,
|
|
int *bufferDims,
|
|
int *borderLengths,
|
|
float *filterCoefs,
|
|
recursiveFilterType filterType )
|
|
{
|
|
const char *proc = "Laplacian";
|
|
float *theSL = NULL;
|
|
float *theZZ = NULL;
|
|
float *theZ0 = NULL;
|
|
|
|
|
|
derivativeOrder XXderiv[3] = { DERIVATIVE_2, SMOOTHING, NODERIVATIVE };
|
|
derivativeOrder YYderiv[3] = { SMOOTHING, DERIVATIVE_2, NODERIVATIVE };
|
|
derivativeOrder Zsmooth[3] = { NODERIVATIVE, NODERIVATIVE, SMOOTHING };
|
|
derivativeOrder ZZderiv[3] = { SMOOTHING, SMOOTHING, DERIVATIVE_2 };
|
|
|
|
int sliceDims[3];
|
|
int z, i, j, dimxXdimy;
|
|
|
|
|
|
|
|
|
|
/*
|
|
* We check the buffers' dimensions.
|
|
*/
|
|
if ( bufferDims[2] == 1 ) {
|
|
return( Laplacian_2D ( bufferIn, typeIn, bufferOut, typeOut,
|
|
bufferDims, borderLengths, filterCoefs, filterType ) );
|
|
}
|
|
|
|
if ( (bufferDims[0] <= 0) || (bufferDims[1] <= 0) || (bufferDims[2] <= 0) ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Fatal error in %s: improper buffer's dimension.\n", proc );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
/*
|
|
* test of the coefficients
|
|
*/
|
|
if ( (filterCoefs[0] < 0.0) || (filterCoefs[1] < 0.0) ||
|
|
(filterCoefs[2] < 0.0) ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Error in %s: negative coefficient's value.\n", proc );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
dimxXdimy = bufferDims[0] * bufferDims[1];
|
|
sliceDims[0] = bufferDims[0];
|
|
sliceDims[1] = bufferDims[1];
|
|
sliceDims[2] = 1;
|
|
|
|
|
|
|
|
if ( typeOut == CGAL_FLOAT ) {
|
|
theSL = (float*)malloc( (1+bufferDims[2]) * dimxXdimy * sizeof( float ) );
|
|
} else {
|
|
theSL = (float*)malloc( (1+2*bufferDims[2]) * dimxXdimy * sizeof( float ) );
|
|
}
|
|
|
|
|
|
|
|
if ( theSL == NULL ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to allocate auxiliary buffer.\n" );
|
|
}
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
|
|
theZ0 = theSL;
|
|
theZ0 += dimxXdimy;
|
|
|
|
|
|
|
|
if ( typeOut == CGAL_FLOAT ) {
|
|
theZZ = (float*) bufferOut;
|
|
} else {
|
|
theZZ = theZ0;
|
|
theZZ += dimxXdimy * bufferDims[2];
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*
|
|
* 3D filtering / filtering along Z
|
|
*
|
|
*/
|
|
|
|
if ( RecursiveFilterOnBuffer( bufferIn, typeIn, theZ0, CGAL_FLOAT,
|
|
bufferDims, borderLengths,
|
|
Zsmooth, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Z^0 derivative.\n" );
|
|
}
|
|
free( theSL );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
if ( RecursiveFilterOnBuffer( bufferIn, typeIn, theZZ, CGAL_FLOAT,
|
|
bufferDims, borderLengths,
|
|
ZZderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Z^2 derivative.\n" );
|
|
}
|
|
free( theSL );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for ( z=0; z<bufferDims[2]; z++ ) {
|
|
|
|
/*
|
|
*
|
|
* 2D filtering / filtering along X and Y
|
|
*
|
|
*/
|
|
|
|
if ( RecursiveFilterOnBuffer( theZ0+z*dimxXdimy, CGAL_FLOAT, theSL, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
XXderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute X^2 derivative.\n" );
|
|
}
|
|
free( theSL );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
for ( j=z*dimxXdimy, i=0; i<dimxXdimy; j++, i++ ) {
|
|
theZZ[j] += theSL[i];
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( theZ0+z*dimxXdimy, CGAL_FLOAT, theSL, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
YYderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Y^2 derivative.\n" );
|
|
}
|
|
free( theSL );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
for ( j=z*dimxXdimy, i=0; i<dimxXdimy; j++, i++ ) {
|
|
theZZ[j] += theSL[i];
|
|
}
|
|
|
|
}
|
|
|
|
if ( typeOut != CGAL_FLOAT ) {
|
|
ConvertBuffer( theZZ, CGAL_FLOAT, bufferOut, typeOut, bufferDims[2]*dimxXdimy );
|
|
}
|
|
|
|
return( EXIT_ON_SUCCESS );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
*
|
|
* Gradient . Hessian * Gradient
|
|
*
|
|
*
|
|
*/
|
|
CGAL_INLINE_FUNCTION
|
|
int GradientHessianGradient_2D ( void *bufferIn,
|
|
bufferType typeIn,
|
|
void *bufferOut,
|
|
bufferType typeOut,
|
|
int *bufferDims,
|
|
int *borderLengths,
|
|
float *filterCoefs,
|
|
recursiveFilterType filterType )
|
|
{
|
|
const char *proc = "GradientHessianGradient_2D";
|
|
float *theXX = NULL;
|
|
float *theYY = NULL;
|
|
float *theXY = NULL;
|
|
float *theX = NULL;
|
|
float *theY = NULL;
|
|
|
|
derivativeOrder Xsmooth[3] = { SMOOTHING, NODERIVATIVE, NODERIVATIVE };
|
|
derivativeOrder Yderiv[3] = { NODERIVATIVE, DERIVATIVE_1_EDGES, NODERIVATIVE };
|
|
derivativeOrder YYderiv[3] = { NODERIVATIVE, DERIVATIVE_2, NODERIVATIVE };
|
|
|
|
derivativeOrder Ysmooth[3] = { NODERIVATIVE, SMOOTHING, NODERIVATIVE };
|
|
derivativeOrder Xderiv[3] = { DERIVATIVE_1_EDGES, NODERIVATIVE, NODERIVATIVE };
|
|
derivativeOrder XXderiv[3] = { DERIVATIVE_2, NODERIVATIVE, NODERIVATIVE };
|
|
|
|
derivativeOrder XYderiv[3] = { DERIVATIVE_1, DERIVATIVE_1, NODERIVATIVE };
|
|
|
|
int sliceDims[3];
|
|
int z, i, dimxXdimy;
|
|
|
|
void *sliceIn = NULL;
|
|
void *sliceOut = NULL;
|
|
|
|
double gx, gy, g;
|
|
|
|
/*
|
|
* We check the buffers' dimensions.
|
|
*/
|
|
if ( (bufferDims[0] <= 0) || (bufferDims[1] <= 0) || (bufferDims[2] <= 0) ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Fatal error in %s: improper buffer's dimension.\n", proc );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
/*
|
|
* test of the coefficients
|
|
*/
|
|
if ( (filterCoefs[0] < 0.0) || (filterCoefs[1] < 0.0) ||
|
|
(filterCoefs[2] < 0.0) ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Error in %s: negative coefficient's value.\n", proc );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
dimxXdimy = bufferDims[0] * bufferDims[1];
|
|
sliceDims[0] = bufferDims[0];
|
|
sliceDims[1] = bufferDims[1];
|
|
sliceDims[2] = 1;
|
|
|
|
|
|
if ( typeOut == CGAL_FLOAT ) {
|
|
theXX = (float*)malloc( 4 * dimxXdimy * sizeof( float ) );
|
|
} else {
|
|
theXX = (float*)malloc( 5 * dimxXdimy * sizeof( float ) );
|
|
}
|
|
|
|
if ( theXX == NULL ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to allocate auxiliary buffer.\n" );
|
|
}
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
|
|
theX = theY = theYY = theXX;
|
|
theYY += dimxXdimy;
|
|
theX += 2*dimxXdimy;
|
|
theY += 3*dimxXdimy;
|
|
|
|
|
|
|
|
if ( typeOut != CGAL_FLOAT ) {
|
|
theXY = theXX;
|
|
theXY += 4*dimxXdimy;
|
|
}
|
|
|
|
|
|
|
|
for ( z=0; z<bufferDims[2]; z++ ) {
|
|
|
|
switch( typeIn ) {
|
|
default :
|
|
break;
|
|
case CGAL_UCHAR :
|
|
case CGAL_SCHAR :
|
|
sliceIn = (void*)( ((u8*)bufferIn) + z*dimxXdimy ); break;
|
|
case CGAL_USHORT :
|
|
case CGAL_SSHORT :
|
|
sliceIn = (void*)( ((u16*)bufferIn) + z*dimxXdimy ); break;
|
|
case CGAL_FLOAT :
|
|
sliceIn = (void*)( ((float*)bufferIn) + z*dimxXdimy ); break;
|
|
case CGAL_DOUBLE :
|
|
sliceIn = (void*)( ((double*)bufferIn) + z*dimxXdimy ); break;
|
|
}
|
|
if ( typeOut == CGAL_FLOAT ) {
|
|
theXY = ((float*)bufferOut) + z * dimxXdimy;
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( sliceIn, typeIn, theX, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
Ysmooth, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Y^0 derivative.\n" );
|
|
}
|
|
free( theXX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( sliceIn, typeIn, theY, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
Xsmooth, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute X^0 derivative.\n" );
|
|
}
|
|
free( theXX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( RecursiveFilterOnBuffer( sliceIn, typeIn, theXY, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
XYderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute X^1Y^1 derivative.\n" );
|
|
}
|
|
free( theXX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( RecursiveFilterOnBuffer( theX, CGAL_FLOAT, theXX, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
XXderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute X^2 derivative.\n" );
|
|
}
|
|
free( theXX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( theY, CGAL_FLOAT, theYY, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
YYderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Y^2 derivative.\n" );
|
|
}
|
|
free( theXX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( RecursiveFilterOnBuffer( theX, CGAL_FLOAT, theX, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
Xderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute X^1 derivative.\n" );
|
|
}
|
|
free( theXX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( theY, CGAL_FLOAT, theY, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
Yderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Y^1 derivative.\n" );
|
|
}
|
|
free( theXX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( i=0; i<dimxXdimy; i++ ) {
|
|
gx = theX[i];
|
|
gy = theY[i];
|
|
g = (gx*gx + gy*gy);
|
|
theXY[i] = (float)(gx * ( theXX[i] * gx + theXY[i] * gy ) +
|
|
gy * ( theXY[i] * gx + theYY[i] * gy ));
|
|
if ( g > 1e-10 ) theXY[i] = (float)(theXY[i] / g);
|
|
}
|
|
|
|
if ( typeOut != CGAL_FLOAT ) {
|
|
switch ( typeOut ) {
|
|
case CGAL_UCHAR :
|
|
sliceOut = (((u8*)bufferOut) + z * dimxXdimy);
|
|
break;
|
|
case CGAL_SCHAR :
|
|
sliceOut = (((s8*)bufferOut) + z * dimxXdimy);
|
|
break;
|
|
case CGAL_SSHORT :
|
|
sliceOut = (((s16*)bufferOut) + z * dimxXdimy);
|
|
break;
|
|
case CGAL_DOUBLE :
|
|
sliceOut = (((r64*)bufferOut) + z * dimxXdimy);
|
|
break;
|
|
default :
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Error in %s: such output type not handled.\n", proc );
|
|
free( theXX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
ConvertBuffer( theXY, CGAL_FLOAT, sliceOut, typeOut, dimxXdimy );
|
|
}
|
|
}
|
|
|
|
return( EXIT_ON_SUCCESS );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CGAL_INLINE_FUNCTION
|
|
int GradientHessianGradient ( void *bufferIn,
|
|
bufferType typeIn,
|
|
void *bufferOut,
|
|
bufferType typeOut,
|
|
int *bufferDims,
|
|
int *borderLengths,
|
|
float *filterCoefs,
|
|
recursiveFilterType filterType )
|
|
{
|
|
const char *proc = "GradientHessianGradient";
|
|
|
|
|
|
|
|
float *theZZ = NULL;
|
|
float *theZ = NULL;
|
|
float *theZ1 = NULL;
|
|
float *theZ0 = NULL;
|
|
|
|
float *theXZ = NULL;
|
|
float *theYZ = NULL;
|
|
|
|
float *theXX = NULL;
|
|
float *theYY = NULL;
|
|
float *theXY = NULL;
|
|
|
|
float *theX = NULL;
|
|
float *theY = NULL;
|
|
|
|
|
|
derivativeOrder ZZderiv[3] = { SMOOTHING, SMOOTHING, DERIVATIVE_2 };
|
|
derivativeOrder Zderiv[3] = { SMOOTHING, SMOOTHING, DERIVATIVE_1 };
|
|
derivativeOrder Z1deriv[3] = { NODERIVATIVE, NODERIVATIVE, DERIVATIVE_1 };
|
|
derivativeOrder Z0deriv[3] = { NODERIVATIVE, NODERIVATIVE, SMOOTHING };
|
|
|
|
derivativeOrder XZderiv[3] = { DERIVATIVE_1, SMOOTHING, NODERIVATIVE };
|
|
derivativeOrder YZderiv[3] = { SMOOTHING, DERIVATIVE_1, NODERIVATIVE };
|
|
|
|
derivativeOrder XXderiv[3] = { DERIVATIVE_2, SMOOTHING, NODERIVATIVE };
|
|
derivativeOrder YYderiv[3] = { SMOOTHING, DERIVATIVE_2, NODERIVATIVE };
|
|
derivativeOrder XYderiv[3] = { DERIVATIVE_1, DERIVATIVE_1, NODERIVATIVE };
|
|
|
|
derivativeOrder Xderiv[3] = { DERIVATIVE_1, SMOOTHING, NODERIVATIVE };
|
|
derivativeOrder Yderiv[3] = { SMOOTHING, DERIVATIVE_1, NODERIVATIVE };
|
|
|
|
int sliceDims[3];
|
|
int z, i, j, dimxXdimy;
|
|
|
|
double gx, gy, gz, g;
|
|
|
|
/*
|
|
* We check the buffers' dimensions.
|
|
*/
|
|
if ( bufferDims[2] == 1 ) {
|
|
return( GradientHessianGradient_2D ( bufferIn, typeIn, bufferOut, typeOut,
|
|
bufferDims, borderLengths, filterCoefs, filterType ) );
|
|
}
|
|
|
|
if ( (bufferDims[0] <= 0) || (bufferDims[1] <= 0) || (bufferDims[2] <= 0) ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Fatal error in %s: improper buffer's dimension.\n", proc );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
/*
|
|
* test of the coefficients
|
|
*/
|
|
if ( (filterCoefs[0] < 0.0) || (filterCoefs[1] < 0.0) ||
|
|
(filterCoefs[2] < 0.0) ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Error in %s: negative coefficient's value.\n", proc );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
/*
|
|
*
|
|
*/
|
|
dimxXdimy = bufferDims[0] * bufferDims[1];
|
|
sliceDims[0] = bufferDims[0];
|
|
sliceDims[1] = bufferDims[1];
|
|
sliceDims[2] = 1;
|
|
|
|
|
|
if ( typeOut == CGAL_FLOAT ) {
|
|
theX = (float*)malloc( (7+3*bufferDims[2]) * dimxXdimy * sizeof( float ) );
|
|
} else {
|
|
theX = (float*)malloc( (7+4*bufferDims[2]) * dimxXdimy * sizeof( float ) );
|
|
}
|
|
|
|
|
|
if ( theX == NULL ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to allocate auxiliary buffer.\n" );
|
|
}
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
/*
|
|
* BUFFERS
|
|
*
|
|
* slices : theX theY theXY theYY theXX theYZ theXZ
|
|
*
|
|
* volumes : theZ0 theZ1 theZ theZZ
|
|
*
|
|
*/
|
|
|
|
theY = theXX = theXY = theYY = theYZ = theXZ = theX;
|
|
theZ0 = theZ1 = theZ = theX;
|
|
|
|
theY += dimxXdimy;
|
|
theXY += 2*dimxXdimy;
|
|
theYY += 3*dimxXdimy;
|
|
theXX += 4*dimxXdimy;
|
|
theYZ += 5*dimxXdimy;
|
|
theXZ += 6*dimxXdimy;
|
|
|
|
theZ0 += 7*dimxXdimy;
|
|
theZ1 += 7*dimxXdimy + bufferDims[2]*dimxXdimy;
|
|
theZ += 7*dimxXdimy + 2*bufferDims[2]*dimxXdimy;
|
|
|
|
if ( typeOut == CGAL_FLOAT ) {
|
|
theZZ = (float*)bufferOut;
|
|
} else {
|
|
theZZ = theX;
|
|
theZZ += 7*dimxXdimy + 3*bufferDims[2]*dimxXdimy;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*
|
|
* 3D filtering / filtering along Z
|
|
*
|
|
*/
|
|
|
|
if ( RecursiveFilterOnBuffer( bufferIn, typeIn, theZ0, CGAL_FLOAT,
|
|
bufferDims, borderLengths,
|
|
Z0deriv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Z^0 derivative.\n" );
|
|
}
|
|
free( theX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( bufferIn, typeIn, theZ1, CGAL_FLOAT,
|
|
bufferDims, borderLengths,
|
|
Z1deriv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Z^1 derivative.\n" );
|
|
}
|
|
free( theX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( bufferIn, typeIn, theZ, CGAL_FLOAT,
|
|
bufferDims, borderLengths,
|
|
Zderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Z^1 derivative (edge).\n" );
|
|
}
|
|
free( theX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( bufferIn, typeIn, theZZ, CGAL_FLOAT,
|
|
bufferDims, borderLengths,
|
|
ZZderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Z^2 derivative.\n" );
|
|
}
|
|
free( theX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
/*
|
|
* theZ0 : smoothed along Z
|
|
* theZ1 : first derivative along Z
|
|
* theZ : first derivative along Z, smoothed along X and Y
|
|
* theZZ : second derivative along Z, smoothed along X and Y
|
|
*/
|
|
|
|
|
|
|
|
for ( z=0; z<bufferDims[2]; z++ ) {
|
|
fprintf( stderr, "%s: processing slice %3d/%d\r",
|
|
proc, z, bufferDims[2] );
|
|
/*
|
|
*
|
|
* 2D filtering / filtering along X and Y
|
|
*
|
|
*/
|
|
|
|
if ( RecursiveFilterOnBuffer( theZ1+z*dimxXdimy, CGAL_FLOAT, theXZ, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
XZderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute X^1Z^1 derivative.\n" );
|
|
}
|
|
free( theX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( theZ1+z*dimxXdimy, CGAL_FLOAT, theYZ, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
YZderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Y^1Z^1 derivative.\n" );
|
|
}
|
|
free( theX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( RecursiveFilterOnBuffer( theZ0+z*dimxXdimy, CGAL_FLOAT, theXX, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
XXderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute X^2 derivative.\n" );
|
|
}
|
|
free( theX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( theZ0+z*dimxXdimy, CGAL_FLOAT, theYY, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
YYderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Y^2 derivative.\n" );
|
|
}
|
|
free( theX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( theZ0+z*dimxXdimy, CGAL_FLOAT, theXY, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
XYderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute X^1Y^1 derivative.\n" );
|
|
}
|
|
free( theX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
|
|
if ( RecursiveFilterOnBuffer( theZ0+z*dimxXdimy, CGAL_FLOAT, theX, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
Xderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute X^1 derivative (edge).\n" );
|
|
}
|
|
free( theX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
if ( RecursiveFilterOnBuffer( theZ0+z*dimxXdimy, CGAL_FLOAT, theY, CGAL_FLOAT,
|
|
sliceDims, borderLengths,
|
|
Yderiv, filterCoefs, filterType ) == 0 ) {
|
|
if ( _VERBOSE_ > 0 ) {
|
|
fprintf( stderr, " Fatal error in %s:", proc );
|
|
fprintf( stderr, " unable to compute Y^1 derivative (edge).\n" );
|
|
}
|
|
free( theX );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
|
|
|
|
for ( j=z*dimxXdimy, i=0; i<dimxXdimy; j++, i++ ) {
|
|
gx = theX[i];
|
|
gy = theY[i];
|
|
gz = theZ[j];
|
|
g = gx*gx + gy*gy + gz*gz;
|
|
theZZ[j] = (float)(gx * ( theXX[i] * gx + theXY[i] * gy + theXZ[i] * gz ) +
|
|
gy * ( theXY[i] * gx + theYY[i] * gy + theYZ[i] * gz ) +
|
|
gz * ( theXZ[i] * gx + theYZ[i] * gy + theZZ[j] * gz ));
|
|
if ( g > 1e-10 ) theZZ[j] = (float)(theZZ[j] / g);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( typeOut != CGAL_FLOAT ) {
|
|
ConvertBuffer( theZZ, CGAL_FLOAT, bufferOut, typeOut, bufferDims[2]*dimxXdimy );
|
|
}
|
|
|
|
free( theX );
|
|
|
|
return( EXIT_ON_SUCCESS );
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
*
|
|
*
|
|
*
|
|
*
|
|
*/
|
|
CGAL_INLINE_FUNCTION
|
|
int RecursiveFilterOnBuffer( void *bufferIn,
|
|
bufferType typeIn,
|
|
void *bufferOut,
|
|
bufferType typeOut,
|
|
int *bufferDims,
|
|
int *borderLengths,
|
|
derivativeOrder *derivatives,
|
|
float *filterCoefs,
|
|
recursiveFilterType filterType )
|
|
{
|
|
const char *proc = "RecursiveFilterOnBuffer";
|
|
int dimx, dimxXdimy;
|
|
int dimy, dimz;
|
|
int x, y, z;
|
|
/*
|
|
*obviously, we need to perform the computation
|
|
* with float or double values. For this reason,
|
|
* we allocate an auxiliary buffer if the output buffer
|
|
* is not of type float or double.
|
|
*/
|
|
void *bufferToBeProcessed = (void*)NULL;
|
|
bufferType typeToBeProcessed = TYPE_UNKNOWN;
|
|
void *bufferResult = (void*)NULL;
|
|
bufferType typeResult = TYPE_UNKNOWN;
|
|
/*
|
|
* lines' lengths
|
|
*/
|
|
int lengthX = 0;
|
|
int lengthY = 0;
|
|
int lengthZ = 0;
|
|
int maxLengthline = 0;
|
|
int borderXlength = 0;
|
|
int borderYlength = 0;
|
|
int borderZlength = 0;
|
|
/*
|
|
* 1D arrays for computations.
|
|
*/
|
|
double *theLine = (double*)NULL;
|
|
double *resLine = (double*)NULL;
|
|
double *tmpLine = (double*)NULL;
|
|
/*
|
|
* pointers for computations;
|
|
*/
|
|
r32 *r32firstPoint = (r32*)NULL;
|
|
r64 *r64firstPoint = (r64*)NULL;
|
|
r32 *r32_pt = (r32*)NULL;
|
|
r64 *r64_pt = (r64*)NULL;
|
|
double *dbl_pt1 = (double*)NULL;
|
|
double *dbl_pt2 = (double*)NULL;
|
|
double dbl_first = 0.0;
|
|
double dbl_last = 0.0;
|
|
int offsetLastPoint = 0;
|
|
int offsetNextFirstPoint = 0;
|
|
r32 *r32firstPointResult = (r32*)NULL;
|
|
r64 *r64firstPointResult = (r64*)NULL;
|
|
double *theLinePlusBorder = (double*)NULL;
|
|
double *resLinePlusBorder = (double*)NULL;
|
|
|
|
RFcoefficientType *RFC = NULL;
|
|
|
|
/*
|
|
* We check the buffers' dimensions.
|
|
*/
|
|
dimx = bufferDims[0]; dimy = bufferDims[1]; dimz = bufferDims[2];
|
|
dimxXdimy = dimx * dimy;
|
|
if ( (dimx <= 0) || (dimy <= 0) || (dimz <= 0) ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Fatal error in %s: improper buffer's dimension.\n", proc );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
/*
|
|
* We check the pointers.
|
|
*/
|
|
if ( (bufferIn == (void*)NULL) || (bufferOut == (void*)NULL) ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Fatal error in %s: NULL pointer on buffer.\n", proc );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
/*
|
|
* May we use the buffer bufferOut as the bufferResult?
|
|
* If its type is CGAL_FLOAT or CGAL_DOUBLE, then yes.
|
|
* If not, we have to allocate an auxiliary buffer.
|
|
*/
|
|
if ( (typeOut == CGAL_FLOAT) || (typeOut == CGAL_DOUBLE) ) {
|
|
bufferResult = bufferOut;
|
|
typeResult = typeOut;
|
|
} else {
|
|
bufferResult = (void*)malloc( (dimx*dimy*dimz) * sizeof(r32) );
|
|
if ( bufferResult == (void*)NULL ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Fatal error in %s: unable to allocate auxiliary buffer.\n", proc );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
typeResult = CGAL_FLOAT;
|
|
}
|
|
|
|
/*
|
|
* May we consider the buffer bufferIn as the bufferToBeProcessed?
|
|
* If its type is CGAL_FLOAT or CGAL_DOUBLE, then yes.
|
|
* If not, we convert it into the buffer bufferResult, and this
|
|
* last buffer is the bufferToBeProcessed.
|
|
*/
|
|
if ( (typeIn == CGAL_FLOAT) || (typeIn == CGAL_DOUBLE) ) {
|
|
bufferToBeProcessed = bufferIn;
|
|
typeToBeProcessed = typeIn;
|
|
} else {
|
|
ConvertBuffer( bufferIn, typeIn, bufferResult, typeResult, (dimx*dimy*dimz) );
|
|
bufferToBeProcessed = bufferResult;
|
|
typeToBeProcessed = typeResult;
|
|
}
|
|
|
|
/*
|
|
* Estimation of the lines' length along each direction.
|
|
*/
|
|
if ( borderLengths != NULL ) {
|
|
borderXlength = borderLengths[0];
|
|
borderYlength = borderLengths[1];
|
|
borderZlength = borderLengths[2];
|
|
if ( borderXlength < 0 ) borderXlength = 0;
|
|
if ( borderYlength < 0 ) borderYlength = 0;
|
|
if ( borderZlength < 0 ) borderZlength = 0;
|
|
}
|
|
|
|
/*
|
|
* Tue Jul 6 19:15:15 MET DST 1999 (gregoire Malandain)
|
|
* changes 3 x dimx -> dimx, dimy, dimz
|
|
*/
|
|
lengthX = dimx + 2 * borderXlength;
|
|
lengthY = dimy + 2 * borderYlength;
|
|
lengthZ = dimz + 2 * borderZlength;
|
|
maxLengthline = lengthX;
|
|
if ( maxLengthline < lengthY ) maxLengthline = lengthY;
|
|
if ( maxLengthline < lengthZ ) maxLengthline = lengthZ;
|
|
if ( maxLengthline <= 0 ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Error in %s: unable to deal with dimensions = 0.\n", proc );
|
|
if ( (typeOut != CGAL_FLOAT) && (typeOut != CGAL_DOUBLE) )
|
|
free( bufferResult );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
/*
|
|
* Allocations of work arrays.
|
|
* We will use them to process each line.
|
|
*/
|
|
theLine = (double*)malloc( 3 * maxLengthline * sizeof(double) );
|
|
if ( theLine == (double*)NULL ) {
|
|
if ( _VERBOSE_ > 0 )
|
|
fprintf( stderr, " Fatal error in %s: unable to allocate auxiliary work arrays.\n", proc );
|
|
if ( (typeOut != CGAL_FLOAT) && (typeOut != CGAL_DOUBLE) )
|
|
free( bufferResult );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
resLine = theLine + maxLengthline;
|
|
tmpLine = resLine + maxLengthline;
|
|
|
|
/*
|
|
* From now,
|
|
* typeToBeProcessed is either CGAL_FLOAT or CGAL_DOUBLE
|
|
* so is typeResult.
|
|
*/
|
|
|
|
|
|
/*
|
|
* Processing along X.
|
|
*/
|
|
if ( dimx > 4 )
|
|
if (derivatives[0] != NODERIVATIVE)
|
|
if (filterCoefs[0] > 0.0) {
|
|
|
|
if ( _VERBOSE_ != 0 )
|
|
fprintf( stderr, " %s: processing along X.\n", proc );
|
|
|
|
RFC = InitRecursiveCoefficients( (double)filterCoefs[0], filterType, derivatives[0] );
|
|
|
|
if ( RFC == NULL ) {
|
|
if ( _VERBOSE_ != 0 )
|
|
fprintf( stderr, " %s: unable to allocate coefficients\n", proc );
|
|
if ( (typeOut != CGAL_FLOAT) && (typeOut != CGAL_DOUBLE) )
|
|
free( bufferResult );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
r64firstPoint = (r64*)bufferToBeProcessed;
|
|
r32firstPoint = (r32*)bufferToBeProcessed;
|
|
|
|
r64firstPointResult = (r64*)bufferResult;
|
|
r32firstPointResult = (r32*)bufferResult;
|
|
|
|
offsetLastPoint = borderXlength + dimx - 1;
|
|
|
|
theLinePlusBorder = theLine + borderXlength;
|
|
resLinePlusBorder = resLine + borderXlength;
|
|
|
|
/*
|
|
* There are dimz*dimy X lines to be processed.
|
|
*/
|
|
for ( z=0; z<dimz; z++ )
|
|
for ( y=0; y<dimy; y++ ) {
|
|
/*
|
|
* Acquiring a X line.
|
|
*/
|
|
dbl_pt1 = theLinePlusBorder;
|
|
switch ( typeToBeProcessed ) {
|
|
case CGAL_DOUBLE :
|
|
(void)memcpy( (void*)dbl_pt1, (void*)r64firstPoint, dimx * sizeof(r64) );
|
|
r64firstPoint += dimx;
|
|
break;
|
|
case CGAL_FLOAT :
|
|
default :
|
|
for ( x=0; x<dimx; x++, dbl_pt1++, r32firstPoint++ ) *dbl_pt1 = *r32firstPoint;
|
|
}
|
|
/*
|
|
* Adding points at both ends of the line.
|
|
*/
|
|
if ( borderXlength > 0 ) {
|
|
dbl_pt1 = theLine + borderXlength; dbl_first = *dbl_pt1;
|
|
dbl_pt2 = theLine + offsetLastPoint; dbl_last = *dbl_pt2;
|
|
for ( x=0; x<borderXlength; x++ ) {
|
|
*--dbl_pt1 = dbl_first;
|
|
*++dbl_pt2 = dbl_last;
|
|
}
|
|
}
|
|
/*
|
|
* Processing the line.
|
|
*/
|
|
if ( RecursiveFilter1D( RFC, theLine, resLine, tmpLine, resLine, lengthX ) == 0 ) {
|
|
if ( _VERBOSE_ != 0 )
|
|
fprintf(stderr," Error in %s: unable to process X line (y=%d,z=%d).\n", proc, y, z);
|
|
if ( (typeOut != CGAL_FLOAT) && (typeOut != CGAL_DOUBLE) )
|
|
free( bufferResult );
|
|
free( (void*)theLine );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
/*
|
|
* Copy the result into the buffer bufferResult.
|
|
*/
|
|
dbl_pt1 = resLinePlusBorder;
|
|
switch ( typeResult ) {
|
|
case CGAL_DOUBLE :
|
|
(void)memcpy( (void*)r64firstPointResult, (void*)dbl_pt1, dimx * sizeof(r64) );
|
|
r64firstPointResult += dimx;
|
|
break;
|
|
case CGAL_FLOAT :
|
|
default :
|
|
for ( x=0; x<dimx; x++, dbl_pt1++, r32firstPointResult++ )
|
|
*r32firstPointResult = (r32)(*dbl_pt1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The next buffer to be processed is the buffer
|
|
* bufferResult.
|
|
*/
|
|
bufferToBeProcessed = bufferResult;
|
|
typeToBeProcessed = typeResult;
|
|
|
|
free( RFC );
|
|
RFC = NULL;
|
|
|
|
} /* end of Processing along X. */
|
|
|
|
/*
|
|
* Processing along Y.
|
|
*/
|
|
if ( dimy > 4 )
|
|
if (derivatives[1] != NODERIVATIVE)
|
|
if (filterCoefs[1] > 0.0) {
|
|
|
|
if ( _VERBOSE_ != 0 )
|
|
fprintf( stderr, " %s: processing along Y.\n", proc );
|
|
|
|
RFC = InitRecursiveCoefficients( (double)filterCoefs[1], filterType, derivatives[1] );
|
|
|
|
if ( RFC == NULL ) {
|
|
if ( _VERBOSE_ != 0 )
|
|
fprintf( stderr, " %s: unable to allocate coefficients\n", proc );
|
|
if ( (typeOut != CGAL_FLOAT) && (typeOut != CGAL_DOUBLE) )
|
|
free( bufferResult );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
r64firstPoint = (r64*)bufferToBeProcessed;
|
|
r32firstPoint = (r32*)bufferToBeProcessed;
|
|
|
|
r64firstPointResult = (r64*)bufferResult;
|
|
r32firstPointResult = (r32*)bufferResult;
|
|
|
|
offsetLastPoint = borderYlength + dimy - 1;
|
|
offsetNextFirstPoint = dimx * dimy - dimx;
|
|
|
|
theLinePlusBorder = theLine + borderYlength;
|
|
resLinePlusBorder = resLine + borderYlength;
|
|
|
|
/*
|
|
* There are dimz*dimx Y lines to be processed.
|
|
*/
|
|
for ( z=0; z<dimz; z++ ) {
|
|
for ( x=0; x<dimx; x++ ) {
|
|
/*
|
|
* Acquiring a Y line.
|
|
*/
|
|
dbl_pt1 = theLinePlusBorder;
|
|
switch ( typeToBeProcessed ) {
|
|
case CGAL_DOUBLE :
|
|
r64_pt = r64firstPoint;
|
|
for ( y=0; y<dimy; y++, dbl_pt1++, r64_pt += dimx ) *dbl_pt1 = *r64_pt;
|
|
/*
|
|
* Going to the first point of the next Y line
|
|
*/
|
|
r64firstPoint ++;
|
|
break;
|
|
case CGAL_FLOAT :
|
|
default :
|
|
r32_pt = r32firstPoint;
|
|
for ( y=0; y<dimy; y++, dbl_pt1++, r32_pt += dimx ) *dbl_pt1 = *r32_pt;
|
|
r32firstPoint ++;
|
|
}
|
|
/*
|
|
* Adding points at both ends of the line.
|
|
*/
|
|
if ( borderYlength > 0 ) {
|
|
dbl_pt1 = theLine + borderYlength; dbl_first = *dbl_pt1;
|
|
dbl_pt2 = theLine + offsetLastPoint; dbl_last = *dbl_pt2;
|
|
for ( y=0; y<borderYlength; y++ ) {
|
|
*--dbl_pt1 = dbl_first;
|
|
*++dbl_pt2 = dbl_last;
|
|
}
|
|
}
|
|
/*
|
|
* Processing the line.
|
|
*/
|
|
if ( RecursiveFilter1D( RFC, theLine, resLine, tmpLine, resLine, lengthY ) == 0 ) {
|
|
if ( _VERBOSE_ != 0 )
|
|
fprintf(stderr," Error in %s: unable to process Y line (x=%d,z=%d).\n", proc, x, z);
|
|
if ( (typeOut != CGAL_FLOAT) && (typeOut != CGAL_DOUBLE) )
|
|
free( bufferResult );
|
|
free( (void*)theLine );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
/*
|
|
* Copy the result into the buffer bufferResult.
|
|
*/
|
|
dbl_pt1 = resLinePlusBorder;
|
|
switch ( typeResult ) {
|
|
case CGAL_DOUBLE :
|
|
r64_pt = r64firstPointResult;
|
|
for ( y=0; y<dimy; y++, dbl_pt1++, r64_pt += dimx ) *r64_pt = *dbl_pt1;
|
|
r64firstPointResult ++;
|
|
break;
|
|
case CGAL_FLOAT :
|
|
default :
|
|
r32_pt = r32firstPointResult;
|
|
for ( y=0; y<dimy; y++, dbl_pt1++, r32_pt += dimx )
|
|
*r32_pt = (float)*dbl_pt1;
|
|
r32firstPointResult ++;
|
|
}
|
|
}
|
|
/*
|
|
* Going to the first point of the next Y line
|
|
* which is the first Y line of the next slice.
|
|
*
|
|
* The pointer r[32,64]firstPoint[Result] has
|
|
* already been increased by dimx. To reach
|
|
* the first point of the next slice, we
|
|
* have to increase it by (dimx*dimy)-dimx.
|
|
*/
|
|
switch ( typeToBeProcessed ) {
|
|
case CGAL_DOUBLE :
|
|
r64firstPoint += offsetNextFirstPoint;
|
|
break;
|
|
case CGAL_FLOAT :
|
|
default :
|
|
r32firstPoint += offsetNextFirstPoint;
|
|
}
|
|
switch ( typeResult ) {
|
|
case CGAL_DOUBLE :
|
|
r64firstPointResult += offsetNextFirstPoint;
|
|
break;
|
|
case CGAL_FLOAT :
|
|
default :
|
|
r32firstPointResult += offsetNextFirstPoint;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* The next buffer to be processed is the buffer
|
|
* bufferResult.
|
|
*/
|
|
bufferToBeProcessed = bufferResult;
|
|
typeToBeProcessed = typeResult;
|
|
|
|
free( RFC );
|
|
RFC = NULL;
|
|
|
|
} /* end of Processing along Y. */
|
|
|
|
|
|
/*
|
|
* Processing along Z.
|
|
*/
|
|
if ( dimz > 4 )
|
|
if (derivatives[2] != NODERIVATIVE)
|
|
if (filterCoefs[2] > 0.0) {
|
|
|
|
if ( _VERBOSE_ != 0 )
|
|
fprintf( stderr, " %s: processing along Z.\n", proc );
|
|
|
|
RFC = InitRecursiveCoefficients( (double)filterCoefs[2], filterType, derivatives[2] );
|
|
|
|
if ( RFC == NULL ) {
|
|
if ( _VERBOSE_ != 0 )
|
|
fprintf( stderr, " %s: unable to allocate coefficients\n", proc );
|
|
if ( (typeOut != CGAL_FLOAT) && (typeOut != CGAL_DOUBLE) )
|
|
free( bufferResult );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
r64firstPoint = (r64*)bufferToBeProcessed;
|
|
r32firstPoint = (r32*)bufferToBeProcessed;
|
|
|
|
offsetLastPoint = borderZlength + dimz - 1;
|
|
|
|
r64firstPointResult = (r64*)bufferResult;
|
|
r32firstPointResult = (r32*)bufferResult;
|
|
|
|
offsetLastPoint = borderZlength + dimz - 1;
|
|
|
|
theLinePlusBorder = theLine + borderYlength;
|
|
resLinePlusBorder = resLine + borderYlength;
|
|
|
|
/*
|
|
* There are dimy*dimx Z lines to be processed.
|
|
*/
|
|
for ( y=0; y<dimy; y++ )
|
|
for ( x=0; x<dimx; x++ ) {
|
|
/*
|
|
* Acquiring a Z line.
|
|
*/
|
|
dbl_pt1 = theLinePlusBorder;
|
|
switch ( typeToBeProcessed ) {
|
|
case CGAL_DOUBLE :
|
|
r64_pt = r64firstPoint;
|
|
for ( z=0; z<dimz; z++, dbl_pt1++, r64_pt += dimxXdimy ) *dbl_pt1 = *r64_pt;
|
|
/*
|
|
* Going to the first point of the next Z line
|
|
*/
|
|
r64firstPoint ++;
|
|
break;
|
|
case CGAL_FLOAT :
|
|
default :
|
|
r32_pt = r32firstPoint;
|
|
for ( z=0; z<dimz; z++, dbl_pt1++, r32_pt += dimxXdimy ) *dbl_pt1 = *r32_pt;
|
|
r32firstPoint ++;
|
|
}
|
|
/*
|
|
* Adding points at both ends of the line.
|
|
*/
|
|
if ( borderZlength > 0 ) {
|
|
dbl_pt1 = theLine + borderZlength; dbl_first = *dbl_pt1;
|
|
dbl_pt2 = theLine + offsetLastPoint; dbl_last = *dbl_pt2;
|
|
for ( z=0; z<borderZlength; z++ ) {
|
|
*--dbl_pt1 = dbl_first;
|
|
*++dbl_pt2 = dbl_last;
|
|
}
|
|
}
|
|
/*
|
|
* Processing the line.
|
|
*/
|
|
if ( RecursiveFilter1D( RFC, theLine, resLine, tmpLine, resLine, lengthZ ) == 0 ) {
|
|
if ( _VERBOSE_ != 0 )
|
|
fprintf(stderr," Error in %s: unable to process Z line (x=%d,y=%d).\n", proc, x, y);
|
|
if ( (typeOut != CGAL_FLOAT) && (typeOut != CGAL_DOUBLE) )
|
|
free( bufferResult );
|
|
free( (void*)theLine );
|
|
return( EXIT_ON_FAILURE );
|
|
}
|
|
|
|
/*
|
|
* Copy the result into the buffer bufferResult.
|
|
*/
|
|
dbl_pt1 = resLinePlusBorder;
|
|
switch ( typeResult ) {
|
|
case CGAL_DOUBLE :
|
|
r64_pt = r64firstPointResult;
|
|
for ( z=0; z<dimz; z++, dbl_pt1++, r64_pt += dimxXdimy )
|
|
*r64_pt = *dbl_pt1;
|
|
r64firstPointResult ++;
|
|
break;
|
|
case CGAL_FLOAT :
|
|
default :
|
|
r32_pt = r32firstPointResult;
|
|
for ( z=0; z<dimz; z++, dbl_pt1++, r32_pt += dimxXdimy )
|
|
*r32_pt = (float)*dbl_pt1;
|
|
r32firstPointResult ++;
|
|
}
|
|
}
|
|
|
|
free( RFC );
|
|
RFC = NULL;
|
|
|
|
} /* end of Processing along Z. */
|
|
|
|
|
|
|
|
|
|
/*
|
|
* From bufferResult to bufferOut
|
|
*/
|
|
ConvertBuffer( bufferResult, typeResult, bufferOut, typeOut, (dimx*dimy*dimz) );
|
|
|
|
/*
|
|
* Releasing the buffers.
|
|
*/
|
|
if ( (typeOut != CGAL_FLOAT) && (typeOut != CGAL_DOUBLE) )
|
|
free( bufferResult );
|
|
free( (void*)theLine );
|
|
|
|
return( EXIT_ON_SUCCESS );
|
|
}
|
|
|
|
CGAL_INLINE_FUNCTION
|
|
void Recbuffer_verbose ( )
|
|
{
|
|
get_static_verbose_recbuffer() = 1;
|
|
Recline_verbose ( );
|
|
}
|
|
|
|
CGAL_INLINE_FUNCTION
|
|
void Recbuffer_noverbose ( )
|
|
{
|
|
get_static_verbose_recbuffer() = 0;
|
|
Recline_noverbose ( );
|
|
}
|