Added lbb resampler; Removed mbicubic resampler

This commit is contained in:
Nicolas Robidoux 2010-03-23 05:44:40 +00:00
parent 8556cc7c4a
commit 60c62a583d
4 changed files with 743 additions and 649 deletions

View File

@ -2,7 +2,7 @@
if ENABLE_CXX
C_SOURCES = \
bicubic.cpp \
mbicubic.cpp \
lbb.cpp \
yafrsmooth.cpp \
nohalo1.cpp \
snohalo1.cpp \
@ -13,7 +13,7 @@ else
C_SOURCES =
C_DIST = \
bicubic.cpp \
mbicubic.cpp \
lbb.cpp \
yafrsmooth.cpp \
nohalo1.cpp \
snohalo1.cpp \

View File

@ -497,7 +497,7 @@ void
vips__interpolate_init( void )
{
extern GType vips_interpolate_bicubic_get_type( void );
extern GType vips_interpolate_mbicubic_get_type( void );
extern GType vips_interpolate_lbb_get_type( void );
extern GType vips_interpolate_yafrsmooth_get_type( void );
extern GType vips_interpolate_nohalo1_get_type( void );
extern GType vips_interpolate_snohalo1_get_type( void );
@ -508,7 +508,7 @@ vips__interpolate_init( void )
#ifdef ENABLE_CXX
vips_interpolate_bicubic_get_type();
vips_interpolate_mbicubic_get_type();
vips_interpolate_lbb_get_type();
vips_interpolate_yafrsmooth_get_type();
vips_interpolate_nohalo1_get_type();
vips_interpolate_snohalo1_get_type();

739
libvips/resample/lbb.cpp Normal file
View File

@ -0,0 +1,739 @@
/* locally bounded bicubic resampler
*/
/*
This file is part of VIPS.
VIPS is free software; 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 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
* 2009-2010 (c) Nicolas Robidoux, John Cupitt, Chantal Racette.
*
* Nicolas Robidoux thanks Ralf Meyer, Minglun Gong, Adam Turcotte,
* Eric Daoust, Øyvind Kolås, Geert Jordaens, and Sven Neumann for
* useful comments and code.
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "templates.h"
#define VIPS_TYPE_INTERPOLATE_LBB \
(vips_interpolate_lbb_get_type())
#define VIPS_INTERPOLATE_LBB( obj ) \
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
VIPS_TYPE_INTERPOLATE_LBB, VipsInterpolateLbb ))
#define VIPS_INTERPOLATE_LBB_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_CAST( (klass), \
VIPS_TYPE_INTERPOLATE_LBB, VipsInterpolateLbbClass))
#define VIPS_IS_INTERPOLATE_LBB( obj ) \
(G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_INTERPOLATE_LBB ))
#define VIPS_IS_INTERPOLATE_LBB_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_INTERPOLATE_LBB ))
#define VIPS_INTERPOLATE_LBB_GET_CLASS( obj ) \
(G_TYPE_INSTANCE_GET_CLASS( (obj), \
VIPS_TYPE_INTERPOLATE_LBB, VipsInterpolateLbbClass ))
typedef struct _VipsInterpolateLbb {
VipsInterpolate parent_object;
} VipsInterpolateLbb;
typedef struct _VipsInterpolateLbbClass {
VipsInterpolateClass parent_class;
} VipsInterpolateLbbClass;
static inline double
lbbicubic( const double c00,
const double c10,
const double c01,
const double c11,
const double c00dx,
const double c10dx,
const double c01dx,
const double c11dx,
const double c00dy,
const double c10dy,
const double c01dy,
const double c11dy,
const double c00dxdy,
const double c10dxdy,
const double c01dxdy,
const double c11dxdy,
const double uno_one,
const double uno_two,
const double uno_thr,
const double uno_fou,
const double dos_one,
const double dos_two,
const double dos_thr,
const double dos_fou,
const double tre_one,
const double tre_two,
const double tre_thr,
const double tre_fou,
const double qua_one,
const double qua_two,
const double qua_thr,
const double qua_fou )
{
/*
* STENCIL (FOOTPRINT) OF INPUT VALUES:
*
* The stencil of Symmetrized Monotone Catmull-Rom is the same as
* the standard Catmull-Rom's:
*
* (ix-1,iy-1) (ix,iy-1) (ix+1,iy-1) (ix+2,iy-1)
* = uno_one = uno_two = uno_thr = uno_fou
*
* (ix-1,iy) (ix,iy) (ix+1,iy) (ix+2,iy)
* = dos_one = dos_two = dos_thr = dos_fou
* X
* (ix-1,iy+1) (ix,iy+1) (ix+1,iy+1) (ix+2,iy+1)
* = tre_one = tre_two = tre_thr = tre_fou
*
* (ix-1,iy+2) (ix,iy+2) (ix+1,iy+2) (ix+2,iy+2)
* = qua_one = qua_two = qua_thr = qua_fou
*
* where ix is the (pseudo-)floor of the requested left-to-right
* location ("X"), and iy is the floor of the requested up-to-down
* location.
*/
/*
* Computation of the four min and four max over 3x3 input data
* sub-blocks of the 4x4 input stencil (involves 28 flag
* computations):
*/
const double m1 = (dos_two <= dos_thr) ? dos_two : dos_thr;
const double M1 = (dos_two <= dos_thr) ? dos_thr : dos_two;
const double m2 = (tre_two <= tre_thr) ? tre_two : tre_thr;
const double M2 = (tre_two <= tre_thr) ? tre_thr : tre_two;
const double m3 = (uno_two <= uno_thr) ? uno_two : uno_thr;
const double M3 = (uno_two <= uno_thr) ? uno_thr : uno_two;
const double m4 = (qua_two <= qua_thr) ? qua_two : qua_thr;
const double M4 = (qua_two <= qua_thr) ? qua_thr : qua_two;
const double m5 = (m1 <= m2 ) ? m1 : m2 ;
const double M5 = (M1 >= M2 ) ? M1 : M2 ;
const double m6 = (dos_one <= tre_one) ? dos_one : tre_one;
const double M6 = (dos_one <= tre_one) ? tre_one : dos_one;
const double m7 = (dos_fou <= tre_fou) ? dos_fou : tre_fou;
const double M7 = (dos_fou <= tre_fou) ? tre_fou : dos_fou;
const double m8 = (m5 <= m3 ) ? m5 : m3 ;
const double M8 = (M5 >= M3 ) ? M5 : M3 ;
const double m9 = (m5 <= m4 ) ? m5 : m4 ;
const double M9 = (M5 >= M4 ) ? M5 : M4 ;
const double m10 = (m6 <= uno_one) ? m6 : uno_one;
const double M10 = (M6 >= uno_one) ? M6 : uno_one;
const double m11 = (m7 <= uno_fou) ? m7 : uno_fou;
const double M11 = (M7 >= uno_fou) ? M7 : uno_fou;
const double m12 = (m6 <= qua_one) ? m6 : qua_one;
const double M12 = (M6 >= qua_one) ? M6 : qua_one;
const double m13 = (m7 <= qua_fou) ? m7 : qua_fou;
const double M13 = (M7 >= qua_fou) ? M7 : qua_fou;
const double min00 = (m8 <= m10 ) ? m8 : m10 ;
const double max00 = (M8 >= M10 ) ? M8 : M10 ;
const double min10 = (m8 <= m11 ) ? m8 : m11 ;
const double max10 = (M8 >= M11 ) ? M8 : M11 ;
const double min01 = (m9 <= m12 ) ? m9 : m12 ;
const double max01 = (M9 >= M12 ) ? M9 : M12 ;
const double min11 = (m9 <= m13 ) ? m9 : m13 ;
const double max11 = (M9 >= M13 ) ? M9 : M13 ;
/*
* Distances to the local min and max:
*/
const double u00 = dos_two - min00;
const double v00 = max00 - dos_two;
const double u10 = dos_thr - min10;
const double v10 = max10 - dos_thr;
const double u01 = tre_two - min01;
const double v01 = max01 - tre_two;
const double u11 = tre_thr - min11;
const double v11 = max11 - tre_thr;
/*
* Initial values of the derivatives computed with centered
* differences. Factors of 1/2 are left out because they are folded
* in later:
*/
const double dble_dzdx00i = dos_thr - dos_one;
const double dble_dzdx10i = dos_fou - dos_two;
const double dble_dzdx01i = tre_thr - tre_one;
const double dble_dzdx11i = tre_fou - tre_two;
const double dble_dzdy00i = tre_two - uno_two;
const double dble_dzdy10i = tre_thr - uno_thr;
const double dble_dzdy01i = qua_two - dos_two;
const double dble_dzdy11i = qua_thr - dos_thr;
/*
* Signs of the derivatives:
*/
const double sign_dzdx00 = (dble_dzdx00i >= 0.) ? 1. : -1.;
const double sign_dzdx10 = (dble_dzdx10i >= 0.) ? 1. : -1.;
const double sign_dzdx01 = (dble_dzdx01i >= 0.) ? 1. : -1.;
const double sign_dzdx11 = (dble_dzdx11i >= 0.) ? 1. : -1.;
const double sign_dzdy00 = (dble_dzdy00i >= 0.) ? 1. : -1.;
const double sign_dzdy10 = (dble_dzdy10i >= 0.) ? 1. : -1.;
const double sign_dzdy01 = (dble_dzdy01i >= 0.) ? 1. : -1.;
const double sign_dzdy11 = (dble_dzdy11i >= 0.) ? 1. : -1.;
/*
* Slope limiters. The key multiplier is 3 but we fold a factor of
* 2, hence 6:
*/
const double dble_slopelimit_00 = 6.0 * ( (u00 <= v00) ? u00 : v00 );
const double dble_slopelimit_10 = 6.0 * ( (u10 <= v10) ? u10 : v10 );
const double dble_slopelimit_01 = 6.0 * ( (u01 <= v01) ? u01 : v01 );
const double dble_slopelimit_11 = 6.0 * ( (u11 <= v11) ? u11 : v11 );
/*
* Initial values of the cross-derivatives. Factors of 1/4 are left
* out because folded in later:
*/
const double quad_d2zdxdy00i = ( uno_one - uno_thr ) + dble_dzdx01i;
const double quad_d2zdxdy10i = ( uno_two - uno_fou ) + dble_dzdx11i;
const double quad_d2zdxdy01i = ( qua_thr - qua_one ) - dble_dzdx00i;
const double quad_d2zdxdy11i = ( qua_fou - qua_two ) - dble_dzdx10i;
/*
* Part of the result which does not need derivatives:
*/
const double newval1 = c00 * dos_two
+
c10 * dos_thr
+
c01 * tre_two
+
c11 * tre_thr;
/*
* Clamped first derivatives:
*/
const double dble_dzdx00 =
( sign_dzdx00 * dble_dzdx00i <= dble_slopelimit_00 )
? dble_dzdx00i : sign_dzdx00 * dble_slopelimit_00;
const double dble_dzdx10 =
( sign_dzdx10 * dble_dzdx10i <= dble_slopelimit_10 )
? dble_dzdx10i : sign_dzdx10 * dble_slopelimit_10;
const double dble_dzdx01 =
( sign_dzdx01 * dble_dzdx01i <= dble_slopelimit_01 )
? dble_dzdx01i : sign_dzdx01 * dble_slopelimit_01;
const double dble_dzdx11 =
( sign_dzdx11 * dble_dzdx11i <= dble_slopelimit_11 )
? dble_dzdx11i : sign_dzdx11 * dble_slopelimit_11;
const double dble_dzdy00 =
( sign_dzdy00 * dble_dzdy00i <= dble_slopelimit_00 )
? dble_dzdy00i : sign_dzdy00 * dble_slopelimit_00;
const double dble_dzdy10 =
( sign_dzdy10 * dble_dzdy10i <= dble_slopelimit_10 )
? dble_dzdy10i : sign_dzdy10 * dble_slopelimit_10;
const double dble_dzdy01 =
( sign_dzdy01 * dble_dzdy01i <= dble_slopelimit_01 )
? dble_dzdy01i : sign_dzdy01 * dble_slopelimit_01;
const double dble_dzdy11 =
( sign_dzdy11 * dble_dzdy11i <= dble_slopelimit_11 )
? dble_dzdy11i : sign_dzdy11 * dble_slopelimit_11;
/*
* Sums and differences of first derivatives:
*/
const double twelve_sum00 = 6.0 * ( dble_dzdx00 + dble_dzdy00 );
const double twelve_dif00 = 6.0 * ( dble_dzdx00 - dble_dzdy00 );
const double twelve_sum10 = 6.0 * ( dble_dzdx10 + dble_dzdy10 );
const double twelve_dif10 = 6.0 * ( dble_dzdx10 - dble_dzdy10 );
const double twelve_sum01 = 6.0 * ( dble_dzdx01 + dble_dzdy01 );
const double twelve_dif01 = 6.0 * ( dble_dzdx01 - dble_dzdy01 );
const double twelve_sum11 = 6.0 * ( dble_dzdx11 + dble_dzdy11 );
const double twelve_dif11 = 6.0 * ( dble_dzdx11 - dble_dzdy11 );
/*
* Part of the result which only needs first derivatives.
*/
const double newval2 = c00dx * dble_dzdx00
+
c10dx * dble_dzdx10
+
c01dx * dble_dzdx01
+
c11dx * dble_dzdx11
+
c00dy * dble_dzdy00
+
c10dy * dble_dzdy10
+
c01dy * dble_dzdy01
+
c11dy * dble_dzdy11;
/*
* Absolute values of the sums:
*/
const double twelve_abs_sum00 =
(twelve_sum00 >= 0.0) ? twelve_sum00 : -twelve_sum00;
const double twelve_abs_sum10 =
(twelve_sum10 >= 0.0) ? twelve_sum10 : -twelve_sum10;
const double twelve_abs_sum01 =
(twelve_sum01 >= 0.0) ? twelve_sum01 : -twelve_sum01;
const double twelve_abs_sum11 =
(twelve_sum11 >= 0.0) ? twelve_sum11 : -twelve_sum11;
/*
* Scaled 'u' differences:
*/
const double u00_times_36 = 36. * u00;
const double u10_times_36 = 36. * u10;
const double u01_times_36 = 36. * u01;
const double u11_times_36 = 36. * u11;
/*
* First cross-derivative limiter:
*/
const double first_limit00 = twelve_abs_sum00 - u00_times_36;
const double first_limit10 = twelve_abs_sum10 - u10_times_36;
const double first_limit01 = twelve_abs_sum01 - u01_times_36;
const double first_limit11 = twelve_abs_sum11 - u11_times_36;
const double quad_d2zdxdy00ii =
(quad_d2zdxdy00i >= first_limit00)
? quad_d2zdxdy00i : first_limit00;
const double quad_d2zdxdy10ii =
(quad_d2zdxdy10i >= first_limit10)
? quad_d2zdxdy10i : first_limit10;
const double quad_d2zdxdy01ii =
(quad_d2zdxdy01i >= first_limit01)
? quad_d2zdxdy01i : first_limit01;
const double quad_d2zdxdy11ii =
(quad_d2zdxdy11i >= first_limit11)
? quad_d2zdxdy11i : first_limit11;
/*
* Absolute values of the differences:
*/
const double twelve_abs_dif00 =
(twelve_dif00 >= 0.0) ? twelve_dif00 : -twelve_dif00;
const double twelve_abs_dif10 =
(twelve_dif10 >= 0.0) ? twelve_dif10 : -twelve_dif10;
const double twelve_abs_dif01 =
(twelve_dif01 >= 0.0) ? twelve_dif01 : -twelve_dif01;
const double twelve_abs_dif11 =
(twelve_dif11 >= 0.0) ? twelve_dif11 : -twelve_dif11;
/*
* Scaled 'v' differences:
*/
const double v00_times_36 = 36. * v00;
const double v10_times_36 = 36. * v10;
const double v01_times_36 = 36. * v01;
const double v11_times_36 = 36. * v11;
/*
* Second cross-derivative limiter:
*/
const double second_limit00 = v00_times_36 - twelve_abs_sum00;
const double second_limit10 = v10_times_36 - twelve_abs_sum10;
const double second_limit01 = v01_times_36 - twelve_abs_sum01;
const double second_limit11 = v11_times_36 - twelve_abs_sum11;
const double quad_d2zdxdy00iii =
(quad_d2zdxdy00ii <= second_limit00)
? quad_d2zdxdy00ii : second_limit00;
const double quad_d2zdxdy10iii =
(quad_d2zdxdy10ii <= second_limit10)
? quad_d2zdxdy10ii : second_limit10;
const double quad_d2zdxdy01iii =
(quad_d2zdxdy01ii <= second_limit01)
? quad_d2zdxdy01ii : second_limit01;
const double quad_d2zdxdy11iii =
(quad_d2zdxdy11ii <= second_limit11)
? quad_d2zdxdy11ii : second_limit11;
/*
* Third cross-derivative limiter:
*/
const double third_limit00 = u00_times_36 - twelve_abs_dif00;
const double third_limit10 = u10_times_36 - twelve_abs_dif10;
const double third_limit01 = u01_times_36 - twelve_abs_dif01;
const double third_limit11 = u11_times_36 - twelve_abs_dif11;
const double quad_d2zdxdy00iiii =
(quad_d2zdxdy00iii <= third_limit00)
? quad_d2zdxdy00iii : third_limit00;
const double quad_d2zdxdy10iiii =
(quad_d2zdxdy10iii <= third_limit10)
? quad_d2zdxdy10iii : third_limit10;
const double quad_d2zdxdy01iiii =
(quad_d2zdxdy01iii <= third_limit01)
? quad_d2zdxdy01iii : third_limit01;
const double quad_d2zdxdy11iiii =
(quad_d2zdxdy11iii <= third_limit11)
? quad_d2zdxdy11iii : third_limit11;
/*
* Fourth cross-derivative limiter:
*/
const double fourth_limit00 = twelve_abs_dif00 - v00_times_36;
const double fourth_limit10 = twelve_abs_dif10 - v10_times_36;
const double fourth_limit01 = twelve_abs_dif01 - v01_times_36;
const double fourth_limit11 = twelve_abs_dif11 - v11_times_36;
const double quad_d2zdxdy00 =
(quad_d2zdxdy00iiii >= fourth_limit00)
? quad_d2zdxdy00iiii : fourth_limit00;
const double quad_d2zdxdy10 =
(quad_d2zdxdy10iiii >= fourth_limit10)
? quad_d2zdxdy10iiii : fourth_limit10;
const double quad_d2zdxdy01 =
(quad_d2zdxdy01iiii >= fourth_limit01)
? quad_d2zdxdy01iiii : fourth_limit01;
const double quad_d2zdxdy11 =
(quad_d2zdxdy11iiii >= fourth_limit11)
? quad_d2zdxdy11iiii : fourth_limit11;
/*
* Four times the part of the result which only uses cross
* derivatives:
*/
const double newval3 = c00dxdy * quad_d2zdxdy00
+
c10dxdy * quad_d2zdxdy10
+
c01dxdy * quad_d2zdxdy01
+
c11dxdy * quad_d2zdxdy11;
const double newval = newval1 + .5 * newval2 + .25 * newval3;
return newval;
}
/*
* Call lbb with a type conversion operator as a parameter.
*
* It would be nice to do this with templates somehow---for one thing
* this would allow code comments!---but we can't figure a clean way
* to do it.
*/
#define LBB_CONVERSION( conversion ) \
template <typename T> static void inline \
lbb_ ## conversion( PEL* restrict pout, \
const PEL* restrict pin, \
const int bands, \
const int lskip, \
const double relative_x, \
const double relative_y ) \
{ \
T* restrict out = (T *) pout; \
\
const T* restrict in = (T *) pin; \
\
const int one_shift = -bands; \
const int thr_shift = bands; \
const int fou_shift = 2*bands; \
\
const int uno_two_shift = -lskip; \
const int dos_two_shift = 0; \
const int tre_two_shift = lskip; \
const int qua_two_shift = 2*lskip; \
\
const int uno_one_shift = uno_two_shift + one_shift; \
const int dos_one_shift = dos_two_shift + one_shift; \
const int tre_one_shift = tre_two_shift + one_shift; \
const int qua_one_shift = qua_two_shift + one_shift; \
\
const int uno_thr_shift = uno_two_shift + thr_shift; \
const int dos_thr_shift = dos_two_shift + thr_shift; \
const int tre_thr_shift = tre_two_shift + thr_shift; \
const int qua_thr_shift = qua_two_shift + thr_shift; \
\
const int uno_fou_shift = uno_two_shift + fou_shift; \
const int dos_fou_shift = dos_two_shift + fou_shift; \
const int tre_fou_shift = tre_two_shift + fou_shift; \
const int qua_fou_shift = qua_two_shift + fou_shift; \
\
const double xp1over2 = relative_x; \
const double xm1over2 = xp1over2 - 1.0; \
const double onemx = 1.5 - xp1over2; \
const double onepx = 0.5 + xp1over2; \
const double xp1over2sq = xp1over2 * xp1over2; \
\
const double yp1over2 = relative_y; \
const double ym1over2 = yp1over2 - 1.0; \
const double onemy = 1.5 - yp1over2; \
const double onepy = 0.5 + yp1over2; \
const double yp1over2sq = yp1over2 * yp1over2; \
\
const double xm1over2sq = xm1over2 * xm1over2; \
const double ym1over2sq = ym1over2 * ym1over2; \
\
const double twice1mx = onemx + onemx; \
const double twice1px = onepx + onepx; \
const double twice1my = onemy + onemy; \
const double twice1py = onepy + onepy; \
\
const double xm1over2sq_times_ym1over2sq = xm1over2sq * ym1over2sq; \
const double xp1over2sq_times_ym1over2sq = xp1over2sq * ym1over2sq; \
const double xp1over2sq_times_yp1over2sq = xp1over2sq * yp1over2sq; \
const double xm1over2sq_times_yp1over2sq = xm1over2sq * yp1over2sq; \
\
const double xm1over2_times_ym1over2 = xm1over2 * ym1over2; \
const double xp1over2_times_ym1over2 = xp1over2 * ym1over2; \
const double twice_1mx_times_ym1over2 = twice1mx * ym1over2; \
const double twice_1px_times_ym1over2 = twice1px * ym1over2; \
\
const double xm1over2_times_yp1over2 = xm1over2 * yp1over2; \
const double xp1over2_times_yp1over2 = xp1over2 * yp1over2; \
const double twice_1mx_times_yp1over2 = twice1mx * yp1over2; \
const double twice_1px_times_yp1over2 = twice1px * yp1over2; \
\
const double twice_xm1over2_times_1my = xm1over2 * twice1my; \
const double twice_xp1over2_times_1my = xp1over2 * twice1my; \
const double four_times_1mx_times_1my = twice1mx * twice1my; \
const double four_times_1px_times_1my = twice1px * twice1my; \
\
const double twice_xm1over2_times_1py = xm1over2 * twice1py; \
const double twice_xp1over2_times_1py = xp1over2 * twice1py; \
const double four_times_1mx_times_1py = twice1mx * twice1py; \
const double four_times_1px_times_1py = twice1px * twice1py; \
\
const double c00 = \
four_times_1px_times_1py * xm1over2sq_times_ym1over2sq; \
const double c00dx = \
twice_xp1over2_times_1py * xm1over2sq_times_ym1over2sq; \
const double c00dy = \
twice_1px_times_yp1over2 * xm1over2sq_times_ym1over2sq; \
const double c00dxdy = \
xp1over2_times_yp1over2 * xm1over2sq_times_ym1over2sq; \
\
const double c10 = \
four_times_1mx_times_1py * xp1over2sq_times_ym1over2sq; \
const double c10dx = \
twice_xm1over2_times_1py * xp1over2sq_times_ym1over2sq; \
const double c10dy = \
twice_1mx_times_yp1over2 * xp1over2sq_times_ym1over2sq; \
const double c10dxdy = \
xm1over2_times_yp1over2 * xp1over2sq_times_ym1over2sq; \
\
const double c01 = \
four_times_1px_times_1my * xm1over2sq_times_yp1over2sq; \
const double c01dx = \
twice_xp1over2_times_1my * xm1over2sq_times_yp1over2sq; \
const double c01dy = \
twice_1px_times_ym1over2 * xm1over2sq_times_yp1over2sq; \
const double c01dxdy = \
xp1over2_times_ym1over2 * xm1over2sq_times_yp1over2sq; \
\
const double c11 = \
four_times_1mx_times_1my * xp1over2sq_times_yp1over2sq; \
const double c11dx = \
twice_xm1over2_times_1my * xp1over2sq_times_yp1over2sq; \
const double c11dy = \
twice_1mx_times_ym1over2 * xp1over2sq_times_yp1over2sq; \
const double c11dxdy = \
xm1over2_times_ym1over2 * xp1over2sq_times_yp1over2sq; \
\
int band = bands; \
\
do \
{ \
const double double_result = \
lbbicubic( c00, \
c10, \
c01, \
c11, \
c00dx, \
c10dx, \
c01dx, \
c11dx, \
c00dy, \
c10dy, \
c01dy, \
c11dy, \
c00dxdy, \
c10dxdy, \
c01dxdy, \
c11dxdy, \
in[ uno_one_shift ], \
in[ uno_two_shift ], \
in[ uno_thr_shift ], \
in[ uno_fou_shift ], \
in[ dos_one_shift ], \
in[ dos_two_shift ], \
in[ dos_thr_shift ], \
in[ dos_fou_shift ], \
in[ tre_one_shift ], \
in[ tre_two_shift ], \
in[ tre_thr_shift ], \
in[ tre_fou_shift ], \
in[ qua_one_shift ], \
in[ qua_two_shift ], \
in[ qua_thr_shift ], \
in[ qua_fou_shift ] ); \
\
const T result = to_ ## conversion<T>( double_result ); \
in++; \
*out++ = result; \
} while (--band); \
}
LBB_CONVERSION( fptypes )
LBB_CONVERSION( withsign )
LBB_CONVERSION( nosign )
#define CALL( T, conversion ) \
lbb_ ## conversion<T>( out, \
p, \
bands, \
lskip, \
relative_x, \
relative_y );
/*
* We need C linkage:
*/
extern "C" {
G_DEFINE_TYPE( VipsInterpolateLbb, vips_interpolate_lbb,
VIPS_TYPE_INTERPOLATE );
}
static void
vips_interpolate_lbb_interpolate( VipsInterpolate* restrict interpolate,
PEL* restrict out,
REGION* restrict in,
double absolute_x,
double absolute_y )
{
/*
* Floor's surrogate FAST_PSEUDO_FLOOR is used to make sure that the
* transition through 0 is smooth. If it is known that absolute_x
* and absolute_y will never be less than 0, plain cast---that is,
* const int ix = absolute_x---should be used instead. Actually,
* any function which agrees with floor for non-integer values, and
* picks one of the two possibilities for integer values, can be
* used. FAST_PSEUDO_FLOOR fits the bill.
*
* Then, x is the x-coordinate of the sampling point relative to the
* position of the top left corner of the convex hull of the 2x2
* block of closest pixels. Similarly for y. Range of values: [0,1).
*/
const int ix = FAST_PSEUDO_FLOOR( absolute_x );
const int iy = FAST_PSEUDO_FLOOR( absolute_y );
/*
* Move the pointer to (the first band of) the top/left pixel of the
* 2x2 group of pixel centers which contains the sampling location
* in its convex hull:
*/
const PEL* restrict p = (PEL *) IM_REGION_ADDR( in, ix, iy );
const double relative_x = absolute_x - ix;
const double relative_y = absolute_y - iy;
/*
* VIPS versions of Nicolas's pixel addressing values.
*/
const int actual_bands = in->im->Bands;
const int lskip = IM_REGION_LSKIP( in ) / IM_IMAGE_SIZEOF_ELEMENT( in->im );
/*
* Double the bands for complex images to account for the real and
* imaginary parts being computed independently:
*/
const int bands =
vips_bandfmt_iscomplex( in->im->BandFmt ) ? 2 * actual_bands : actual_bands;
switch( in->im->BandFmt ) {
case IM_BANDFMT_UCHAR:
CALL( unsigned char, nosign );
break;
case IM_BANDFMT_CHAR:
CALL( signed char, withsign );
break;
case IM_BANDFMT_USHORT:
CALL( unsigned short, nosign );
break;
case IM_BANDFMT_SHORT:
CALL( signed short, withsign );
break;
case IM_BANDFMT_UINT:
CALL( unsigned int, nosign );
break;
case IM_BANDFMT_INT:
CALL( signed int, withsign );
break;
/*
* Complex images are handled by doubling of bands.
*/
case IM_BANDFMT_FLOAT:
case IM_BANDFMT_COMPLEX:
CALL( float, fptypes );
break;
case IM_BANDFMT_DOUBLE:
case IM_BANDFMT_DPCOMPLEX:
CALL( double, fptypes );
break;
default:
g_assert( 0 );
break;
}
}
static void
vips_interpolate_lbb_class_init( VipsInterpolateLbbClass *klass )
{
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( klass );
VipsInterpolateClass *interpolate_class =
VIPS_INTERPOLATE_CLASS( klass );
object_class->nickname = "lbb";
object_class->description = _( "Reduced halo bicubic" );
interpolate_class->interpolate = vips_interpolate_lbb_interpolate;
interpolate_class->window_size = 4;
}
static void
vips_interpolate_lbb_init( VipsInterpolateLbb *lbb )
{
}

View File

@ -1,645 +0,0 @@
/* symmetrized monotone cubic splines
*/
/*
This file is part of VIPS.
VIPS is free software; 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 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this program; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
* 2009-2010 (c) Nicolas Robidoux, John Cupitt, Eric Daoust and Adam
* Turcotte
*
* E. Daoust and A. Turcotte's symmetrized monotone cubic splines
* programming funded in part by two Google Summer of Code 2010 awards
* made to GIMP (Gnu Image Manipulation Program) and its library GEGL.
*
* Nicolas Robidoux thanks Chantal Racette, Ralf Meyer, Minglun Gong,
* Øyvind Kolås, Geert Jordaens and Sven Neumann for useful comments
* and code.
*/
/*
* mbicubic is the VIPS name of the symmetrized implementation in 2D
* of monotone cubic spline interpolation method a.k.a. MP-Quadratic
* (Monotonicity Preserving with derivative estimated by fitting a
* parabola (quadratic polynomial)) method, which essentially is
* Catmull-Rom with derivatives clamped with Fristsh and Carlson's
* "rule of 3" so as to ensure monotonicity.
*
* 1D MP-quadratic (for curve, not surface, interpolation) is
* described in
*
* Accurate Monotone Cubic Interpolation, by Hung T. Huynh, published
* in the SIAM Journal on Numerical Analysis, Volume 30, Issue 1
* (February 1993), pages 57-100, 1993. ISSN:0036-1429.
*
* and in NASA technical memorandum 103789, which can be downloaded
* from http://
* ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19910011517_1991011517.pdf
*
* In order to ensure reflexion symmetry about diagonal lines, 1D
* MP-quadratic is performed two different ways---horizontally then
* vertically, and vertically then horizontally---and
* averaged. (Symmetry about 45 degree lines is not automatically
* respected because MP-quadratic is a nonlinear method: interpolating
* horizontally then vertically does not necessarily give the same as
* interpolating vertically then horizontally.)
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <vips/vips.h>
#include <vips/internal.h>
#include "templates.h"
#define VIPS_TYPE_INTERPOLATE_MBICUBIC \
(vips_interpolate_mbicubic_get_type())
#define VIPS_INTERPOLATE_MBICUBIC( obj ) \
(G_TYPE_CHECK_INSTANCE_CAST( (obj), \
VIPS_TYPE_INTERPOLATE_MBICUBIC, VipsInterpolateMbicubic ))
#define VIPS_INTERPOLATE_MBICUBIC_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_CAST( (klass), \
VIPS_TYPE_INTERPOLATE_MBICUBIC, VipsInterpolateMbicubicClass))
#define VIPS_IS_INTERPOLATE_MBICUBIC( obj ) \
(G_TYPE_CHECK_INSTANCE_TYPE( (obj), VIPS_TYPE_INTERPOLATE_MBICUBIC ))
#define VIPS_IS_INTERPOLATE_MBICUBIC_CLASS( klass ) \
(G_TYPE_CHECK_CLASS_TYPE( (klass), VIPS_TYPE_INTERPOLATE_MBICUBIC ))
#define VIPS_INTERPOLATE_MBICUBIC_GET_CLASS( obj ) \
(G_TYPE_INSTANCE_GET_CLASS( (obj), \
VIPS_TYPE_INTERPOLATE_MBICUBIC, VipsInterpolateMbicubicClass ))
typedef struct _VipsInterpolateMbicubic {
VipsInterpolate parent_object;
} VipsInterpolateMbicubic;
typedef struct _VipsInterpolateMbicubicClass {
VipsInterpolateClass parent_class;
} VipsInterpolateMbicubicClass;
/*
* MINMOD is an implementation of the minmod function which only needs
* two conditional moves.
*
* MINMOD(a,b,a_times_a,a_times_b) "returns" minmod(a,b). The
* parameter ("input") a_times_a is assumed to contain the square of
* a; the parameter a_times_b, the product of a and b.
*
* The version most suitable for images with flat (constant) colour
* areas, since a, which is a pixel difference, will often be 0, in
* which case both forward branches are likely:
*
* ( (a_times_b)>=0 ? 1. : 0. ) * ( (a_times_a)<=(a_times_b) ? (a) : (b) )
*
* For uncompressed natural images in high bit depth (images for which
* the slopes a and b are unlikely to be equal to zero or be equal to
* each other), we recommend using
*
* ( (a_times_b)>=0. ? 1. : 0. ) * ( (a_times_b)<(a_times_a) ? (b) : (a) )
*
* instead. With this second version, the forward branch of the second
* conditional move is taken when |b|>|a| and when a*b<0. However, the
* "else" branch is taken when a=0 (or when a=b), which is why this
* second version is not recommended for images with large regions
* with constant pixel values (or even, actually, regions with nearby
* pixel values which vary bilinearly, which may arise from dirt-cheap
* demosaicing or computer graphics operations).
*
* Both of the above use a multiplication instead of a nested
* "if-then-else" because gcc does not always rewrite the latter using
* conditional moves.
*
* Implementation note: Both of the above are better than FAST_MINMOD
* (currently found in templates.h and used by the "classic"
* implementations of the other Nohalo methods). Unfortunately, MINMOD
* uses different parameters and consequently is not a direct
* substitute. To be fixed in the future.
*
* Note that the two variants differ in whether (a) or (b) is the
* "out" of the forward branch of the second factor. If there is a
* difference in likelihood, put the likely one in (a) in the first
* variant, and the likely one in (b) in the second.
*/
#define MINMOD(a,b,a_times_a,a_times_b) \
( (a_times_b)>=0. ? 1. : 0. ) * ( (a_times_b)<(a_times_a) ? (b) : (a) )
static inline double
mcubic( const double one,
const double two,
const double thr,
const double fou,
const double coef_thr_point,
const double half_coef_two_slope,
const double half_coef_thr_slope )
{
/*
* Computation of the slopes and slope limiters:
*
* Differences:
*/
const double prem = two - one;
const double deux = thr - two;
const double troi = fou - thr;
const double part = two + deux * coef_thr_point;
/*
* Products useful for the minmod computations:
*/
const double deux_prem = deux * prem;
const double deux_deux = deux * deux;
const double deux_troi = deux * troi;
/*
* Twice the horizontal limiter slopes (twice_lx) interwoven with
* twice the Catmull-Rom slopes (twice_sx). Because we have twice
* the Catmull-Rom slope, we need to use 6 times the minmod slope
* instead of the usual 3 (specified by the cited article).
*/
const double twice_lx_two =
6. * MINMOD( deux, prem, deux_deux, deux_prem );
const double twice_sx_two = deux + prem;
const double twice_lx_thr =
6. * MINMOD( deux, troi, deux_deux, deux_troi );
const double twice_sx_thr = deux + troi;
const double lx_lx_two = twice_lx_two * twice_lx_two;
const double lx_sx_two = twice_lx_two * twice_sx_two;
const double lx_lx_thr = twice_lx_thr * twice_lx_thr;
const double lx_sx_thr = twice_lx_thr * twice_sx_thr;
/*
* Result of the first interpolations along horizontal lines. Note
* that the Catmull-Rom slope almost always satisfies the
* monotonicity constraint, hence twice_sx is "likely" to be the one
* selected by minmod.
*/
const double newval =
part +
+ half_coef_two_slope
* MINMOD( twice_lx_two, twice_sx_two, lx_lx_two, lx_sx_two )
+ half_coef_thr_slope
* MINMOD( twice_lx_thr, twice_sx_thr, lx_lx_thr, lx_sx_thr );
return newval;
}
static inline double
symmetrized_monotone_cubic_splines( const double coef_rite_point,
const double coef_bot_point,
const double half_coef_left_slope,
const double half_coef_rite_slope,
const double half_coef_top_slope,
const double half_coef_bot_slope,
const double uno_one,
const double uno_two,
const double uno_thr,
const double uno_fou,
const double dos_one,
const double dos_two,
const double dos_thr,
const double dos_fou,
const double tre_one,
const double tre_two,
const double tre_thr,
const double tre_fou,
const double qua_one,
const double qua_two,
const double qua_thr,
const double qua_fou )
{
/*
* STENCIL (FOOTPRINT) OF INPUT VALUES:
*
* The stencil of Symmetrized Monotone Catmull-Rom is the same as
* the standard Catmull-Rom's:
*
* (ix-1,iy-1) (ix,iy-1) (ix+1,iy-1) (ix+2,iy-1)
* = uno_one = uno_two = uno_thr = uno_fou
*
* (ix-1,iy) (ix,iy) (ix+1,iy) (ix+2,iy)
* = dos_one = dos_two = dos_thr = dos_fou
* X
* (ix-1,iy+1) (ix,iy+1) (ix+1,iy+1) (ix+2,iy+1)
* = tre_one = tre_two = tre_thr = tre_fou
*
* (ix-1,iy+2) (ix,iy+2) (ix+1,iy+2) (ix+2,iy+2)
* = qua_one = qua_two = qua_thr = qua_fou
*
* where ix is the (pseudo-)floor of the requested left-to-right
* location ("X"), and iy is the floor of the requested up-to-down
* location.
*/
/*
* Outline of the computation:
*
* First, four horizontal cubic Hermite interpolations are performed
* to get values on the vertical line which passes through X, and
* then these four values are used to perform cubic Hermite
* interpolation in the vertical direction to get one approximation
* of the pixel value at X,
*
* Then, four vertical cubic Hermite interpolations are performed to
* get values on the horizontal line which passes through X, and
* then these four values are used to perform cubic Hermite
* interpolation in the horizontal direction to get another
* approximation of the pixel value at X,
*
* These two interpolated pixel values are then averaged.
*/
/*
* Computation of the slopes and slope limiters:
*
* Uno horizontal differences:
*/
const double uno = mcubic( uno_one,
uno_two,
uno_thr,
uno_fou,
coef_rite_point,
half_coef_left_slope,
half_coef_rite_slope );
/*
* Do the same with the other three horizontal lines.
*
* Dos horizontal line:
*/
const double dos = mcubic( dos_one,
dos_two,
dos_thr,
dos_fou,
coef_rite_point,
half_coef_left_slope,
half_coef_rite_slope );
/*
* Tre(s) horizontal line:
*/
const double tre = mcubic( tre_one,
tre_two,
tre_thr,
tre_fou,
coef_rite_point,
half_coef_left_slope,
half_coef_rite_slope );
/*
* Qua(ttro) horizontal line:
*/
const double qua = mcubic( qua_one,
qua_two,
qua_thr,
qua_fou,
coef_rite_point,
half_coef_left_slope,
half_coef_rite_slope );
/*
* Perform the interpolation along the one vertical line (filled
* with results obtained by interpolating along horizontal lines):
*/
const double partial_y = mcubic( uno,
dos,
tre,
qua,
coef_bot_point,
half_coef_top_slope,
half_coef_bot_slope );
/*
* Redo with four vertical lines (and the corresponding horizontal
* one).
*
* One:
*/
const double one = mcubic( uno_one,
dos_one,
tre_one,
qua_one,
coef_bot_point,
half_coef_top_slope,
half_coef_bot_slope );
/*
* Two:
*/
const double two = mcubic( uno_two,
dos_two,
tre_two,
qua_two,
coef_bot_point,
half_coef_top_slope,
half_coef_bot_slope );
/*
* Thr(ee):
*/
const double thr = mcubic( uno_thr,
dos_thr,
tre_thr,
qua_thr,
coef_bot_point,
half_coef_top_slope,
half_coef_bot_slope );
/*
* Fou(r):
*/
const double fou = mcubic( uno_fou,
dos_fou,
tre_fou,
qua_fou,
coef_bot_point,
half_coef_top_slope,
half_coef_bot_slope );
/*
* Final horizontal line of vertical results:
*/
const double prem_x = two - one;
const double deux_x = thr - two;
const double troi_x = fou - thr;
const double partial_newval = partial_y + two + coef_rite_point * deux_x;
const double deux_prem_x = deux_x * prem_x;
const double deux_deux_x = deux_x * deux_x;
const double deux_troi_x = deux_x * troi_x;
const double twice_l_two =
6. * MINMOD( deux_x, prem_x, deux_deux_x, deux_prem_x );
const double twice_s_two = deux_x + prem_x;
const double twice_l_thr =
6. * MINMOD( deux_x, troi_x, deux_deux_x, deux_troi_x );
const double twice_s_thr = deux_x + troi_x;
const double l_l_two = twice_l_two * twice_l_two;
const double l_s_two = twice_l_two * twice_s_two;
const double l_l_thr = twice_l_thr * twice_l_thr;
const double l_s_thr = twice_l_thr * twice_s_thr;
const double newval =
(
partial_newval
+
half_coef_left_slope
*
MINMOD( twice_l_two, twice_s_two, l_l_two, l_s_two )
+
half_coef_rite_slope
*
MINMOD( twice_l_thr, twice_s_thr, l_l_thr, l_s_thr )
) * .5;
return newval;
}
/*
* Call Snohalo with an conversion operator as a parameter.
*
* It would be nice to do this with templates somehow---for one thing
* this would allow code comments!---but we can't figure a clean way
* to do it.
*/
#define MBICUBIC_CONVERSION( conversion ) \
template <typename T> static void inline \
mbicubic_ ## conversion( PEL* restrict pout, \
const PEL* restrict pin, \
const int bands, \
const int lskip, \
const double x, \
const double y ) \
{ \
T* restrict out = (T *) pout; \
\
const T* restrict in = (T *) pin; \
\
const int one_shift = -bands; \
const int thr_shift = bands; \
const int fou_shift = 2*bands; \
\
const int uno_two_shift = -lskip; \
const int dos_two_shift = 0; \
const int tre_two_shift = lskip; \
const int qua_two_shift = 2*lskip; \
\
const int uno_one_shift = uno_two_shift + one_shift; \
const int dos_one_shift = dos_two_shift + one_shift; \
const int tre_one_shift = tre_two_shift + one_shift; \
const int qua_one_shift = qua_two_shift + one_shift; \
\
const int uno_thr_shift = uno_two_shift + thr_shift; \
const int dos_thr_shift = dos_two_shift + thr_shift; \
const int tre_thr_shift = tre_two_shift + thr_shift; \
const int qua_thr_shift = qua_two_shift + thr_shift; \
\
const int uno_fou_shift = uno_two_shift + fou_shift; \
const int dos_fou_shift = dos_two_shift + fou_shift; \
const int tre_fou_shift = tre_two_shift + fou_shift; \
const int qua_fou_shift = qua_two_shift + fou_shift; \
\
const double x_squared = x * x; \
const double y_squared = y * y; \
const double twice_x = x + x; \
const double twice_y = y + y; \
const double half_x_squared_minus_x = .5 * ( x_squared - x ); \
const double half_y_squared_minus_y = .5 * ( y_squared - y ); \
\
const double coef_rite_point = x_squared * ( 3. - twice_x ); \
const double coef_bot_point = y_squared * ( 3. - twice_y ); \
\
const double half_coef_rite_slope = x * half_x_squared_minus_x; \
const double half_coef_bot_slope = y * half_y_squared_minus_y; \
const double half_coef_left_slope = \
half_coef_rite_slope - half_x_squared_minus_x; \
const double half_coef_top_slope = \
half_coef_bot_slope - half_y_squared_minus_y; \
\
int band = bands; \
\
do \
{ \
const double double_result = \
symmetrized_monotone_cubic_splines( coef_rite_point, \
coef_bot_point, \
half_coef_left_slope, \
half_coef_rite_slope, \
half_coef_top_slope, \
half_coef_bot_slope, \
in[ uno_one_shift ], \
in[ uno_two_shift ], \
in[ uno_thr_shift ], \
in[ uno_fou_shift ], \
in[ dos_one_shift ], \
in[ dos_two_shift ], \
in[ dos_thr_shift ], \
in[ dos_fou_shift ], \
in[ tre_one_shift ], \
in[ tre_two_shift ], \
in[ tre_thr_shift ], \
in[ tre_fou_shift ], \
in[ qua_one_shift ], \
in[ qua_two_shift ], \
in[ qua_thr_shift ], \
in[ qua_fou_shift ] ); \
\
const T result = to_ ## conversion<T>( double_result ); \
in++; \
*out++ = result; \
} while (--band); \
}
MBICUBIC_CONVERSION( fptypes )
MBICUBIC_CONVERSION( withsign )
MBICUBIC_CONVERSION( nosign )
#define CALL( T, conversion ) \
mbicubic_ ## conversion<T>( out, \
p, \
bands, \
lskip, \
relative_x, \
relative_y );
/*
* We need C linkage:
*/
extern "C" {
G_DEFINE_TYPE( VipsInterpolateMbicubic, vips_interpolate_mbicubic,
VIPS_TYPE_INTERPOLATE );
}
static void
vips_interpolate_mbicubic_interpolate( VipsInterpolate* restrict interpolate,
PEL* restrict out,
REGION* restrict in,
double absolute_x,
double absolute_y )
{
/*
* Floor's surrogate FAST_PSEUDO_FLOOR is used to make sure that the
* transition through 0 is smooth. If it is known that absolute_x
* and absolute_y will never be less than 0, plain cast---that is,
* const int ix = absolute_x---should be used instead. Actually,
* any function which agrees with floor for non-integer values, and
* picks one of the two possibilities for integer values, can be
* used. FAST_PSEUDO_FLOOR fits the bill.
*
* Then, x is the x-coordinate of the sampling point relative to the
* position of the center of the convex hull of the 2x2 block of
* closest pixels. Similarly for y. Range of values: [-.5,.5).
*/
const int ix = FAST_PSEUDO_FLOOR( absolute_x );
const int iy = FAST_PSEUDO_FLOOR( absolute_y );
/*
* Move the pointer to (the first band of) the top/left pixel of the
* 2x2 group of pixel centers which contains the sampling location
* in its convex hull:
*/
const PEL* restrict p = (PEL *) IM_REGION_ADDR( in, ix, iy );
const double relative_x = absolute_x - ix;
const double relative_y = absolute_y - iy;
/*
* VIPS versions of Nicolas's pixel addressing values.
*/
const int actual_bands = in->im->Bands;
const int lskip = IM_REGION_LSKIP( in ) / IM_IMAGE_SIZEOF_ELEMENT( in->im );
/*
* Double the bands for complex images to account for the real and
* imaginary parts being computed independently:
*/
const int bands =
vips_bandfmt_iscomplex( in->im->BandFmt ) ? 2 * actual_bands : actual_bands;
switch( in->im->BandFmt ) {
case IM_BANDFMT_UCHAR:
CALL( unsigned char, nosign );
break;
case IM_BANDFMT_CHAR:
CALL( signed char, withsign );
break;
case IM_BANDFMT_USHORT:
CALL( unsigned short, nosign );
break;
case IM_BANDFMT_SHORT:
CALL( signed short, withsign );
break;
case IM_BANDFMT_UINT:
CALL( unsigned int, nosign );
break;
case IM_BANDFMT_INT:
CALL( signed int, withsign );
break;
/*
* Complex images are handled by doubling of bands.
*/
case IM_BANDFMT_FLOAT:
case IM_BANDFMT_COMPLEX:
CALL( float, fptypes );
break;
case IM_BANDFMT_DOUBLE:
case IM_BANDFMT_DPCOMPLEX:
CALL( double, fptypes );
break;
default:
g_assert( 0 );
break;
}
}
static void
vips_interpolate_mbicubic_class_init( VipsInterpolateMbicubicClass *klass )
{
VipsObjectClass *object_class = VIPS_OBJECT_CLASS( klass );
VipsInterpolateClass *interpolate_class =
VIPS_INTERPOLATE_CLASS( klass );
object_class->nickname = "mbicubic";
object_class->description = _( "Halo-free mbicubic" );
interpolate_class->interpolate = vips_interpolate_mbicubic_interpolate;
interpolate_class->window_size = 4;
}
static void
vips_interpolate_mbicubic_init( VipsInterpolateMbicubic *mbicubic )
{
}