added vips_gaussblur()

This commit is contained in:
John Cupitt 2013-11-15 12:37:26 +00:00
parent 82f680484c
commit 5e0a9f941f
7 changed files with 220 additions and 22 deletions

View File

@ -22,6 +22,7 @@
- add --linear mode to vipsthumbnail
- support XYZ as a PCS for vips_icc_import() and vips_icc_export()
- add --strip option to jpegsave
- added vips_gaussblur() convenience function
18/10/13 started 7.36.3
- fix compiler warnings in ubuntu 13.10

13
TODO
View File

@ -1,8 +1,15 @@
- we're spending a lot of time on threading
- add vips_gaussian_blur() with approx / int / float precision, maybe
vips_resize() as well?
$ time vips sharpen x.v x2.v
real 0m6.925s
user 0m18.240s
sys 0m0.996s
$ time vips sharpen x.v x2.v --vips-concurrency=1
real 0m12.831s
user 0m10.016s
sys 0m0.480s
could share a base class with vips_sharpen()/
almost 50% of CPU!
- do morph quickly as simple wrappers over the vips7 operations

View File

@ -12,6 +12,7 @@ libconvolution_la_SOURCES = \
fastcor.c \
spcor.c \
sharpen.c \
gaussblur.c \
im_aconv.c \
im_aconvsep.c \
im_conv.c \

View File

@ -153,6 +153,7 @@ vips_convolution_operation_init( void )
extern int vips_fastcor_get_type( void );
extern int vips_spcor_get_type( void );
extern int vips_sharpen_get_type( void );
extern int vips_gaussblur_get_type( void );
vips_conv_get_type();
vips_morph_get_type();
@ -161,4 +162,5 @@ vips_convolution_operation_init( void )
vips_fastcor_get_type();
vips_spcor_get_type();
vips_sharpen_get_type();
vips_gaussblur_get_type();
}

View File

@ -0,0 +1,180 @@
/* Gaussian blur.
*
* 15/11/13
* - from vips_sharpen()
*/
/*
This file is part of VIPS.
VIPS is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301 USA
*/
/*
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
*/
/*
#define DEBUG
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif /*HAVE_CONFIG_H*/
#include <vips/intl.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <vips/vips.h>
typedef struct _VipsGaussblur {
VipsOperation parent_instance;
VipsImage *in;
VipsImage *out;
int radius;
VipsPrecision precision;
} VipsGaussblur;
typedef VipsOperationClass VipsGaussblurClass;
G_DEFINE_TYPE( VipsGaussblur, vips_gaussblur, VIPS_TYPE_OPERATION );
static int
vips_gaussblur_build( VipsObject *object )
{
VipsGaussblur *gaussblur = (VipsGaussblur *) object;
VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 );
if( VIPS_OBJECT_CLASS( vips_gaussblur_parent_class )->build( object ) )
return( -1 );
/* Stop at 20% of max ... bit mean, but means mask radius is roughly
* right.
*/
if( vips_gaussmat( &t[0], gaussblur->radius / 2, 0.2,
"separable", TRUE,
"integer", gaussblur->precision != VIPS_PRECISION_FLOAT,
NULL ) )
return( -1 );
#ifdef DEBUG
printf( "gaussblur: blurring with:\n" );
vips_matrixprint( t[0], NULL );
#endif /*DEBUG*/
if( vips_convsep( gaussblur->in, &t[1], t[0],
"precision", gaussblur->precision,
NULL ) )
return( -1 );
g_object_set( object, "out", vips_image_new(), NULL );
if( vips_image_write( t[1], gaussblur->out ) )
return( -1 );
return( 0 );
}
static void
vips_gaussblur_class_init( VipsGaussblurClass *class )
{
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
VipsObjectClass *object_class = (VipsObjectClass *) class;
gobject_class->set_property = vips_object_set_property;
gobject_class->get_property = vips_object_get_property;
object_class->nickname = "gaussblur";
object_class->description = _( "Unsharp masking for print" );
object_class->build = vips_gaussblur_build;
VIPS_ARG_IMAGE( class, "in", 1,
_( "Input" ),
_( "Input image" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsGaussblur, in ) );
VIPS_ARG_IMAGE( class, "out", 2,
_( "Output" ),
_( "Output image" ),
VIPS_ARGUMENT_REQUIRED_OUTPUT,
G_STRUCT_OFFSET( VipsGaussblur, out ) );
VIPS_ARG_INT( class, "radius", 3,
_( "radius" ),
_( "Mask radius" ),
VIPS_ARGUMENT_REQUIRED_INPUT,
G_STRUCT_OFFSET( VipsGaussblur, radius ),
1, 1000000, 3 );
VIPS_ARG_ENUM( class, "precision", 4,
_( "Precision" ),
_( "Convolve with this precision" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsGaussblur, precision ),
VIPS_TYPE_PRECISION, VIPS_PRECISION_INTEGER );
}
static void
vips_gaussblur_init( VipsGaussblur *gaussblur )
{
gaussblur->radius = 3;
gaussblur->precision = VIPS_PRECISION_INTEGER;
}
/**
* vips_gaussblur:
* @in: input image
* @out: output image
* @radius: how large a mask to use
* @...: %NULL-terminated list of optional named arguments
*
* Optional arguments:
*
* @precision: #VipsPrecision for blur
*
* This operator runs vips_gaussmat() and vips_convsep() for you on an image.
*
* @radius is not used directly. Instead the standard deviation of
* vips_gaussmat() is set to @radius / 2 and the minimum amplitude set to 20%.
* This gives a mask radius of approximately @radius pixels.
*
* See also: vips_gaussmat(), vips_conv().
*
* Returns: 0 on success, -1 on error.
*/
int
vips_gaussblur( VipsImage *in, VipsImage **out, int radius, ... )
{
va_list ap;
int result;
va_start( ap, radius );
result = vips_call_split( "gaussblur", ap, in, out, radius );
va_end( ap );
return( result );
}

View File

@ -92,7 +92,7 @@ typedef struct _VipsSharpen {
VipsImage *in;
VipsImage *out;
int mask_size;
int radius;
double x1;
double y2;
double y3;
@ -226,14 +226,19 @@ vips_sharpen_build( VipsObject *object )
}
/* Stop at 20% of max ... bit mean, but means mask radius is roughly
* right.
* right. We always sharpen a short, so no point using a float mask.
*/
if( vips_gaussmat( &t[1], sharpen->mask_size / 2, 0.2,
if( vips_gaussmat( &t[1], sharpen->radius / 2, 0.2,
"separable", TRUE,
"integer", TRUE,
NULL ) )
return( -1 );
#ifdef DEBUG
printf( "sharpen: blurring with:\n" );
vips_matrixprint( t[1], NULL );
#endif /*DEBUG*/
/* Build the int lut.
*/
sharpen->ix1 = ix1 = sharpen->x1 * 327.67;
@ -310,42 +315,42 @@ vips_sharpen_class_init( VipsSharpenClass *class )
VIPS_ARGUMENT_REQUIRED_OUTPUT,
G_STRUCT_OFFSET( VipsSharpen, out ) );
VIPS_ARG_INT( class, "mask_size", 3,
_( "mask_size" ),
VIPS_ARG_INT( class, "radius", 3,
_( "Radius" ),
_( "Mask radius" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsSharpen, mask_size ),
1, 1000000, 7 );
G_STRUCT_OFFSET( VipsSharpen, radius ),
1, 1000000, 3 );
VIPS_ARG_DOUBLE( class, "x1", 4,
VIPS_ARG_DOUBLE( class, "x1", 5,
_( "x1" ),
_( "Flat/jaggy threshold" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsSharpen, x1 ),
1, 1000000, 1.5 );
VIPS_ARG_DOUBLE( class, "y2", 5,
VIPS_ARG_DOUBLE( class, "y2", 6,
_( "y2" ),
_( "Maximum brightening" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsSharpen, y2 ),
1, 1000000, 20 );
VIPS_ARG_DOUBLE( class, "y3", 6,
VIPS_ARG_DOUBLE( class, "y3", 7,
_( "y3" ),
_( "Maximum darkening" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsSharpen, y3 ),
1, 1000000, 50 );
VIPS_ARG_DOUBLE( class, "m1", 7,
VIPS_ARG_DOUBLE( class, "m1", 8,
_( "m1" ),
_( "Slope for flat areas" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
G_STRUCT_OFFSET( VipsSharpen, m1 ),
1, 1000000, 1 );
VIPS_ARG_DOUBLE( class, "m2", 8,
VIPS_ARG_DOUBLE( class, "m2", 9,
_( "m2" ),
_( "Slope for jaggy areas" ),
VIPS_ARGUMENT_OPTIONAL_INPUT,
@ -357,7 +362,7 @@ vips_sharpen_class_init( VipsSharpenClass *class )
static void
vips_sharpen_init( VipsSharpen *sharpen )
{
sharpen->mask_size = 7;
sharpen->radius = 3;
sharpen->x1 = 1.5;
sharpen->y2 = 20;
sharpen->y3 = 50;
@ -373,7 +378,7 @@ vips_sharpen_init( VipsSharpen *sharpen )
*
* Optional arguments:
*
* @mask_size: how large a mask to use
* @radius: how large a mask to use
* @x1: flat/jaggy threshold
* @y2: maximum amount of brightening
* @y3: maximum amount of darkening
@ -383,7 +388,7 @@ vips_sharpen_init( VipsSharpen *sharpen )
* Selectively sharpen the L channel of a LAB image. The input image is
* transformed to #VIPS_INTERPRETATION_LABS.
*
* The operation performs a gaussian blur of size @mask_size and subtracts
* The operation performs a gaussian blur of radius @radius and subtracts
* from @in to generate a high-frequency signal. This signal is passed
* through a lookup table formed from the five parameters and added back to
* @in.
@ -413,7 +418,7 @@ vips_sharpen_init( VipsSharpen *sharpen )
* For printing, we recommend the following settings (the defaults):
*
* |[
mask_size == 7
radius == 3
x1 == 1.5
y2 == 20 (don't brighten by more than 20 L*)
y3 == 50 (can darken by up to 50 L*)
@ -425,10 +430,10 @@ vips_sharpen_init( VipsSharpen *sharpen )
* If you want more or less sharpening, we suggest you just change the m1
* and m2 parameters.
*
* The @mask_size parameter changes the width of the fringe and can be
* The @radius parameter changes the width of the fringe and can be
* adjusted according to the output printing resolution. As an approximate
* guideline, use 3 for 4 pixels/mm (CRT display resolution), 5 for 8
* pixels/mm, 7 for 12 pixels/mm and 9 for 16 pixels/mm (300 dpi == 12
* guideline, use 1 for 4 pixels/mm (CRT display resolution), 2 for 8
* pixels/mm, 3 for 12 pixels/mm and 4 for 16 pixels/mm (300 dpi == 12
* pixels/mm). These figures refer to the image raster, not the half-tone
* resolution.
*

View File

@ -80,6 +80,8 @@ int vips_morph( VipsImage *in, VipsImage **out, VipsImage *mask,
int vips_sharpen( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
int vips_gaussblur( VipsImage *in, VipsImage **out, int radius, ... )
__attribute__((sentinel));
void vips_convolution_operation_init( void );