allow non-square vips_resize()

in a very crude way
This commit is contained in:
John Cupitt 2015-11-19 17:09:18 +00:00
parent 8506ff13a6
commit 2620f3b8c9
2 changed files with 49 additions and 17 deletions

View File

@ -13,6 +13,7 @@
a x2 saving in C stack use in many cases
- added vips_mapim() ... resample with an index image, plus test
- try to improve vips_resize() quality a little more
- vips_resize() can do non-square resizes
7/5/15 started 8.1.1
- oop, vips-8.0 wrapper script should be vips-8.1, thanks Danilo

View File

@ -62,6 +62,7 @@ typedef struct _VipsResize {
VipsResample parent_instance;
double scale;
double vscale;
VipsInterpolate *interpolate;
double idx;
double idy;
@ -84,9 +85,12 @@ vips_resize_build( VipsObject *object )
VipsImage *in;
int window_size;
int int_shrink;
int int_hshrink;
int int_vshrink;
int int_shrink_width;
double residual;
int int_shrink_height;
double hresidual;
double vresidual;
double sigma;
gboolean anti_alias;
@ -106,6 +110,11 @@ vips_resize_build( VipsObject *object )
VIPS_UNREF( interpolate );
}
/* Unset vscale means it's equal to hscale.
*/
if( !vips_object_argument_isset( object, "vscale" ) )
resize->vscale = resize->scale;
in = resample->in;
window_size = resize->interpolate ?
@ -114,25 +123,31 @@ vips_resize_build( VipsObject *object )
/* If the factor is > 1.0, we need to zoom rather than shrink.
* Just set the int part to 1 in this case.
*/
int_shrink = resize->scale > 1.0 ? 1 : floor( 1.0 / resize->scale );
int_hshrink = resize->scale > 1.0 ? 1 : floor( 1.0 / resize->scale );
int_vshrink = resize->vscale > 1.0 ? 1 : floor( 1.0 / resize->vscale );
/* We want to shrink by less for interpolators with larger windows.
*/
int_shrink = VIPS_MAX( 1,
int_shrink / VIPS_MAX( 1, window_size / 2 ) );
int_hshrink = VIPS_MAX( 1,
int_hshrink / VIPS_MAX( 1, window_size / 2 ) );
int_vshrink = VIPS_MAX( 1,
int_vshrink / VIPS_MAX( 1, window_size / 2 ) );
/* Size after int shrink.
*/
int_shrink_width = in->Xsize / int_shrink;
int_shrink_width = in->Xsize / int_hshrink;
int_shrink_height = in->Ysize / int_vshrink;
/* Therefore residual scale factor is.
*/
residual = (in->Xsize * resize->scale) / int_shrink_width;
hresidual = (in->Xsize * resize->scale) / int_shrink_width;
vresidual = (in->Ysize * resize->vscale) / int_shrink_height;
/* A copy for enlarge resize.
*/
vips_info( class->nickname, "box shrink by x %d", int_shrink );
if( vips_shrink( in, &t[0], int_shrink, int_shrink, NULL ) )
vips_info( class->nickname, "box shrink by %d x %d",
int_hshrink, int_vshrink );
if( vips_shrink( in, &t[0], int_hshrink, int_vshrink, NULL ) )
return( -1 );
in = t[0];
@ -165,7 +180,7 @@ vips_resize_build( VipsObject *object )
* the number of scanlines we need to keep for the worst case is
* 2 * @tile_height / @residual, plus a little extra.
*/
if( int_shrink > 1 ) {
if( int_vshrink > 1 ) {
int tile_width;
int tile_height;
int n_lines;
@ -174,7 +189,7 @@ vips_resize_build( VipsObject *object )
vips_get_tile_size( in,
&tile_width, &tile_height, &n_lines );
need_lines = 1.2 * n_lines / residual;
need_lines = 1.2 * n_lines / vresidual;
if( vips_tilecache( in, &t[6],
"tile_width", in->Xsize,
"tile_height", 10,
@ -191,9 +206,12 @@ vips_resize_build( VipsObject *object )
*
* Don't blur for very small shrinks, blur with radius 1 for x1.5
* shrinks, blur radius 2 for x2.5 shrinks and above, etc.
*
* Don't try to be clever for non-rectangular shrinks. We just
* consider the horizontal factor.
*/
sigma = ((1.0 / residual) - 0.5) / 2.0;
anti_alias = residual < 1.0 && sigma > 0.1;
sigma = ((1.0 / hresidual) - 0.5) / 2.0;
anti_alias = hresidual < 1.0 && sigma > 0.1;
if( anti_alias ) {
vips_info( class->nickname, "anti-alias sigma %g", sigma );
if( vips_gaussblur( in, &t[2], sigma, NULL ) )
@ -201,11 +219,12 @@ vips_resize_build( VipsObject *object )
in = t[2];
}
vips_info( class->nickname, "residual affine %g", residual );
vips_info( class->nickname, "residual affine %g x %g",
hresidual, vresidual );
vips_info( class->nickname, "%s interpolation",
VIPS_OBJECT_GET_CLASS( resize->interpolate )->nickname );
if( vips_affine( in, &t[3], residual, 0, 0, residual,
if( vips_affine( in, &t[3], hresidual, 0, 0, vresidual,
"interpolate", resize->interpolate,
"idx", resize->idx,
"idy", resize->idy,
@ -216,7 +235,7 @@ vips_resize_build( VipsObject *object )
/* If we are upsampling, don't sharpen. Also don't sharpen if we
* skipped the anti-alias filter.
*/
if( int_shrink >= 1 &&
if( int_hshrink >= 1 &&
anti_alias ) {
vips_info( class->nickname, "final sharpen" );
t[5] = vips_image_new_matrixv( 3, 3,
@ -261,6 +280,13 @@ vips_resize_class_init( VipsResizeClass *class )
G_STRUCT_OFFSET( VipsResize, scale ),
0, 10000000, 0 );
VIPS_ARG_DOUBLE( class, "vscale", 113,
_( "Vertical scale factor" ),
_( "Vertical scale image by this factor" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsResize, vscale ),
0, 10000000, 0 );
VIPS_ARG_INTERPOLATE( class, "interpolate", 2,
_( "Interpolate" ),
_( "Interpolate pixels with this" ),
@ -296,6 +322,7 @@ vips_resize_init( VipsResize *resize )
*
* Optional arguments:
*
* @vscale: vertical scale factor
* @interpolate: interpolate pixels with this
* @idx: input horizontal offset
* @idy: input vertical offset
@ -307,9 +334,13 @@ vips_resize_init( VipsResize *resize )
* then resampled with vips_affine() and the supplied interpolator, then
* sharpened.
*
* vips_resize() normally maintains the image apect ratio. If you set
* @vscale, that factor is used for the vertical scale and @scale for the
* horizontal.
*
* @interpolate defaults to bicubic.
*
* @idx, @idy default to zero. Offset them by 0.5 to get pixel-centre sampling.
* @idx, @idy default to zero. Set them to 0.5 to get pixel-centre sampling.
*
* This operation does not change xres or yres. The image resolution needs to
* be updated by the application.