1 /* convolution
2 *
3 * 12/8/13
4 * - from vips_hist_cum()
5 * 8/5/17
6 * - default to float ... int will often lose precision and should not be
7 * the default
8 */
9
10 /*
11
12 This file is part of VIPS.
13
14 VIPS is free software; you can redistribute it and/or modify
15 it under the terms of the GNU Lesser General Public License as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU Lesser General Public License for more details.
23
24 You should have received a copy of the GNU Lesser General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 02110-1301 USA
28
29 */
30
31 /*
32
33 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
34
35 */
36
37 #ifdef HAVE_CONFIG_H
38 #include <config.h>
39 #endif /*HAVE_CONFIG_H*/
40 #include <vips/intl.h>
41
42 #include <stdio.h>
43
44 #include <vips/vips.h>
45 #include <vips/internal.h>
46
47 #include "pconvolution.h"
48
49 typedef struct {
50 VipsConvolution parent_instance;
51
52 VipsPrecision precision;
53 int layers;
54 int cluster;
55 } VipsConv;
56
57 typedef VipsConvolutionClass VipsConvClass;
58
59 G_DEFINE_TYPE( VipsConv, vips_conv, VIPS_TYPE_CONVOLUTION );
60
61 static int
vips_conv_build(VipsObject * object)62 vips_conv_build( VipsObject *object )
63 {
64 VipsConvolution *convolution = (VipsConvolution *) object;
65 VipsConv *conv = (VipsConv *) object;
66 VipsImage **t = (VipsImage **) vips_object_local_array( object, 4 );
67
68 VipsImage *in;
69
70 if( VIPS_OBJECT_CLASS( vips_conv_parent_class )->build( object ) )
71 return( -1 );
72
73 g_object_set( conv, "out", vips_image_new(), NULL );
74
75 in = convolution->in;
76
77 /*
78 printf( "vips_conv_build: convolving with:\n" );
79 vips_matrixprint( convolution->M, NULL );
80 */
81
82 /* Unpack for processing.
83 */
84 if( vips_image_decode( in, &t[0] ) )
85 return( -1 );
86 in = t[0];
87
88 switch( conv->precision ) {
89 case VIPS_PRECISION_FLOAT:
90 if( vips_convf( in, &t[1], convolution->M, NULL ) ||
91 vips_image_write( t[1], convolution->out ) )
92 return( -1 );
93 break;
94
95 case VIPS_PRECISION_INTEGER:
96 if( vips_convi( in, &t[1], convolution->M, NULL ) ||
97 vips_image_write( t[1], convolution->out ) )
98 return( -1 );
99 break;
100
101 case VIPS_PRECISION_APPROXIMATE:
102 if( vips_conva( in, &t[1], convolution->M,
103 "layers", conv->layers,
104 "cluster", conv->cluster,
105 NULL ) ||
106 vips_image_write( t[1], convolution->out ) )
107 return( -1 );
108 break;
109
110 default:
111 g_assert_not_reached();
112 }
113
114 vips_reorder_margin_hint( convolution->out,
115 convolution->M->Xsize * convolution->M->Ysize );
116
117 return( 0 );
118 }
119
120 static void
vips_conv_class_init(VipsConvClass * class)121 vips_conv_class_init( VipsConvClass *class )
122 {
123 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
124 VipsObjectClass *object_class = (VipsObjectClass *) class;
125
126 gobject_class->set_property = vips_object_set_property;
127 gobject_class->get_property = vips_object_get_property;
128
129 object_class->nickname = "conv";
130 object_class->description = _( "convolution operation" );
131 object_class->build = vips_conv_build;
132
133 VIPS_ARG_ENUM( class, "precision", 103,
134 _( "Precision" ),
135 _( "Convolve with this precision" ),
136 VIPS_ARGUMENT_OPTIONAL_INPUT,
137 G_STRUCT_OFFSET( VipsConv, precision ),
138 VIPS_TYPE_PRECISION, VIPS_PRECISION_FLOAT );
139
140 VIPS_ARG_INT( class, "layers", 104,
141 _( "Layers" ),
142 _( "Use this many layers in approximation" ),
143 VIPS_ARGUMENT_OPTIONAL_INPUT,
144 G_STRUCT_OFFSET( VipsConv, layers ),
145 1, 1000, 5 );
146
147 VIPS_ARG_INT( class, "cluster", 105,
148 _( "Cluster" ),
149 _( "Cluster lines closer than this in approximation" ),
150 VIPS_ARGUMENT_OPTIONAL_INPUT,
151 G_STRUCT_OFFSET( VipsConv, cluster ),
152 1, 100, 1 );
153
154 }
155
156 static void
vips_conv_init(VipsConv * conv)157 vips_conv_init( VipsConv *conv )
158 {
159 conv->precision = VIPS_PRECISION_FLOAT;
160 conv->layers = 5;
161 conv->cluster = 1;
162 }
163
164 /**
165 * vips_conv: (method)
166 * @in: input image
167 * @out: (out): output image
168 * @mask: convolve with this mask
169 * @...: %NULL-terminated list of optional named arguments
170 *
171 * Optional arguments:
172 *
173 * * @precision: #VipsPrecision, calculation accuracy
174 * * @layers: %gint, number of layers for approximation
175 * * @cluster: %gint, cluster lines closer than this distance
176 *
177 * Convolution.
178 *
179 * Perform a convolution of @in with @mask.
180 * Each output pixel is calculated as:
181 *
182 * |[
183 * sigma[i]{pixel[i] * mask[i]} / scale + offset
184 * ]|
185 *
186 * where scale and offset are part of @mask.
187 *
188 * By default, @precision is
189 * #VIPS_PRECISION_FLOAT. The output image
190 * is always #VIPS_FORMAT_FLOAT unless @in is #VIPS_FORMAT_DOUBLE, in which case
191 * @out is also #VIPS_FORMAT_DOUBLE.
192 *
193 * If @precision is #VIPS_PRECISION_INTEGER, then
194 * elements of @mask are converted to
195 * integers before convolution, using rint(),
196 * and the output image
197 * always has the same #VipsBandFormat as the input image.
198 *
199 * For #VIPS_FORMAT_UCHAR images and #VIPS_PRECISION_INTEGER @precision,
200 * vips_conv() uses a fast vector path based on
201 * fixed-point arithmetic. This can produce slightly different results.
202 * Disable the vector path with `--vips-novector` or `VIPS_NOVECTOR` or
203 * vips_vector_set_enabled().
204 *
205 * If @precision is #VIPS_PRECISION_APPROXIMATE then, like
206 * #VIPS_PRECISION_INTEGER, @mask is converted to int before convolution, and
207 * the output image
208 * always has the same #VipsBandFormat as the input image.
209 *
210 * Larger values for @layers give more accurate
211 * results, but are slower. As @layers approaches the mask radius, the
212 * accuracy will become close to exact convolution and the speed will drop to
213 * match. For many large masks, such as Gaussian, @n_layers need be only 10% of
214 * this value and accuracy will still be good.
215 *
216 * Smaller values of @cluster will give more accurate results, but be slower
217 * and use more memory. 10% of the mask radius is a good rule of thumb.
218 *
219 * See also: vips_convsep().
220 *
221 * Returns: 0 on success, -1 on error
222 */
223 int
vips_conv(VipsImage * in,VipsImage ** out,VipsImage * mask,...)224 vips_conv( VipsImage *in, VipsImage **out, VipsImage *mask, ... )
225 {
226 va_list ap;
227 int result;
228
229 va_start( ap, mask );
230 result = vips_call_split( "conv", ap, in, out, mask );
231 va_end( ap );
232
233 return( result );
234 }
235