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
|
29/1/16 started 8.3
|
||||||
- add vips_reduce*() ... a fast path for bicubic downsize
|
- add vips_reduce*() ... a fast path for bicubic downsize
|
||||||
- vips_resize() and vips_similarity use it when they can
|
- 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
|
12/1/16 started 8.2.2
|
||||||
- changes to ease compiling C++ binding with MSVC [Lovell Fuller]
|
- 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:
|
- new vips_reduce:
|
||||||
|
|
||||||
affine
|
affine
|
||||||
@ -20,17 +8,15 @@
|
|||||||
|
|
||||||
reduce
|
reduce
|
||||||
$ time vipsthumbnail wtc.tif -o x.tif -s 7000
|
$ time vipsthumbnail wtc.tif -o x.tif -s 7000
|
||||||
real 0m1.818s
|
real 0m1.677s
|
||||||
user 0m5.956s
|
user 0m5.996s
|
||||||
sys 0m0.296s
|
sys 0m0.300s
|
||||||
|
|
||||||
add tests for vips_reduce(), update c++ binding, check docs and "see also"
|
|
||||||
lines
|
|
||||||
|
|
||||||
|
|
||||||
- get some brightly coloured spots with nohalo / vsqbs on wobble.ws ... very
|
- get some brightly coloured spots with nohalo / vsqbs on wobble.ws ... very
|
||||||
odd, the interpolation shouldn't change between bands
|
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
|
- still not happy about float->int mask conversion in im_vips2mask.c
|
||||||
|
|
||||||
- need to follow up on
|
- need to follow up on
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// headers for vips operations
|
// 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!
|
// this file is generated automatically, do not edit!
|
||||||
|
|
||||||
static void system( char * cmd_format , VOption *options = 0 );
|
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 shrink( double xshrink , double yshrink , VOption *options = 0 );
|
||||||
VImage shrinkh( int xshrink , VOption *options = 0 );
|
VImage shrinkh( int xshrink , VOption *options = 0 );
|
||||||
VImage shrinkv( int yshrink , 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 quadratic( VImage coeff , VOption *options = 0 );
|
||||||
VImage affine( std::vector<double> matrix , VOption *options = 0 );
|
VImage affine( std::vector<double> matrix , VOption *options = 0 );
|
||||||
VImage similarity( VOption *options = 0 );
|
VImage similarity( VOption *options = 0 );
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// bodies for vips operations
|
// 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!
|
// this file is generated automatically, do not edit!
|
||||||
|
|
||||||
void VImage::system( char * cmd_format , VOption *options )
|
void VImage::system( char * cmd_format , VOption *options )
|
||||||
@ -1783,11 +1783,37 @@ VImage VImage::shrinkv( int yshrink , VOption *options )
|
|||||||
return( out );
|
return( out );
|
||||||
}
|
}
|
||||||
|
|
||||||
VImage VImage::shrink2( double xshrink , double yshrink , VOption *options )
|
VImage VImage::reduceh( double xshrink , VOption *options )
|
||||||
{
|
{
|
||||||
VImage out;
|
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()) ->
|
(options ? options : VImage::option()) ->
|
||||||
set( "in", *this ) ->
|
set( "in", *this ) ->
|
||||||
set( "out", &out ) ->
|
set( "out", &out ) ->
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<bookinfo>
|
<bookinfo>
|
||||||
<title>VIPS Reference Manual</title>
|
<title>VIPS Reference Manual</title>
|
||||||
<releaseinfo>
|
<releaseinfo>
|
||||||
For VIPS 8.2.2.
|
For VIPS 8.3.0.
|
||||||
The latest version of this documentation can be found on the
|
The latest version of this documentation can be found on the
|
||||||
<ulink role="online-location"
|
<ulink role="online-location"
|
||||||
url="http://www.vips.ecs.soton.ac.uk/index.php?title=Documentation">VIPS website</ulink>.
|
url="http://www.vips.ecs.soton.ac.uk/index.php?title=Documentation">VIPS website</ulink>.
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
*
|
*
|
||||||
* 12/8/10
|
* 12/8/10
|
||||||
* - revise window_size / window_offset stuff again
|
* - 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>
|
template <typename T>
|
||||||
static void inline
|
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.
|
/* Ultra-high-quality version for double images.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -461,12 +592,14 @@ vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VIPS_FORMAT_UINT:
|
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 );
|
cxf, cyf );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIPS_FORMAT_INT:
|
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 );
|
cxf, cyf );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -160,9 +160,76 @@ reduceh_float_tab( VipsPel *pout, const VipsPel *pin,
|
|||||||
for( int z = 0; z < bands; z++ ) {
|
for( int z = 0; z < bands; z++ ) {
|
||||||
out[z] =
|
out[z] =
|
||||||
c0 * in[0] +
|
c0 * in[0] +
|
||||||
c1 * in[1] +
|
c1 * in[b1] +
|
||||||
c2 * in[2] +
|
c2 * in[b2] +
|
||||||
c3 * in[3];
|
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;
|
in += 1;
|
||||||
}
|
}
|
||||||
@ -222,7 +289,7 @@ vips_reduceh_gen( VipsRegion *out_region, void *seq,
|
|||||||
|
|
||||||
s.left = r->left * reduceh->xshrink;
|
s.left = r->left * reduceh->xshrink;
|
||||||
s.top = r->top;
|
s.top = r->top;
|
||||||
s.width = r->width * reduceh->xshrink + 3;
|
s.width = r->width * reduceh->xshrink + 4;
|
||||||
s.height = r->height;
|
s.height = r->height;
|
||||||
if( vips_region_prepare( ir, &s ) )
|
if( vips_region_prepare( ir, &s ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
@ -271,12 +338,14 @@ vips_reduceh_gen( VipsRegion *out_region, void *seq,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VIPS_FORMAT_UINT:
|
case VIPS_FORMAT_UINT:
|
||||||
reduceh_float_tab<unsigned int>(
|
reduceh_unsigned_int32_tab
|
||||||
|
<unsigned int, INT_MAX>(
|
||||||
q, p, bands, cxf );
|
q, p, bands, cxf );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIPS_FORMAT_INT:
|
case VIPS_FORMAT_INT:
|
||||||
reduceh_float_tab<signed int>(
|
reduceh_signed_int32_tab
|
||||||
|
<signed int, INT_MIN, INT_MAX>(
|
||||||
q, p, bands, cxf );
|
q, p, bands, cxf );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -326,9 +395,9 @@ vips_reduceh_build( VipsObject *object )
|
|||||||
"%s", _( "reduce factors should be >= 1" ) );
|
"%s", _( "reduce factors should be >= 1" ) );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
if( reduceh->xshrink > 2 )
|
if( reduceh->xshrink > 3 )
|
||||||
vips_warn( object_class->nickname,
|
vips_warn( object_class->nickname,
|
||||||
"%s", _( "reduce factor greater than 2" ) );
|
"%s", _( "reduce factor greater than 3" ) );
|
||||||
|
|
||||||
if( reduceh->xshrink == 1 )
|
if( reduceh->xshrink == 1 )
|
||||||
return( vips_image_write( in, resample->out ) );
|
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>
|
template <typename T>
|
||||||
static void inline
|
static void inline
|
||||||
reducev_float_tab( VipsPel *pout, const VipsPel *pin,
|
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.
|
/* Ultra-high-quality version for double images.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@ -231,7 +301,7 @@ vips_reducev_gen( VipsRegion *out_region, void *seq,
|
|||||||
s.left = r->left;
|
s.left = r->left;
|
||||||
s.top = r->top * reducev->yshrink;
|
s.top = r->top * reducev->yshrink;
|
||||||
s.width = r->width;
|
s.width = r->width;
|
||||||
s.height = r->height * reducev->yshrink + 3;
|
s.height = r->height * reducev->yshrink + 4;
|
||||||
if( vips_region_prepare( ir, &s ) )
|
if( vips_region_prepare( ir, &s ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
@ -274,11 +344,15 @@ vips_reducev_gen( VipsRegion *out_region, void *seq,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case VIPS_FORMAT_UINT:
|
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;
|
break;
|
||||||
|
|
||||||
case VIPS_FORMAT_INT:
|
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;
|
break;
|
||||||
|
|
||||||
case VIPS_FORMAT_FLOAT:
|
case VIPS_FORMAT_FLOAT:
|
||||||
@ -322,9 +396,9 @@ vips_reducev_build( VipsObject *object )
|
|||||||
"%s", _( "reduce factors should be >= 1" ) );
|
"%s", _( "reduce factors should be >= 1" ) );
|
||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
if( reducev->yshrink > 2 )
|
if( reducev->yshrink > 3 )
|
||||||
vips_warn( object_class->nickname,
|
vips_warn( object_class->nickname,
|
||||||
"%s", _( "reduce factor greater than 2" ) );
|
"%s", _( "reduce factor greater than 3" ) );
|
||||||
|
|
||||||
if( reducev->yshrink == 1 )
|
if( reducev->yshrink == 1 )
|
||||||
return( vips_image_write( in, resample->out ) );
|
return( vips_image_write( in, resample->out ) );
|
||||||
|
@ -52,6 +52,28 @@
|
|||||||
|
|
||||||
#include "presample.h"
|
#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 );
|
G_DEFINE_ABSTRACT_TYPE( VipsResample, vips_resample, VIPS_TYPE_OPERATION );
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
* rest of vips
|
* rest of vips
|
||||||
* 13/8/14
|
* 13/8/14
|
||||||
* - oops, missing scale from b, thanks Topochicho
|
* - 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 );
|
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.
|
/* Fixed-point integer bicubic, used for 8 and 16-bit types.
|
||||||
*/
|
*/
|
||||||
template <typename T> static int inline
|
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 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* restrict cx, const int* restrict cy )
|
||||||
{
|
{
|
||||||
const int r0 = cubic_unsigned_int<T>(
|
const int c0 = cx[0];
|
||||||
uno_one, uno_two, uno_thr, uno_fou, cx );
|
const int c1 = cx[1];
|
||||||
const int r1 = cubic_unsigned_int<T>(
|
const int c2 = cx[2];
|
||||||
dos_one, dos_two, dos_thr, dos_fou, cx );
|
const int c3 = cx[3];
|
||||||
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 );
|
|
||||||
|
|
||||||
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
|
static int inline
|
||||||
@ -197,18 +206,6 @@ signed_fixed_round( int v )
|
|||||||
return( (v + round_by) >> VIPS_INTERPOLATE_SHIFT );
|
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.
|
/* Fixed-point integer bicubic, used for 8 and 16-bit types.
|
||||||
*/
|
*/
|
||||||
template <typename T> static int inline
|
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 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* restrict cx, const int* restrict cy )
|
||||||
{
|
{
|
||||||
const int r0 = cubic_signed_int<T>(
|
const int c0 = cx[0];
|
||||||
uno_one, uno_two, uno_thr, uno_fou, cx );
|
const int c1 = cx[1];
|
||||||
const int r1 = cubic_signed_int<T>(
|
const int c2 = cx[2];
|
||||||
dos_one, dos_two, dos_thr, dos_fou, cx );
|
const int c3 = cx[3];
|
||||||
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 );
|
|
||||||
|
|
||||||
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
|
template <typename T> static T inline
|
||||||
|
@ -11,7 +11,6 @@ from gi.repository import Vips
|
|||||||
|
|
||||||
Vips.leak_set(True)
|
Vips.leak_set(True)
|
||||||
|
|
||||||
|
|
||||||
unsigned_formats = [Vips.BandFormat.UCHAR,
|
unsigned_formats = [Vips.BandFormat.UCHAR,
|
||||||
Vips.BandFormat.USHORT,
|
Vips.BandFormat.USHORT,
|
||||||
Vips.BandFormat.UINT]
|
Vips.BandFormat.UINT]
|
||||||
|
@ -10,6 +10,20 @@ from gi.repository import Vips
|
|||||||
|
|
||||||
Vips.leak_set(True)
|
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
|
# Run a function expecting a complex image on a two-band image
|
||||||
def run_cmplx(fn, image):
|
def run_cmplx(fn, image):
|
||||||
if image.format == Vips.BandFormat.FLOAT:
|
if image.format == Vips.BandFormat.FLOAT:
|
||||||
@ -105,13 +119,14 @@ class TestResample(unittest.TestCase):
|
|||||||
bicubic = Vips.Interpolate.new("bicubic")
|
bicubic = Vips.Interpolate.new("bicubic")
|
||||||
|
|
||||||
for fac in [1, 1.1, 1.5, 1.999]:
|
for fac in [1, 1.1, 1.5, 1.999]:
|
||||||
print("fac =", fac)
|
for fmt in all_formats:
|
||||||
r = im.reduce(fac, fac)
|
x = im.cast(fmt)
|
||||||
a = im.affine([1.0 / fac, 0, 0, 1.0 / fac], interpolate = bicubic)
|
r = x.reduce(fac, fac)
|
||||||
r.write_to_file("r.v")
|
a = x.affine([1.0 / fac, 0, 0, 1.0 / fac],
|
||||||
a.write_to_file("a.v")
|
interpolate = bicubic,
|
||||||
d = (r - a).abs().max()
|
oarea = [0, 0, x.width / fac, x.height / fac])
|
||||||
self.assertLess(d, 0.1)
|
d = (r - a).abs().max()
|
||||||
|
self.assertLess(d, 5)
|
||||||
|
|
||||||
def test_resize(self):
|
def test_resize(self):
|
||||||
im = Vips.Image.new_from_file("images/IMG_4618.jpg")
|
im = Vips.Image.new_from_file("images/IMG_4618.jpg")
|
||||||
|
Loading…
Reference in New Issue
Block a user