1 /* Gaussian blur.
2  *
3  * 15/11/13
4  * 	- from vips_sharpen()
5  * 19/11/14
6  * 	- change parameters to be more imagemagick-like
7  * 21/9/20
8  * 	- allow sigma zero, meaning no blur
9  * 	- sigma < 0.2 is just copy
10  */
11 
12 /*
13 
14     This file is part of VIPS.
15 
16     VIPS is free software; you can redistribute it and/or modify
17     it under the terms of the GNU Lesser General Public License as published by
18     the Free Software Foundation; either version 2 of the License, or
19     (at your option) any later version.
20 
21     This program is distributed in the hope that it will be useful,
22     but WITHOUT ANY WARRANTY; without even the implied warranty of
23     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24     GNU Lesser General Public License for more details.
25 
26     You should have received a copy of the GNU Lesser General Public License
27     along with this program; if not, write to the Free Software
28     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
29     02110-1301  USA
30 
31  */
32 
33 /*
34 
35     These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
36 
37  */
38 
39 /*
40 #define DEBUG
41  */
42 
43 #ifdef HAVE_CONFIG_H
44 #include <config.h>
45 #endif /*HAVE_CONFIG_H*/
46 #include <vips/intl.h>
47 
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <math.h>
51 
52 #include <vips/vips.h>
53 
54 typedef struct _VipsGaussblur {
55 	VipsOperation parent_instance;
56 
57 	VipsImage *in;
58 	VipsImage *out;
59 
60 	gdouble sigma;
61 	gdouble min_ampl;
62 	VipsPrecision precision;
63 
64 } VipsGaussblur;
65 
66 typedef VipsOperationClass VipsGaussblurClass;
67 
68 G_DEFINE_TYPE( VipsGaussblur, vips_gaussblur, VIPS_TYPE_OPERATION );
69 
70 static int
vips_gaussblur_build(VipsObject * object)71 vips_gaussblur_build( VipsObject *object )
72 {
73 	VipsGaussblur *gaussblur = (VipsGaussblur *) object;
74 	VipsImage **t = (VipsImage **) vips_object_local_array( object, 2 );
75 
76 	if( VIPS_OBJECT_CLASS( vips_gaussblur_parent_class )->build( object ) )
77 		return( -1 );
78 
79 	/* vips_gaussmat() will make a 1x1 pixel mask for anything smaller than
80 	 * this.
81 	 */
82 	if( gaussblur->sigma < 0.2 ) {
83 		if( vips_copy( gaussblur->in, &t[1], NULL ) )
84 			return( -1 );
85 	}
86 	else {
87 		if( vips_gaussmat( &t[0],
88 			gaussblur->sigma, gaussblur->min_ampl,
89 			"separable", TRUE,
90 			"precision", gaussblur->precision,
91 			NULL ) )
92 			return( -1 );
93 
94 #ifdef DEBUG
95 		printf( "gaussblur: blurring with:\n" );
96 		vips_matrixprint( t[0], NULL );
97 #endif /*DEBUG*/
98 
99 		g_info( "gaussblur mask width %d", t[0]->Xsize );
100 
101 		if( vips_convsep( gaussblur->in, &t[1], t[0],
102 			"precision", gaussblur->precision,
103 			NULL ) )
104 			return( -1 );
105 	}
106 
107 	g_object_set( object, "out", vips_image_new(), NULL );
108 
109 	if( vips_image_write( t[1], gaussblur->out ) )
110 		return( -1 );
111 
112 	return( 0 );
113 }
114 
115 static void
vips_gaussblur_class_init(VipsGaussblurClass * class)116 vips_gaussblur_class_init( VipsGaussblurClass *class )
117 {
118 	GObjectClass *gobject_class = G_OBJECT_CLASS( class );
119 	VipsObjectClass *object_class = (VipsObjectClass *) class;
120 	VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
121 
122 	gobject_class->set_property = vips_object_set_property;
123 	gobject_class->get_property = vips_object_get_property;
124 
125 	object_class->nickname = "gaussblur";
126 	object_class->description = _( "gaussian blur" );
127 	object_class->build = vips_gaussblur_build;
128 
129 	operation_class->flags = VIPS_OPERATION_SEQUENTIAL;
130 
131 	VIPS_ARG_IMAGE( class, "in", 1,
132 		_( "Input" ),
133 		_( "Input image" ),
134 		VIPS_ARGUMENT_REQUIRED_INPUT,
135 		G_STRUCT_OFFSET( VipsGaussblur, in ) );
136 
137 	VIPS_ARG_IMAGE( class, "out", 2,
138 		_( "Output" ),
139 		_( "Output image" ),
140 		VIPS_ARGUMENT_REQUIRED_OUTPUT,
141 		G_STRUCT_OFFSET( VipsGaussblur, out ) );
142 
143 	VIPS_ARG_DOUBLE( class, "sigma", 3,
144 		_( "Sigma" ),
145 		_( "Sigma of Gaussian" ),
146 		VIPS_ARGUMENT_REQUIRED_INPUT,
147 		G_STRUCT_OFFSET( VipsGaussblur, sigma ),
148 		0.0, 1000, 1.5 );
149 
150 	VIPS_ARG_DOUBLE( class, "min_ampl", 3,
151 		_( "Minimum amplitude" ),
152 		_( "Minimum amplitude of Gaussian" ),
153 		VIPS_ARGUMENT_OPTIONAL_INPUT,
154 		G_STRUCT_OFFSET( VipsGaussblur, min_ampl ),
155 		0.001, 1.0, 0.2 );
156 
157 	VIPS_ARG_ENUM( class, "precision", 4,
158 		_( "Precision" ),
159 		_( "Convolve with this precision" ),
160 		VIPS_ARGUMENT_OPTIONAL_INPUT,
161 		G_STRUCT_OFFSET( VipsGaussblur, precision ),
162 		VIPS_TYPE_PRECISION, VIPS_PRECISION_INTEGER );
163 
164 }
165 
166 static void
vips_gaussblur_init(VipsGaussblur * gaussblur)167 vips_gaussblur_init( VipsGaussblur *gaussblur )
168 {
169 	gaussblur->sigma = 1.5;
170 	gaussblur->min_ampl = 0.2;
171 	gaussblur->precision = VIPS_PRECISION_INTEGER;
172 }
173 
174 /**
175  * vips_gaussblur: (method)
176  * @in: input image
177  * @out: (out): output image
178  * @sigma: how large a mask to use
179  * @...: %NULL-terminated list of optional named arguments
180  *
181  * Optional arguments:
182  *
183  * * @precision: #VipsPrecision, precision for blur, default int
184  * * @min_ampl: minimum amplitude, default 0.2
185  *
186  * This operator runs vips_gaussmat() and vips_convsep() for you on an image.
187  * Set @min_ampl smaller to generate a larger, more accurate mask. Set @sigma
188  * larger to make the blur more blurry.
189  *
190  * See also: vips_gaussmat(), vips_convsep().
191  *
192  * Returns: 0 on success, -1 on error.
193  */
194 int
vips_gaussblur(VipsImage * in,VipsImage ** out,double sigma,...)195 vips_gaussblur( VipsImage *in, VipsImage **out, double sigma, ... )
196 {
197 	va_list ap;
198 	int result;
199 
200 	va_start( ap, sigma );
201 	result = vips_call_split( "gaussblur", ap, in, out, sigma );
202 	va_end( ap );
203 
204 	return( result );
205 }
206