upsize with something other than nearest
vips_resize() uses to just use nearest when upsizing, following standard practice in repro. This is often unfortunate for image processing, where small nearest upsizes will produce obvious aliasing. It now picks a VipsInterpolate which corresponds (roughly) to the selected VipsKernel and uses that with affine for any upsizing.
This commit is contained in:
parent
6f52f14fc5
commit
65105a9442
@ -26,6 +26,7 @@
|
|||||||
- better accuracy for reducev with smarter multiplication
|
- better accuracy for reducev with smarter multiplication
|
||||||
- better quality for vips_resize() with linear/cubic kernels
|
- better quality for vips_resize() with linear/cubic kernels
|
||||||
- pyvips8 can create new metadata
|
- pyvips8 can create new metadata
|
||||||
|
- better upsizing with vips_resize()
|
||||||
|
|
||||||
18/5/16 started 8.3.2
|
18/5/16 started 8.3.2
|
||||||
- more robust vips image reading
|
- more robust vips image reading
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
* 16/6/16
|
* 16/6/16
|
||||||
* - better quality for linear/cubic kernels ... do more shrink and less
|
* - better quality for linear/cubic kernels ... do more shrink and less
|
||||||
* reduce
|
* reduce
|
||||||
|
* 22/6/16
|
||||||
|
* - faster and better upsizing
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -124,6 +126,27 @@ vips_resize_int_shrink( VipsResize *resize, double scale )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Suggest a VipsInterpolate which corresponds to a VipsKernel. We use
|
||||||
|
* this to pick a thing for affine().
|
||||||
|
*/
|
||||||
|
static const char *
|
||||||
|
vips_resize_interpolate( VipsKernel kernel )
|
||||||
|
{
|
||||||
|
switch( kernel ) {
|
||||||
|
case VIPS_KERNEL_NEAREST:
|
||||||
|
return( "nearest" );
|
||||||
|
|
||||||
|
case VIPS_KERNEL_LINEAR:
|
||||||
|
return( "bilinear" );
|
||||||
|
|
||||||
|
/* Use cubic for everything else. There are other interpolators, like
|
||||||
|
* nohalo, but they don't really correspond well to any kernel.
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
return( "bicubic" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vips_resize_build( VipsObject *object )
|
vips_resize_build( VipsObject *object )
|
||||||
{
|
{
|
||||||
@ -252,23 +275,44 @@ vips_resize_build( VipsObject *object )
|
|||||||
|
|
||||||
/* Any upsizing.
|
/* Any upsizing.
|
||||||
*/
|
*/
|
||||||
if( hresidual > 1.0 ) {
|
if( hresidual > 1.0 ||
|
||||||
vips_info( class->nickname, "residual scaleh %g",
|
vresidual > 1.0 ) {
|
||||||
hresidual );
|
const char *nickname = vips_resize_interpolate( resize->kernel );
|
||||||
if( vips_affine( in, &t[4], hresidual, 0.0, 0.0, 1.0,
|
VipsInterpolate *interpolate;
|
||||||
"interpolate", vips_interpolate_nearest_static(),
|
|
||||||
NULL ) )
|
|
||||||
return( -1 );
|
|
||||||
in = t[4];
|
|
||||||
}
|
|
||||||
|
|
||||||
if( vresidual > 1.0 ) {
|
if( !(interpolate = vips_interpolate_new( nickname )) )
|
||||||
vips_info( class->nickname, "residual scalev %g", vresidual );
|
return( -1 );
|
||||||
if( vips_affine( in, &t[5], 1.0, 0.0, 0.0, vresidual,
|
vips_object_local( object, interpolate );
|
||||||
"interpolate", vips_interpolate_nearest_static(),
|
|
||||||
NULL ) )
|
if( hresidual > 1.0 &&
|
||||||
return( -1 );
|
vresidual > 1.0 ) {
|
||||||
in = t[5];
|
vips_info( class->nickname,
|
||||||
|
"residual scale %g x %g", hresidual, vresidual );
|
||||||
|
if( vips_affine( in, &t[4],
|
||||||
|
hresidual, 0.0, 0.0, vresidual,
|
||||||
|
"interpolate", interpolate,
|
||||||
|
NULL ) )
|
||||||
|
return( -1 );
|
||||||
|
in = t[4];
|
||||||
|
}
|
||||||
|
else if( hresidual > 1.0 ) {
|
||||||
|
vips_info( class->nickname,
|
||||||
|
"residual scaleh %g", hresidual );
|
||||||
|
if( vips_affine( in, &t[4], hresidual, 0.0, 0.0, 1.0,
|
||||||
|
"interpolate", interpolate,
|
||||||
|
NULL ) )
|
||||||
|
return( -1 );
|
||||||
|
in = t[4];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vips_info( class->nickname,
|
||||||
|
"residual scalev %g", vresidual );
|
||||||
|
if( vips_affine( in, &t[4], 1.0, 0.0, 0.0, vresidual,
|
||||||
|
"interpolate", interpolate,
|
||||||
|
NULL ) )
|
||||||
|
return( -1 );
|
||||||
|
in = t[4];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if( vips_image_write( in, resample->out ) )
|
if( vips_image_write( in, resample->out ) )
|
||||||
@ -361,20 +405,25 @@ vips_resize_init( VipsResize *resize )
|
|||||||
* * @vscale: %gdouble vertical scale factor
|
* * @vscale: %gdouble vertical scale factor
|
||||||
* * @kernel: #VipsKernel to reduce with
|
* * @kernel: #VipsKernel to reduce with
|
||||||
*
|
*
|
||||||
* Resize an image. When upsizing (@scale > 1), the image is simply block
|
* Resize an image.
|
||||||
* upsized. When downsizing, the
|
*
|
||||||
|
* When downsizing, the
|
||||||
* image is block-shrunk with vips_shrink(),
|
* image is block-shrunk with vips_shrink(),
|
||||||
* then the image is shrunk again to the
|
* then the image is shrunk again to the
|
||||||
* target size with vips_reduce(). How much is done by vips_shrink() vs.
|
* target size with vips_reduce(). How much is done by vips_shrink() vs.
|
||||||
* vips_reduce() varies with the @kernel setting.
|
* vips_reduce() varies with the @kernel setting.
|
||||||
*
|
*
|
||||||
|
* vips_resize() normally uses #VIPS_KERNEL_LANCZOS3 for the final reduce, you
|
||||||
|
* can change this with @kernel.
|
||||||
|
*
|
||||||
|
* When upsizing (@scale > 1), the operation uses vips_affine() with
|
||||||
|
* a #VipsInterpolate selected depending on @kernel. It will use
|
||||||
|
* #VipsInterpolateBicubic for #VIPS_KERNEL_CUBIC and above.
|
||||||
|
*
|
||||||
* vips_resize() normally maintains the image apect ratio. If you set
|
* vips_resize() normally maintains the image apect ratio. If you set
|
||||||
* @vscale, that factor is used for the vertical scale and @scale for the
|
* @vscale, that factor is used for the vertical scale and @scale for the
|
||||||
* horizontal.
|
* horizontal.
|
||||||
*
|
*
|
||||||
* vips_resize() normally uses #VIPS_KERNEL_LANCZOS3 for the final shrink, you
|
|
||||||
* can change this with @kernel.
|
|
||||||
*
|
|
||||||
* This operation does not change xres or yres. The image resolution needs to
|
* This operation does not change xres or yres. The image resolution needs to
|
||||||
* be updated by the application.
|
* be updated by the application.
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user