added vips_gaussblur()
This commit is contained in:
parent
82f680484c
commit
5e0a9f941f
|
@ -22,6 +22,7 @@
|
||||||
- add --linear mode to vipsthumbnail
|
- add --linear mode to vipsthumbnail
|
||||||
- support XYZ as a PCS for vips_icc_import() and vips_icc_export()
|
- support XYZ as a PCS for vips_icc_import() and vips_icc_export()
|
||||||
- add --strip option to jpegsave
|
- add --strip option to jpegsave
|
||||||
|
- added vips_gaussblur() convenience function
|
||||||
|
|
||||||
18/10/13 started 7.36.3
|
18/10/13 started 7.36.3
|
||||||
- fix compiler warnings in ubuntu 13.10
|
- 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
|
$ time vips sharpen x.v x2.v
|
||||||
vips_resize() as well?
|
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
|
- do morph quickly as simple wrappers over the vips7 operations
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ libconvolution_la_SOURCES = \
|
||||||
fastcor.c \
|
fastcor.c \
|
||||||
spcor.c \
|
spcor.c \
|
||||||
sharpen.c \
|
sharpen.c \
|
||||||
|
gaussblur.c \
|
||||||
im_aconv.c \
|
im_aconv.c \
|
||||||
im_aconvsep.c \
|
im_aconvsep.c \
|
||||||
im_conv.c \
|
im_conv.c \
|
||||||
|
|
|
@ -153,6 +153,7 @@ vips_convolution_operation_init( void )
|
||||||
extern int vips_fastcor_get_type( void );
|
extern int vips_fastcor_get_type( void );
|
||||||
extern int vips_spcor_get_type( void );
|
extern int vips_spcor_get_type( void );
|
||||||
extern int vips_sharpen_get_type( void );
|
extern int vips_sharpen_get_type( void );
|
||||||
|
extern int vips_gaussblur_get_type( void );
|
||||||
|
|
||||||
vips_conv_get_type();
|
vips_conv_get_type();
|
||||||
vips_morph_get_type();
|
vips_morph_get_type();
|
||||||
|
@ -161,4 +162,5 @@ vips_convolution_operation_init( void )
|
||||||
vips_fastcor_get_type();
|
vips_fastcor_get_type();
|
||||||
vips_spcor_get_type();
|
vips_spcor_get_type();
|
||||||
vips_sharpen_get_type();
|
vips_sharpen_get_type();
|
||||||
|
vips_gaussblur_get_type();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 *in;
|
||||||
VipsImage *out;
|
VipsImage *out;
|
||||||
|
|
||||||
int mask_size;
|
int radius;
|
||||||
double x1;
|
double x1;
|
||||||
double y2;
|
double y2;
|
||||||
double y3;
|
double y3;
|
||||||
|
@ -226,14 +226,19 @@ vips_sharpen_build( VipsObject *object )
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Stop at 20% of max ... bit mean, but means mask radius is roughly
|
/* 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,
|
"separable", TRUE,
|
||||||
"integer", TRUE,
|
"integer", TRUE,
|
||||||
NULL ) )
|
NULL ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
printf( "sharpen: blurring with:\n" );
|
||||||
|
vips_matrixprint( t[1], NULL );
|
||||||
|
#endif /*DEBUG*/
|
||||||
|
|
||||||
/* Build the int lut.
|
/* Build the int lut.
|
||||||
*/
|
*/
|
||||||
sharpen->ix1 = ix1 = sharpen->x1 * 327.67;
|
sharpen->ix1 = ix1 = sharpen->x1 * 327.67;
|
||||||
|
@ -310,42 +315,42 @@ vips_sharpen_class_init( VipsSharpenClass *class )
|
||||||
VIPS_ARGUMENT_REQUIRED_OUTPUT,
|
VIPS_ARGUMENT_REQUIRED_OUTPUT,
|
||||||
G_STRUCT_OFFSET( VipsSharpen, out ) );
|
G_STRUCT_OFFSET( VipsSharpen, out ) );
|
||||||
|
|
||||||
VIPS_ARG_INT( class, "mask_size", 3,
|
VIPS_ARG_INT( class, "radius", 3,
|
||||||
_( "mask_size" ),
|
_( "Radius" ),
|
||||||
_( "Mask radius" ),
|
_( "Mask radius" ),
|
||||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
G_STRUCT_OFFSET( VipsSharpen, mask_size ),
|
G_STRUCT_OFFSET( VipsSharpen, radius ),
|
||||||
1, 1000000, 7 );
|
1, 1000000, 3 );
|
||||||
|
|
||||||
VIPS_ARG_DOUBLE( class, "x1", 4,
|
VIPS_ARG_DOUBLE( class, "x1", 5,
|
||||||
_( "x1" ),
|
_( "x1" ),
|
||||||
_( "Flat/jaggy threshold" ),
|
_( "Flat/jaggy threshold" ),
|
||||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
G_STRUCT_OFFSET( VipsSharpen, x1 ),
|
G_STRUCT_OFFSET( VipsSharpen, x1 ),
|
||||||
1, 1000000, 1.5 );
|
1, 1000000, 1.5 );
|
||||||
|
|
||||||
VIPS_ARG_DOUBLE( class, "y2", 5,
|
VIPS_ARG_DOUBLE( class, "y2", 6,
|
||||||
_( "y2" ),
|
_( "y2" ),
|
||||||
_( "Maximum brightening" ),
|
_( "Maximum brightening" ),
|
||||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
G_STRUCT_OFFSET( VipsSharpen, y2 ),
|
G_STRUCT_OFFSET( VipsSharpen, y2 ),
|
||||||
1, 1000000, 20 );
|
1, 1000000, 20 );
|
||||||
|
|
||||||
VIPS_ARG_DOUBLE( class, "y3", 6,
|
VIPS_ARG_DOUBLE( class, "y3", 7,
|
||||||
_( "y3" ),
|
_( "y3" ),
|
||||||
_( "Maximum darkening" ),
|
_( "Maximum darkening" ),
|
||||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
G_STRUCT_OFFSET( VipsSharpen, y3 ),
|
G_STRUCT_OFFSET( VipsSharpen, y3 ),
|
||||||
1, 1000000, 50 );
|
1, 1000000, 50 );
|
||||||
|
|
||||||
VIPS_ARG_DOUBLE( class, "m1", 7,
|
VIPS_ARG_DOUBLE( class, "m1", 8,
|
||||||
_( "m1" ),
|
_( "m1" ),
|
||||||
_( "Slope for flat areas" ),
|
_( "Slope for flat areas" ),
|
||||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
G_STRUCT_OFFSET( VipsSharpen, m1 ),
|
G_STRUCT_OFFSET( VipsSharpen, m1 ),
|
||||||
1, 1000000, 1 );
|
1, 1000000, 1 );
|
||||||
|
|
||||||
VIPS_ARG_DOUBLE( class, "m2", 8,
|
VIPS_ARG_DOUBLE( class, "m2", 9,
|
||||||
_( "m2" ),
|
_( "m2" ),
|
||||||
_( "Slope for jaggy areas" ),
|
_( "Slope for jaggy areas" ),
|
||||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||||
|
@ -357,7 +362,7 @@ vips_sharpen_class_init( VipsSharpenClass *class )
|
||||||
static void
|
static void
|
||||||
vips_sharpen_init( VipsSharpen *sharpen )
|
vips_sharpen_init( VipsSharpen *sharpen )
|
||||||
{
|
{
|
||||||
sharpen->mask_size = 7;
|
sharpen->radius = 3;
|
||||||
sharpen->x1 = 1.5;
|
sharpen->x1 = 1.5;
|
||||||
sharpen->y2 = 20;
|
sharpen->y2 = 20;
|
||||||
sharpen->y3 = 50;
|
sharpen->y3 = 50;
|
||||||
|
@ -373,7 +378,7 @@ vips_sharpen_init( VipsSharpen *sharpen )
|
||||||
*
|
*
|
||||||
* Optional arguments:
|
* Optional arguments:
|
||||||
*
|
*
|
||||||
* @mask_size: how large a mask to use
|
* @radius: how large a mask to use
|
||||||
* @x1: flat/jaggy threshold
|
* @x1: flat/jaggy threshold
|
||||||
* @y2: maximum amount of brightening
|
* @y2: maximum amount of brightening
|
||||||
* @y3: maximum amount of darkening
|
* @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
|
* Selectively sharpen the L channel of a LAB image. The input image is
|
||||||
* transformed to #VIPS_INTERPRETATION_LABS.
|
* 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
|
* 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
|
* through a lookup table formed from the five parameters and added back to
|
||||||
* @in.
|
* @in.
|
||||||
|
@ -413,7 +418,7 @@ vips_sharpen_init( VipsSharpen *sharpen )
|
||||||
* For printing, we recommend the following settings (the defaults):
|
* For printing, we recommend the following settings (the defaults):
|
||||||
*
|
*
|
||||||
* |[
|
* |[
|
||||||
mask_size == 7
|
radius == 3
|
||||||
x1 == 1.5
|
x1 == 1.5
|
||||||
y2 == 20 (don't brighten by more than 20 L*)
|
y2 == 20 (don't brighten by more than 20 L*)
|
||||||
y3 == 50 (can darken by up to 50 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
|
* If you want more or less sharpening, we suggest you just change the m1
|
||||||
* and m2 parameters.
|
* 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
|
* adjusted according to the output printing resolution. As an approximate
|
||||||
* guideline, use 3 for 4 pixels/mm (CRT display resolution), 5 for 8
|
* guideline, use 1 for 4 pixels/mm (CRT display resolution), 2 for 8
|
||||||
* pixels/mm, 7 for 12 pixels/mm and 9 for 16 pixels/mm (300 dpi == 12
|
* 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
|
* pixels/mm). These figures refer to the image raster, not the half-tone
|
||||||
* resolution.
|
* resolution.
|
||||||
*
|
*
|
||||||
|
|
|
@ -80,6 +80,8 @@ int vips_morph( VipsImage *in, VipsImage **out, VipsImage *mask,
|
||||||
|
|
||||||
int vips_sharpen( VipsImage *in, VipsImage **out, ... )
|
int vips_sharpen( VipsImage *in, VipsImage **out, ... )
|
||||||
__attribute__((sentinel));
|
__attribute__((sentinel));
|
||||||
|
int vips_gaussblur( VipsImage *in, VipsImage **out, int radius, ... )
|
||||||
|
__attribute__((sentinel));
|
||||||
|
|
||||||
void vips_convolution_operation_init( void );
|
void vips_convolution_operation_init( void );
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue