added vips_gaussblur()
This commit is contained in:
parent
82f680484c
commit
5e0a9f941f
@ -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
13
TODO
@ -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
|
||||
|
||||
|
@ -12,6 +12,7 @@ libconvolution_la_SOURCES = \
|
||||
fastcor.c \
|
||||
spcor.c \
|
||||
sharpen.c \
|
||||
gaussblur.c \
|
||||
im_aconv.c \
|
||||
im_aconvsep.c \
|
||||
im_conv.c \
|
||||
|
@ -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();
|
||||
}
|
||||
|
180
libvips/convolution/gaussblur.c
Normal file
180
libvips/convolution/gaussblur.c
Normal 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 );
|
||||
}
|
@ -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.
|
||||
*
|
||||
|
@ -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 );
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user