finish reduce
and fix up bicubic a bit, it works better on int32 images now
This commit is contained in:
parent
39e6963033
commit
8cffd136e9
@ -1,6 +1,7 @@
|
||||
29/1/16 started 8.3
|
||||
- add vips_reduce*() ... a fast path for bicubic downsize
|
||||
- vips_resize() and vips_similarity use it when they can
|
||||
- bicubic is better on 32-bit int images
|
||||
|
||||
12/1/16 started 8.2.2
|
||||
- changes to ease compiling C++ binding with MSVC [Lovell Fuller]
|
||||
|
24
TODO
24
TODO
@ -1,15 +1,3 @@
|
||||
- strange, try
|
||||
|
||||
$ vips affine babe.jpg x.v "0.909 0 0 0.909"
|
||||
$ vipsheader x.v
|
||||
x.v: 931x698 uchar, 3 bands, srgb, jpegload
|
||||
|
||||
but 1024 * 0.909 == 930.9, shouldn't we be rounding down? I guess we are
|
||||
rounding up
|
||||
|
||||
need to fix this if we want to be able to used reduce as a shortcut for
|
||||
similarity
|
||||
|
||||
- new vips_reduce:
|
||||
|
||||
affine
|
||||
@ -20,17 +8,15 @@
|
||||
|
||||
reduce
|
||||
$ time vipsthumbnail wtc.tif -o x.tif -s 7000
|
||||
real 0m1.818s
|
||||
user 0m5.956s
|
||||
sys 0m0.296s
|
||||
|
||||
add tests for vips_reduce(), update c++ binding, check docs and "see also"
|
||||
lines
|
||||
|
||||
real 0m1.677s
|
||||
user 0m5.996s
|
||||
sys 0m0.300s
|
||||
|
||||
- get some brightly coloured spots with nohalo / vsqbs on wobble.ws ... very
|
||||
odd, the interpolation shouldn't change between bands
|
||||
|
||||
probably over/underflow in interpolation ... clipping problems?
|
||||
|
||||
- still not happy about float->int mask conversion in im_vips2mask.c
|
||||
|
||||
- need to follow up on
|
||||
|
@ -1,5 +1,5 @@
|
||||
// headers for vips operations
|
||||
// Sat Jan 9 15:06:40 GMT 2016
|
||||
// Sun Feb 7 16:27:14 GMT 2016
|
||||
// this file is generated automatically, do not edit!
|
||||
|
||||
static void system( char * cmd_format , VOption *options = 0 );
|
||||
@ -146,7 +146,9 @@ VImage mapim( VImage index , VOption *options = 0 );
|
||||
VImage shrink( double xshrink , double yshrink , VOption *options = 0 );
|
||||
VImage shrinkh( int xshrink , VOption *options = 0 );
|
||||
VImage shrinkv( int yshrink , VOption *options = 0 );
|
||||
VImage shrink2( double xshrink , double yshrink , VOption *options = 0 );
|
||||
VImage reduceh( double xshrink , VOption *options = 0 );
|
||||
VImage reducev( double yshrink , VOption *options = 0 );
|
||||
VImage reduce( double xshrink , double yshrink , VOption *options = 0 );
|
||||
VImage quadratic( VImage coeff , VOption *options = 0 );
|
||||
VImage affine( std::vector<double> matrix , VOption *options = 0 );
|
||||
VImage similarity( VOption *options = 0 );
|
||||
|
@ -1,5 +1,5 @@
|
||||
// bodies for vips operations
|
||||
// Sat Jan 9 15:05:58 GMT 2016
|
||||
// Sun Feb 7 16:26:59 GMT 2016
|
||||
// this file is generated automatically, do not edit!
|
||||
|
||||
void VImage::system( char * cmd_format , VOption *options )
|
||||
@ -1783,11 +1783,37 @@ VImage VImage::shrinkv( int yshrink , VOption *options )
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::shrink2( double xshrink , double yshrink , VOption *options )
|
||||
VImage VImage::reduceh( double xshrink , VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "shrink2" ,
|
||||
call( "reduceh" ,
|
||||
(options ? options : VImage::option()) ->
|
||||
set( "in", *this ) ->
|
||||
set( "out", &out ) ->
|
||||
set( "xshrink", xshrink ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::reducev( double yshrink , VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "reducev" ,
|
||||
(options ? options : VImage::option()) ->
|
||||
set( "in", *this ) ->
|
||||
set( "out", &out ) ->
|
||||
set( "yshrink", yshrink ) );
|
||||
|
||||
return( out );
|
||||
}
|
||||
|
||||
VImage VImage::reduce( double xshrink , double yshrink , VOption *options )
|
||||
{
|
||||
VImage out;
|
||||
|
||||
call( "reduce" ,
|
||||
(options ? options : VImage::option()) ->
|
||||
set( "in", *this ) ->
|
||||
set( "out", &out ) ->
|
||||
|
@ -9,7 +9,7 @@
|
||||
<bookinfo>
|
||||
<title>VIPS Reference Manual</title>
|
||||
<releaseinfo>
|
||||
For VIPS 8.2.2.
|
||||
For VIPS 8.3.0.
|
||||
The latest version of this documentation can be found on the
|
||||
<ulink role="online-location"
|
||||
url="http://www.vips.ecs.soton.ac.uk/index.php?title=Documentation">VIPS website</ulink>.
|
||||
|
@ -2,6 +2,8 @@
|
||||
*
|
||||
* 12/8/10
|
||||
* - revise window_size / window_offset stuff again
|
||||
* 7/2/16
|
||||
* - double intermediate for 32-bit int types
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -231,7 +233,7 @@ bicubic_signed_int_tab( void *pout, const VipsPel *pin,
|
||||
}
|
||||
}
|
||||
|
||||
/* Floating-point version, for int/float types.
|
||||
/* Floating-point version.
|
||||
*/
|
||||
template <typename T>
|
||||
static void inline
|
||||
@ -294,6 +296,135 @@ bicubic_float_tab( void *pout, const VipsPel *pin,
|
||||
}
|
||||
}
|
||||
|
||||
/* uint32 version needs a double intermediate.
|
||||
*/
|
||||
|
||||
template <typename T, int max_value>
|
||||
static void inline
|
||||
bicubic_unsigned_int32_tab( void *pout, const VipsPel *pin,
|
||||
const int bands, const int lskip,
|
||||
const double *cx, const double *cy )
|
||||
{
|
||||
T* restrict out = (T *) pout;
|
||||
const T* restrict in = (T *) pin;
|
||||
|
||||
const int b1 = bands;
|
||||
const int b2 = b1 + b1;
|
||||
const int b3 = b1 + b2;
|
||||
|
||||
const int l1 = lskip / sizeof( T );
|
||||
const int l2 = l1 + l1;
|
||||
const int l3 = l1 + l2;
|
||||
|
||||
const int l1_plus_b1 = l1 + b1;
|
||||
const int l1_plus_b2 = l1 + b2;
|
||||
const int l1_plus_b3 = l1 + b3;
|
||||
const int l2_plus_b1 = l2 + b1;
|
||||
const int l2_plus_b2 = l2 + b2;
|
||||
const int l2_plus_b3 = l2 + b3;
|
||||
const int l3_plus_b1 = l3 + b1;
|
||||
const int l3_plus_b2 = l3 + b2;
|
||||
const int l3_plus_b3 = l3 + b3;
|
||||
|
||||
for( int z = 0; z < bands; z++ ) {
|
||||
const T uno_one = in[0];
|
||||
const T uno_two = in[b1];
|
||||
const T uno_thr = in[b2];
|
||||
const T uno_fou = in[b3];
|
||||
|
||||
const T dos_one = in[l1];
|
||||
const T dos_two = in[l1_plus_b1];
|
||||
const T dos_thr = in[l1_plus_b2];
|
||||
const T dos_fou = in[l1_plus_b3];
|
||||
|
||||
const T tre_one = in[l2];
|
||||
const T tre_two = in[l2_plus_b1];
|
||||
const T tre_thr = in[l2_plus_b2];
|
||||
const T tre_fou = in[l2_plus_b3];
|
||||
|
||||
const T qua_one = in[l3];
|
||||
const T qua_two = in[l3_plus_b1];
|
||||
const T qua_thr = in[l3_plus_b2];
|
||||
const T qua_fou = in[l3_plus_b3];
|
||||
|
||||
double bicubic = bicubic_float<double>(
|
||||
uno_one, uno_two, uno_thr, uno_fou,
|
||||
dos_one, dos_two, dos_thr, dos_fou,
|
||||
tre_one, tre_two, tre_thr, tre_fou,
|
||||
qua_one, qua_two, qua_thr, qua_fou,
|
||||
cx, cy );
|
||||
|
||||
bicubic = VIPS_CLIP( 0, bicubic, max_value );
|
||||
|
||||
out[z] = bicubic;
|
||||
|
||||
in += 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, int min_value, int max_value>
|
||||
static void inline
|
||||
bicubic_signed_int32_tab( void *pout, const VipsPel *pin,
|
||||
const int bands, const int lskip,
|
||||
const double *cx, const double *cy )
|
||||
{
|
||||
T* restrict out = (T *) pout;
|
||||
const T* restrict in = (T *) pin;
|
||||
|
||||
const int b1 = bands;
|
||||
const int b2 = b1 + b1;
|
||||
const int b3 = b1 + b2;
|
||||
|
||||
const int l1 = lskip / sizeof( T );
|
||||
const int l2 = l1 + l1;
|
||||
const int l3 = l1 + l2;
|
||||
|
||||
const int l1_plus_b1 = l1 + b1;
|
||||
const int l1_plus_b2 = l1 + b2;
|
||||
const int l1_plus_b3 = l1 + b3;
|
||||
const int l2_plus_b1 = l2 + b1;
|
||||
const int l2_plus_b2 = l2 + b2;
|
||||
const int l2_plus_b3 = l2 + b3;
|
||||
const int l3_plus_b1 = l3 + b1;
|
||||
const int l3_plus_b2 = l3 + b2;
|
||||
const int l3_plus_b3 = l3 + b3;
|
||||
|
||||
for( int z = 0; z < bands; z++ ) {
|
||||
const T uno_one = in[0];
|
||||
const T uno_two = in[b1];
|
||||
const T uno_thr = in[b2];
|
||||
const T uno_fou = in[b3];
|
||||
|
||||
const T dos_one = in[l1];
|
||||
const T dos_two = in[l1_plus_b1];
|
||||
const T dos_thr = in[l1_plus_b2];
|
||||
const T dos_fou = in[l1_plus_b3];
|
||||
|
||||
const T tre_one = in[l2];
|
||||
const T tre_two = in[l2_plus_b1];
|
||||
const T tre_thr = in[l2_plus_b2];
|
||||
const T tre_fou = in[l2_plus_b3];
|
||||
|
||||
const T qua_one = in[l3];
|
||||
const T qua_two = in[l3_plus_b1];
|
||||
const T qua_thr = in[l3_plus_b2];
|
||||
const T qua_fou = in[l3_plus_b3];
|
||||
|
||||
double bicubic = bicubic_float<double>(
|
||||
uno_one, uno_two, uno_thr, uno_fou,
|
||||
dos_one, dos_two, dos_thr, dos_fou,
|
||||
tre_one, tre_two, tre_thr, tre_fou,
|
||||
qua_one, qua_two, qua_thr, qua_fou,
|
||||
cx, cy );
|
||||
|
||||
bicubic = VIPS_CLIP( min_value, bicubic, max_value );
|
||||
|
||||
out[z] = bicubic;
|
||||
|
||||
in += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ultra-high-quality version for double images.
|
||||
*/
|
||||
template <typename T>
|
||||
@ -461,12 +592,14 @@ vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate,
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_UINT:
|
||||
bicubic_float_tab<unsigned int>( out, p, bands, lskip,
|
||||
bicubic_unsigned_int32_tab<unsigned int, INT_MAX>(
|
||||
out, p, bands, lskip,
|
||||
cxf, cyf );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_INT:
|
||||
bicubic_float_tab<signed int>( out, p, bands, lskip,
|
||||
bicubic_signed_int32_tab<signed int, INT_MIN, INT_MAX>(
|
||||
out, p, bands, lskip,
|
||||
cxf, cyf );
|
||||
break;
|
||||
|
||||
|
@ -160,9 +160,76 @@ reduceh_float_tab( VipsPel *pout, const VipsPel *pin,
|
||||
for( int z = 0; z < bands; z++ ) {
|
||||
out[z] =
|
||||
c0 * in[0] +
|
||||
c1 * in[1] +
|
||||
c2 * in[2] +
|
||||
c3 * in[3];
|
||||
c1 * in[b1] +
|
||||
c2 * in[b2] +
|
||||
c3 * in[b3];
|
||||
|
||||
in += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* 32-bit output needs a double intermediate.
|
||||
*/
|
||||
|
||||
template <typename T, int max_value>
|
||||
static void inline
|
||||
reduceh_unsigned_int32_tab( VipsPel *pout, const VipsPel *pin,
|
||||
const int bands, const double *cx )
|
||||
{
|
||||
T* restrict out = (T *) pout;
|
||||
const T* restrict in = (T *) pin;
|
||||
|
||||
const int b1 = bands;
|
||||
const int b2 = b1 + b1;
|
||||
const int b3 = b1 + b2;
|
||||
|
||||
const double c0 = cx[0];
|
||||
const double c1 = cx[1];
|
||||
const double c2 = cx[2];
|
||||
const double c3 = cx[3];
|
||||
|
||||
for( int z = 0; z < bands; z++ ) {
|
||||
double cubich =
|
||||
c0 * in[0] +
|
||||
c1 * in[b1] +
|
||||
c2 * in[b2] +
|
||||
c3 * in[b3];
|
||||
|
||||
cubich = VIPS_CLIP( 0, cubich, max_value );
|
||||
|
||||
out[z] = cubich;
|
||||
|
||||
in += 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, int min_value, int max_value>
|
||||
static void inline
|
||||
reduceh_signed_int32_tab( VipsPel *pout, const VipsPel *pin,
|
||||
const int bands, const double *cx )
|
||||
{
|
||||
T* restrict out = (T *) pout;
|
||||
const T* restrict in = (T *) pin;
|
||||
|
||||
const int b1 = bands;
|
||||
const int b2 = b1 + b1;
|
||||
const int b3 = b1 + b2;
|
||||
|
||||
const double c0 = cx[0];
|
||||
const double c1 = cx[1];
|
||||
const double c2 = cx[2];
|
||||
const double c3 = cx[3];
|
||||
|
||||
for( int z = 0; z < bands; z++ ) {
|
||||
double cubich =
|
||||
c0 * in[0] +
|
||||
c1 * in[b1] +
|
||||
c2 * in[b2] +
|
||||
c3 * in[b3];
|
||||
|
||||
cubich = VIPS_CLIP( min_value, cubich, max_value );
|
||||
|
||||
out[z] = cubich;
|
||||
|
||||
in += 1;
|
||||
}
|
||||
@ -222,7 +289,7 @@ vips_reduceh_gen( VipsRegion *out_region, void *seq,
|
||||
|
||||
s.left = r->left * reduceh->xshrink;
|
||||
s.top = r->top;
|
||||
s.width = r->width * reduceh->xshrink + 3;
|
||||
s.width = r->width * reduceh->xshrink + 4;
|
||||
s.height = r->height;
|
||||
if( vips_region_prepare( ir, &s ) )
|
||||
return( -1 );
|
||||
@ -271,12 +338,14 @@ vips_reduceh_gen( VipsRegion *out_region, void *seq,
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_UINT:
|
||||
reduceh_float_tab<unsigned int>(
|
||||
reduceh_unsigned_int32_tab
|
||||
<unsigned int, INT_MAX>(
|
||||
q, p, bands, cxf );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_INT:
|
||||
reduceh_float_tab<signed int>(
|
||||
reduceh_signed_int32_tab
|
||||
<signed int, INT_MIN, INT_MAX>(
|
||||
q, p, bands, cxf );
|
||||
break;
|
||||
|
||||
@ -326,9 +395,9 @@ vips_reduceh_build( VipsObject *object )
|
||||
"%s", _( "reduce factors should be >= 1" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( reduceh->xshrink > 2 )
|
||||
if( reduceh->xshrink > 3 )
|
||||
vips_warn( object_class->nickname,
|
||||
"%s", _( "reduce factor greater than 2" ) );
|
||||
"%s", _( "reduce factor greater than 3" ) );
|
||||
|
||||
if( reduceh->xshrink == 1 )
|
||||
return( vips_image_write( in, resample->out ) );
|
||||
|
@ -140,8 +140,9 @@ reducev_signed_int_tab( VipsPel *pout, const VipsPel *pin,
|
||||
}
|
||||
}
|
||||
|
||||
/* Floating-point version, for int/float types.
|
||||
/* Floating-point version.
|
||||
*/
|
||||
|
||||
template <typename T>
|
||||
static void inline
|
||||
reducev_float_tab( VipsPel *pout, const VipsPel *pin,
|
||||
@ -171,6 +172,75 @@ reducev_float_tab( VipsPel *pout, const VipsPel *pin,
|
||||
}
|
||||
}
|
||||
|
||||
/* 32-bit int version needs a double intermediate.
|
||||
*/
|
||||
|
||||
template <typename T, int max_value>
|
||||
static void inline
|
||||
reducev_unsigned_int32_tab( VipsPel *pout, const VipsPel *pin,
|
||||
const int ne, const int lskip,
|
||||
const double *cy )
|
||||
{
|
||||
T* restrict out = (T *) pout;
|
||||
const T* restrict in = (T *) pin;
|
||||
|
||||
const int l1 = lskip / sizeof( T );
|
||||
const int l2 = l1 + l1;
|
||||
const int l3 = l1 + l2;
|
||||
|
||||
const double c0 = cy[0];
|
||||
const double c1 = cy[1];
|
||||
const double c2 = cy[2];
|
||||
const double c3 = cy[3];
|
||||
|
||||
for( int z = 0; z < ne; z++ ) {
|
||||
double cubicv =
|
||||
c0 * in[0] +
|
||||
c1 * in[l1] +
|
||||
c2 * in[l2] +
|
||||
c3 * in[l3];
|
||||
|
||||
cubicv = VIPS_CLIP( 0, cubicv, max_value );
|
||||
|
||||
out[z] = cubicv;
|
||||
|
||||
in += 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, int min_value, int max_value>
|
||||
static void inline
|
||||
reducev_signed_int32_tab( VipsPel *pout, const VipsPel *pin,
|
||||
const int ne, const int lskip,
|
||||
const double *cy )
|
||||
{
|
||||
T* restrict out = (T *) pout;
|
||||
const T* restrict in = (T *) pin;
|
||||
|
||||
const int l1 = lskip / sizeof( T );
|
||||
const int l2 = l1 + l1;
|
||||
const int l3 = l1 + l2;
|
||||
|
||||
const double c0 = cy[0];
|
||||
const double c1 = cy[1];
|
||||
const double c2 = cy[2];
|
||||
const double c3 = cy[3];
|
||||
|
||||
for( int z = 0; z < ne; z++ ) {
|
||||
double cubicv =
|
||||
c0 * in[0] +
|
||||
c1 * in[l1] +
|
||||
c2 * in[l2] +
|
||||
c3 * in[l3];
|
||||
|
||||
cubicv = VIPS_CLIP( min_value, cubicv, max_value );
|
||||
|
||||
out[z] = cubicv;
|
||||
|
||||
in += 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Ultra-high-quality version for double images.
|
||||
*/
|
||||
template <typename T>
|
||||
@ -231,7 +301,7 @@ vips_reducev_gen( VipsRegion *out_region, void *seq,
|
||||
s.left = r->left;
|
||||
s.top = r->top * reducev->yshrink;
|
||||
s.width = r->width;
|
||||
s.height = r->height * reducev->yshrink + 3;
|
||||
s.height = r->height * reducev->yshrink + 4;
|
||||
if( vips_region_prepare( ir, &s ) )
|
||||
return( -1 );
|
||||
|
||||
@ -274,11 +344,15 @@ vips_reducev_gen( VipsRegion *out_region, void *seq,
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_UINT:
|
||||
reducev_float_tab<unsigned int>( q, p, ne, lskip, cyf );
|
||||
reducev_unsigned_int32_tab
|
||||
<unsigned int, INT_MAX>(
|
||||
q, p, ne, lskip, cyf );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_INT:
|
||||
reducev_float_tab<signed int>( q, p, ne, lskip, cyf );
|
||||
reducev_signed_int32_tab
|
||||
<signed int, INT_MIN, INT_MAX>(
|
||||
q, p, ne, lskip, cyf );
|
||||
break;
|
||||
|
||||
case VIPS_FORMAT_FLOAT:
|
||||
@ -322,9 +396,9 @@ vips_reducev_build( VipsObject *object )
|
||||
"%s", _( "reduce factors should be >= 1" ) );
|
||||
return( -1 );
|
||||
}
|
||||
if( reducev->yshrink > 2 )
|
||||
if( reducev->yshrink > 3 )
|
||||
vips_warn( object_class->nickname,
|
||||
"%s", _( "reduce factor greater than 2" ) );
|
||||
"%s", _( "reduce factor greater than 3" ) );
|
||||
|
||||
if( reducev->yshrink == 1 )
|
||||
return( vips_image_write( in, resample->out ) );
|
||||
|
@ -52,6 +52,28 @@
|
||||
|
||||
#include "presample.h"
|
||||
|
||||
/**
|
||||
* SECTION: resample
|
||||
* @short_description: resample images in various ways
|
||||
* @stability: Stable
|
||||
* @include: vips/vips.h
|
||||
*
|
||||
* There are three types of operation in this section.
|
||||
*
|
||||
* First, vips_affine() applies an affine transform to an image. This is any
|
||||
* sort of 2D transform which preserves straight lines; so any combination of
|
||||
* stretch, sheer, rotate and translate. You supply an interpolator for it to
|
||||
* use to generate pixels, see vips_interpolate_new(). It will not produce
|
||||
* good results for very large shrinks.
|
||||
*
|
||||
* Next, vips_resize() specialises in the common task of image reduce and
|
||||
* enlarge. It strings together combinations of vips_shrink(), vips_reduce(),
|
||||
* vips_affine() and others to implement a general, high-quality image
|
||||
* resizer.
|
||||
*
|
||||
* Finally, vips_mapim() can apply arbitrary 2D image transforms to an image.
|
||||
*/
|
||||
|
||||
G_DEFINE_ABSTRACT_TYPE( VipsResample, vips_resample, VIPS_TYPE_OPERATION );
|
||||
|
||||
static int
|
||||
|
@ -8,6 +8,8 @@
|
||||
* rest of vips
|
||||
* 13/8/14
|
||||
* - oops, missing scale from b, thanks Topochicho
|
||||
* 7/2/16
|
||||
* - use vips_reduce(), if we can
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -154,18 +154,6 @@ unsigned_fixed_round( int v )
|
||||
return( (v + round_by) >> VIPS_INTERPOLATE_SHIFT );
|
||||
}
|
||||
|
||||
template <typename T> static int inline
|
||||
cubic_unsigned_int(
|
||||
const T one, const T two, const T thr, const T fou,
|
||||
const int* restrict cx )
|
||||
{
|
||||
return( unsigned_fixed_round(
|
||||
cx[0] * one +
|
||||
cx[1] * two +
|
||||
cx[2] * thr +
|
||||
cx[3] * fou ) );
|
||||
}
|
||||
|
||||
/* Fixed-point integer bicubic, used for 8 and 16-bit types.
|
||||
*/
|
||||
template <typename T> static int inline
|
||||
@ -176,16 +164,37 @@ bicubic_unsigned_int(
|
||||
const T qua_one, const T qua_two, const T qua_thr, const T qua_fou,
|
||||
const int* restrict cx, const int* restrict cy )
|
||||
{
|
||||
const int r0 = cubic_unsigned_int<T>(
|
||||
uno_one, uno_two, uno_thr, uno_fou, cx );
|
||||
const int r1 = cubic_unsigned_int<T>(
|
||||
dos_one, dos_two, dos_thr, dos_fou, cx );
|
||||
const int r2 = cubic_unsigned_int<T>(
|
||||
tre_one, tre_two, tre_thr, tre_fou, cx );
|
||||
const int r3 = cubic_unsigned_int<T>(
|
||||
qua_one, qua_two, qua_thr, qua_fou, cx );
|
||||
const int c0 = cx[0];
|
||||
const int c1 = cx[1];
|
||||
const int c2 = cx[2];
|
||||
const int c3 = cx[3];
|
||||
|
||||
return( cubic_unsigned_int<T>( r0, r1, r2, r3, cy ) );
|
||||
const int r0 = unsigned_fixed_round(
|
||||
c0 * uno_one +
|
||||
c1 * uno_two +
|
||||
c2 * uno_thr +
|
||||
c3 * uno_fou );
|
||||
const int r1 = unsigned_fixed_round(
|
||||
c0 * dos_one +
|
||||
c1 * dos_two +
|
||||
c2 * dos_thr +
|
||||
c3 * dos_fou );
|
||||
const int r2 = unsigned_fixed_round(
|
||||
c0 * tre_one +
|
||||
c1 * tre_two +
|
||||
c2 * tre_thr +
|
||||
c3 * tre_fou );
|
||||
const int r3 = unsigned_fixed_round(
|
||||
c0 * qua_one +
|
||||
c1 * qua_two +
|
||||
c2 * qua_thr +
|
||||
c3 * qua_fou );
|
||||
|
||||
return( unsigned_fixed_round(
|
||||
cy[0] * r0 +
|
||||
cy[1] * r1 +
|
||||
cy[2] * r2 +
|
||||
cy[3] * r3 ) );
|
||||
}
|
||||
|
||||
static int inline
|
||||
@ -197,18 +206,6 @@ signed_fixed_round( int v )
|
||||
return( (v + round_by) >> VIPS_INTERPOLATE_SHIFT );
|
||||
}
|
||||
|
||||
template <typename T> static int inline
|
||||
cubic_signed_int(
|
||||
const T one, const T two, const T thr, const T fou,
|
||||
const int* restrict cx )
|
||||
{
|
||||
return( signed_fixed_round(
|
||||
cx[0] * one +
|
||||
cx[1] * two +
|
||||
cx[2] * thr +
|
||||
cx[3] * fou ) );
|
||||
}
|
||||
|
||||
/* Fixed-point integer bicubic, used for 8 and 16-bit types.
|
||||
*/
|
||||
template <typename T> static int inline
|
||||
@ -219,16 +216,37 @@ bicubic_signed_int(
|
||||
const T qua_one, const T qua_two, const T qua_thr, const T qua_fou,
|
||||
const int* restrict cx, const int* restrict cy )
|
||||
{
|
||||
const int r0 = cubic_signed_int<T>(
|
||||
uno_one, uno_two, uno_thr, uno_fou, cx );
|
||||
const int r1 = cubic_signed_int<T>(
|
||||
dos_one, dos_two, dos_thr, dos_fou, cx );
|
||||
const int r2 = cubic_signed_int<T>(
|
||||
tre_one, tre_two, tre_thr, tre_fou, cx );
|
||||
const int r3 = cubic_signed_int<T>(
|
||||
qua_one, qua_two, qua_thr, qua_fou, cx );
|
||||
const int c0 = cx[0];
|
||||
const int c1 = cx[1];
|
||||
const int c2 = cx[2];
|
||||
const int c3 = cx[3];
|
||||
|
||||
return( cubic_signed_int<T>( r0, r1, r2, r3, cy ) );
|
||||
const int r0 = signed_fixed_round(
|
||||
c0 * uno_one +
|
||||
c1 * uno_two +
|
||||
c2 * uno_thr +
|
||||
c3 * uno_fou );
|
||||
const int r1 = signed_fixed_round(
|
||||
c0 * dos_one +
|
||||
c1 * dos_two +
|
||||
c2 * dos_thr +
|
||||
c3 * dos_fou );
|
||||
const int r2 = signed_fixed_round(
|
||||
c0 * tre_one +
|
||||
c1 * tre_two +
|
||||
c2 * tre_thr +
|
||||
c3 * tre_fou );
|
||||
const int r3 = signed_fixed_round(
|
||||
c0 * qua_one +
|
||||
c1 * qua_two +
|
||||
c2 * qua_thr +
|
||||
c3 * qua_fou );
|
||||
|
||||
return( signed_fixed_round(
|
||||
cy[0] * r0 +
|
||||
cy[1] * r1 +
|
||||
cy[2] * r2 +
|
||||
cy[3] * r3 ) );
|
||||
}
|
||||
|
||||
template <typename T> static T inline
|
||||
|
@ -11,7 +11,6 @@ from gi.repository import Vips
|
||||
|
||||
Vips.leak_set(True)
|
||||
|
||||
|
||||
unsigned_formats = [Vips.BandFormat.UCHAR,
|
||||
Vips.BandFormat.USHORT,
|
||||
Vips.BandFormat.UINT]
|
||||
|
@ -10,6 +10,20 @@ from gi.repository import Vips
|
||||
|
||||
Vips.leak_set(True)
|
||||
|
||||
unsigned_formats = [Vips.BandFormat.UCHAR,
|
||||
Vips.BandFormat.USHORT,
|
||||
Vips.BandFormat.UINT]
|
||||
signed_formats = [Vips.BandFormat.CHAR,
|
||||
Vips.BandFormat.SHORT,
|
||||
Vips.BandFormat.INT]
|
||||
float_formats = [Vips.BandFormat.FLOAT,
|
||||
Vips.BandFormat.DOUBLE]
|
||||
complex_formats = [Vips.BandFormat.COMPLEX,
|
||||
Vips.BandFormat.DPCOMPLEX]
|
||||
int_formats = unsigned_formats + signed_formats
|
||||
noncomplex_formats = int_formats + float_formats
|
||||
all_formats = int_formats + float_formats + complex_formats
|
||||
|
||||
# Run a function expecting a complex image on a two-band image
|
||||
def run_cmplx(fn, image):
|
||||
if image.format == Vips.BandFormat.FLOAT:
|
||||
@ -105,13 +119,14 @@ class TestResample(unittest.TestCase):
|
||||
bicubic = Vips.Interpolate.new("bicubic")
|
||||
|
||||
for fac in [1, 1.1, 1.5, 1.999]:
|
||||
print("fac =", fac)
|
||||
r = im.reduce(fac, fac)
|
||||
a = im.affine([1.0 / fac, 0, 0, 1.0 / fac], interpolate = bicubic)
|
||||
r.write_to_file("r.v")
|
||||
a.write_to_file("a.v")
|
||||
d = (r - a).abs().max()
|
||||
self.assertLess(d, 0.1)
|
||||
for fmt in all_formats:
|
||||
x = im.cast(fmt)
|
||||
r = x.reduce(fac, fac)
|
||||
a = x.affine([1.0 / fac, 0, 0, 1.0 / fac],
|
||||
interpolate = bicubic,
|
||||
oarea = [0, 0, x.width / fac, x.height / fac])
|
||||
d = (r - a).abs().max()
|
||||
self.assertLess(d, 5)
|
||||
|
||||
def test_resize(self):
|
||||
im = Vips.Image.new_from_file("images/IMG_4618.jpg")
|
||||
|
Loading…
Reference in New Issue
Block a user