Skip to content

Fix the pixel shift within reduce (#703) #1592

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 9 additions & 16 deletions libvips/resample/bicubic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,16 +79,15 @@ typedef VipsInterpolate VipsInterpolateBicubic;
typedef VipsInterpolateClass VipsInterpolateBicubicClass;

/* Precalculated interpolation matrices. int (used for pel
* sizes up to short), and double (for all others). We go to
* scale + 1 so we can round-to-nearest safely.
* sizes up to short), and double (for all others).
*/

/* We could keep a large set of 2d 4x4 matricies, but this actually
* works out slower since for many resizes the thing will no longer
* fit in L1.
*/
static int vips_bicubic_matrixi[VIPS_TRANSFORM_SCALE + 1][4];
static double vips_bicubic_matrixf[VIPS_TRANSFORM_SCALE + 1][4];
static int vips_bicubic_matrixi[VIPS_TRANSFORM_SCALE][4];
static double vips_bicubic_matrixf[VIPS_TRANSFORM_SCALE][4];

/* We need C linkage for this.
*/
Expand Down Expand Up @@ -498,19 +497,13 @@ static void
vips_interpolate_bicubic_interpolate( VipsInterpolate *interpolate,
void *out, VipsRegion *in, double x, double y )
{
/* Find the mask index. We round-to-nearest, so we need to generate
* indexes in 0 to VIPS_TRANSFORM_SCALE, 2^n + 1 values. We multiply
* by 2 more than we need to, add one, mask, then shift down again to
* get the extra range.
/* Find the mask index.
*/
const int sx = x * VIPS_TRANSFORM_SCALE * 2;
const int sy = y * VIPS_TRANSFORM_SCALE * 2;
const int sx = x * VIPS_TRANSFORM_SCALE;
const int sy = y * VIPS_TRANSFORM_SCALE;

const int six = sx & (VIPS_TRANSFORM_SCALE * 2 - 1);
const int siy = sy & (VIPS_TRANSFORM_SCALE * 2 - 1);

const int tx = (six + 1) >> 1;
const int ty = (siy + 1) >> 1;
const int tx = sx & (VIPS_TRANSFORM_SCALE - 1);
const int ty = sy & (VIPS_TRANSFORM_SCALE - 1);

/* We know x/y are always positive, so we can just (int) them.
*/
Expand Down Expand Up @@ -643,7 +636,7 @@ vips_interpolate_bicubic_class_init( VipsInterpolateBicubicClass *iclass )

/* Build the tables of pre-computed coefficients.
*/
for( int x = 0; x < VIPS_TRANSFORM_SCALE + 1; x++ ) {
for( int x = 0; x < VIPS_TRANSFORM_SCALE; x++ ) {
calculate_coefficients_catmull( vips_bicubic_matrixf[x],
(float) x / VIPS_TRANSFORM_SCALE );

Expand Down
36 changes: 13 additions & 23 deletions libvips/resample/reduce.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
* - rename xshrink -> hshrink for greater consistency
* 9/9/16
* - add @centre option
* 6/6/20 kleisauke
* - deprecate @centre option, it's now always on
*/

/*
Expand Down Expand Up @@ -78,14 +80,10 @@
* Optional arguments:
*
* * @kernel: #VipsKernel to use to interpolate (default: lanczos3)
* * @centre: %gboolean use centre rather than corner sampling convention
*
* Reduce @in vertically by a float factor. The pixels in @out are
* interpolated with a 1D mask generated by @kernel.
*
* Set @centre to use centre rather than corner sampling convention. Centre
* convention can be useful to match the behaviour of other systems.
*
* This is a very low-level operation: see vips_resize() for a more
* convenient way to resize images.
*
Expand All @@ -107,14 +105,10 @@
* Optional arguments:
*
* * @kernel: #VipsKernel to use to interpolate (default: lanczos3)
* * @centre: %gboolean use centre rather than corner sampling convention
*
* Reduce @in horizontally by a float factor. The pixels in @out are
* interpolated with a 1D mask generated by @kernel.
*
* Set @centre to use centre rather than corner sampling convention. Centre
* convention can be useful to match the behaviour of other systems.
*
* This is a very low-level operation: see vips_resize() for a more
* convenient way to resize images.
*
Expand All @@ -136,7 +130,7 @@ typedef struct _VipsReduce {
*/
VipsKernel kernel;

/* Use centre rather than corner sampling convention.
/* Deprecated.
*/
gboolean centre;

Expand All @@ -152,18 +146,16 @@ vips_reduce_build( VipsObject *object )
VipsResample *resample = VIPS_RESAMPLE( object );
VipsReduce *reduce = (VipsReduce *) object;
VipsImage **t = (VipsImage **)
vips_object_local_array( object, 3 );
vips_object_local_array( object, 2 );

if( VIPS_OBJECT_CLASS( vips_reduce_parent_class )->build( object ) )
return( -1 );

if( vips_reducev( resample->in, &t[0], reduce->vshrink,
"kernel", reduce->kernel,
"centre", reduce->centre,
NULL ) ||
vips_reduceh( t[0], &t[1], reduce->hshrink,
"kernel", reduce->kernel,
"centre", reduce->centre,
NULL ) ||
vips_image_write( t[1], resample->out ) )
return( -1 );
Expand Down Expand Up @@ -210,13 +202,6 @@ vips_reduce_class_init( VipsReduceClass *class )
G_STRUCT_OFFSET( VipsReduce, kernel ),
VIPS_TYPE_KERNEL, VIPS_KERNEL_LANCZOS3 );

VIPS_ARG_BOOL( class, "centre", 7,
_( "Centre" ),
_( "Use centre sampling convention" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsReduce, centre ),
FALSE );

/* The old names .. now use h and v everywhere.
*/
VIPS_ARG_DOUBLE( class, "xshrink", 8,
Expand All @@ -233,6 +218,15 @@ vips_reduce_class_init( VipsReduceClass *class )
G_STRUCT_OFFSET( VipsReduce, vshrink ),
1.0, 1000000.0, 1.0 );

/* We used to let people pick centre or corner, but it's automatic now.
*/
VIPS_ARG_BOOL( class, "centre", 7,
_( "Centre" ),
_( "Use centre sampling convention" ),
VIPS_ARGUMENT_OPTIONAL_INPUT | VIPS_ARGUMENT_DEPRECATED,
G_STRUCT_OFFSET( VipsReduce, centre ),
FALSE );

}

static void
Expand All @@ -252,14 +246,10 @@ vips_reduce_init( VipsReduce *reduce )
* Optional arguments:
*
* * @kernel: #VipsKernel to use to interpolate (default: lanczos3)
* * @centre: %gboolean use centre rather than corner sampling convention
*
* Reduce @in by a pair of factors with a pair of 1D kernels. This
* will not work well for shrink factors greater than three.
*
* Set @centre to use centre rather than corner sampling convention. Centre
* convention can be useful to match the behaviour of other systems.
*
* This is a very low-level operation: see vips_resize() for a more
* convenient way to resize images.
*
Expand Down
Loading