Alien-FreeImage

 view release on metacpan or  search on metacpan

src/Source/FreeImageToolkit/BSplineRotate.cpp  view on Meta::CPAN


/* 
==========================================================
This code was taken and adapted from the following reference : 

[1] Philippe Thévenaz, Spline interpolation, a C source code 
implementation. http://bigwww.epfl.ch/thevenaz/

It implements ideas described in the following papers : 

[2] Unser M., Splines: A Perfect Fit for Signal and Image Processing. 
IEEE Signal Processing Magazine, vol. 16, no. 6, pp. 22-38, November 1999. 

[3] Unser M., Aldroubi A., Eden M., B-Spline Signal Processing: Part I--Theory.
IEEE Transactions on Signal Processing, vol. 41, no. 2, pp. 821-832, February 1993. 

[4] Unser M., Aldroubi A., Eden M., B-Spline Signal Processing: Part II--Efficient Design and Applications.
IEEE Transactions on Signal Processing, vol. 41, no. 2, pp. 834-848, February 1993.

========================================================== 
*/


#include <float.h>
#include "FreeImage.h"
#include "Utilities.h"

#define PI	((double)3.14159265358979323846264338327950288419716939937510)

#define ROTATE_QUADRATIC 2L	// Use B-splines of degree 2 (quadratic interpolation)
#define ROTATE_CUBIC     3L	// Use B-splines of degree 3 (cubic interpolation)
#define ROTATE_QUARTIC   4L	// Use B-splines of degree 4 (quartic interpolation)
#define ROTATE_QUINTIC   5L	// Use B-splines of degree 5 (quintic interpolation)


/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Prototypes definition

static void ConvertToInterpolationCoefficients(double *c, long DataLength, double *z, long NbPoles,	double Tolerance);
static double InitialCausalCoefficient(double *c, long DataLength, double z, double Tolerance);
static void GetColumn(double *Image, long Width, long x, double *Line, long Height);
static void	GetRow(double *Image, long y, double *Line, long Width);
static double InitialAntiCausalCoefficient(double *c, long DataLength, double z);
static void	PutColumn(double *Image, long Width, long x, double *Line, long Height);
static void	PutRow(double *Image, long y, double *Line, long Width);
static bool SamplesToCoefficients(double *Image, long Width, long Height, long spline_degree);
static double InterpolatedValue(double *Bcoeff, long Width, long Height, double x, double y, long spline_degree);

static FIBITMAP * Rotate8Bit(FIBITMAP *dib, double angle, double x_shift, double y_shift, double x_origin, double y_origin, long spline_degree, BOOL use_mask);

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Coefficients routines

/**
 ConvertToInterpolationCoefficients

 @param c Input samples --> output coefficients
 @param DataLength Number of samples or coefficients
 @param z Poles
 @param NbPoles Number of poles
 @param Tolerance Admissible relative error
*/
static void 
ConvertToInterpolationCoefficients(double *c, long DataLength, double *z, long NbPoles,	double Tolerance) {
	double	Lambda = 1;
	long	n, k;

	// special case required by mirror boundaries
	if(DataLength == 1L) {
		return;
	}
	// compute the overall gain
	for(k = 0L; k < NbPoles; k++) {
		Lambda = Lambda * (1.0 - z[k]) * (1.0 - 1.0 / z[k]);
	}
	// apply the gain 
	for (n = 0L; n < DataLength; n++) {
		c[n] *= Lambda;
	}
	// loop over all poles 
	for (k = 0L; k < NbPoles; k++) {
		// causal initialization 
		c[0] = InitialCausalCoefficient(c, DataLength, z[k], Tolerance);
		// causal recursion 
		for (n = 1L; n < DataLength; n++) {
			c[n] += z[k] * c[n - 1L];
		}
		// anticausal initialization 
		c[DataLength - 1L] = InitialAntiCausalCoefficient(c, DataLength, z[k]);
		// anticausal recursion 
		for (n = DataLength - 2L; 0 <= n; n--) {
			c[n] = z[k] * (c[n + 1L] - c[n]);
		}
	}
} 

/**
 InitialCausalCoefficient

 @param c Coefficients
 @param DataLength Number of coefficients
 @param z Actual pole
 @param Tolerance Admissible relative error
 @return
*/
static double 
InitialCausalCoefficient(double	*c, long DataLength, double	z, double Tolerance) {
	double	Sum, zn, z2n, iz;
	long	n, Horizon;

	// this initialization corresponds to mirror boundaries 
	Horizon = DataLength;
	if(Tolerance > 0) {
		Horizon = (long)ceil(log(Tolerance) / log(fabs(z)));
	}
	if(Horizon < DataLength) {
		// accelerated loop
		zn = z;
		Sum = c[0];
		for (n = 1L; n < Horizon; n++) {
			Sum += zn * c[n];
			zn *= z;
		}
		return(Sum);
	}
	else {
		// full loop 
		zn = z;
		iz = 1.0 / z;
		z2n = pow(z, (double)(DataLength - 1L));
		Sum = c[0] + z2n * c[DataLength - 1L];
		z2n *= z2n * iz;
		for (n = 1L; n <= DataLength - 2L; n++) {
			Sum += (zn + z2n) * c[n];
			zn *= z;
			z2n *= iz;
		}
		return(Sum / (1.0 - zn * zn));
	}
}

/**
 GetColumn

 @param Image Input image array
 @param Width Width of the image
 @param x x coordinate of the selected line
 @param Line Output linear array
 @param Height Length of the line
*/
static void 
GetColumn(double *Image, long Width, long x, double *Line, long Height) {
	long y;

	Image = Image + x;
	for(y = 0L; y < Height; y++) {
		Line[y] = (double)*Image;
		Image += Width;
	}
}

/**
 GetRow



( run in 1.105 second using v1.01-cache-2.11-cpan-5735350b133 )