1 /* creates an butterworth_band filter.
2 *
3 * 02/01/14
4 * - from butterworth_band.c
5 */
6
7 /*
8
9 This file is part of VIPS.
10
11 VIPS is free software; you can redistribute it and/or modify
12 it under the terms of the GNU Lesser General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU Lesser General Public License for more details.
20
21 You should have received a copy of the GNU Lesser General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 02110-1301 USA
25
26 */
27
28 /*
29
30 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
31
32 */
33
34 /*
35 #define VIPS_DEBUG
36 */
37
38 #ifdef HAVE_CONFIG_H
39 #include <config.h>
40 #endif /*HAVE_CONFIG_H*/
41 #include <vips/intl.h>
42
43 #include <stdio.h>
44 #include <string.h>
45 #include <stdlib.h>
46 #include <math.h>
47
48 #include <vips/vips.h>
49
50 #include "pcreate.h"
51 #include "point.h"
52 #include "pmask.h"
53
54 typedef struct _VipsMaskButterworthBand {
55 VipsMask parent_instance;
56
57 double order;
58 double frequency_cutoff_x;
59 double frequency_cutoff_y;
60 double radius;
61 double amplitude_cutoff;
62
63 } VipsMaskButterworthBand;
64
65 typedef VipsMaskClass VipsMaskButterworthBandClass;
66
67 G_DEFINE_TYPE( VipsMaskButterworthBand, vips_mask_butterworth_band,
68 VIPS_TYPE_MASK );
69
70 static double
vips_mask_butterworth_band_point(VipsMask * mask,double dx,double dy)71 vips_mask_butterworth_band_point( VipsMask *mask,
72 double dx, double dy )
73 {
74 VipsMaskButterworthBand *butterworth_band =
75 (VipsMaskButterworthBand *) mask;
76 double order = butterworth_band->order;
77 double fcx = butterworth_band->frequency_cutoff_x;
78 double fcy = butterworth_band->frequency_cutoff_y;
79 double r2 = butterworth_band->radius * butterworth_band->radius;
80 double ac = butterworth_band->amplitude_cutoff;
81
82 double cnst = (1.0 / ac) - 1.0;
83
84 /* Normalise the amplitude at (fcx, fcy) to 1.0.
85 */
86 double cnsta = 1.0 / (1.0 + 1.0 / (1.0 +
87 cnst * pow( 4.0 * (fcx * fcx + fcy * fcy) / r2, order )));
88
89 double d1 = (dx - fcx) * (dx - fcx) + (dy - fcy) * (dy - fcy);
90 double d2 = (dx + fcx) * (dx + fcx) + (dy + fcy) * (dy + fcy);
91
92 return( cnsta * (1.0 / (1.0 + cnst * pow( d1 / r2, order )) +
93 1.0 / (1.0 + cnst * pow( d2 / r2, order ))) );
94 }
95
96 static void
vips_mask_butterworth_band_class_init(VipsMaskButterworthBandClass * class)97 vips_mask_butterworth_band_class_init(
98 VipsMaskButterworthBandClass *class )
99 {
100 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
101 VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
102 VipsMaskClass *mask_class = VIPS_MASK_CLASS( class );
103
104 gobject_class->set_property = vips_object_set_property;
105 gobject_class->get_property = vips_object_get_property;
106
107 vobject_class->nickname = "mask_butterworth_band";
108 vobject_class->description = _( "make a butterworth_band filter" );
109
110 mask_class->point = vips_mask_butterworth_band_point;
111
112 VIPS_ARG_DOUBLE( class, "order", 6,
113 _( "Order" ),
114 _( "Filter order" ),
115 VIPS_ARGUMENT_REQUIRED_INPUT,
116 G_STRUCT_OFFSET( VipsMaskButterworthBand, order ),
117 1.0, 1000000.0, 1.0 );
118
119 VIPS_ARG_DOUBLE( class, "frequency_cutoff_x", 7,
120 _( "Frequency cutoff x" ),
121 _( "Frequency cutoff x" ),
122 VIPS_ARGUMENT_REQUIRED_INPUT,
123 G_STRUCT_OFFSET( VipsMaskButterworthBand, frequency_cutoff_x ),
124 0.0, 1000000.0, 0.5 );
125
126 VIPS_ARG_DOUBLE( class, "frequency_cutoff_y", 8,
127 _( "Frequency cutoff y" ),
128 _( "Frequency cutoff y" ),
129 VIPS_ARGUMENT_REQUIRED_INPUT,
130 G_STRUCT_OFFSET( VipsMaskButterworthBand, frequency_cutoff_y ),
131 0.0, 1000000.0, 0.5 );
132
133 VIPS_ARG_DOUBLE( class, "radius", 9,
134 _( "radius" ),
135 _( "radius of circle" ),
136 VIPS_ARGUMENT_REQUIRED_INPUT,
137 G_STRUCT_OFFSET( VipsMaskButterworthBand, radius ),
138 0.0, 1000000.0, 0.1 );
139
140 VIPS_ARG_DOUBLE( class, "amplitude_cutoff", 10,
141 _( "Amplitude cutoff" ),
142 _( "Amplitude cutoff" ),
143 VIPS_ARGUMENT_REQUIRED_INPUT,
144 G_STRUCT_OFFSET( VipsMaskButterworthBand, amplitude_cutoff ),
145 0.0, 1.0, 0.5 );
146
147 }
148
149 static void
vips_mask_butterworth_band_init(VipsMaskButterworthBand * butterworth_band)150 vips_mask_butterworth_band_init(
151 VipsMaskButterworthBand *butterworth_band )
152 {
153 butterworth_band->order = 1.0;
154 butterworth_band->frequency_cutoff_x = 0.5;
155 butterworth_band->frequency_cutoff_y = 0.5;
156 butterworth_band->radius = 0.1;
157 butterworth_band->amplitude_cutoff = 0.5;
158 }
159
160 /**
161 * vips_mask_butterworth_band:
162 * @out: (out): output image
163 * @width: image size
164 * @height: image size
165 * @order: filter order
166 * @frequency_cutoff_x: band position
167 * @frequency_cutoff_y: band position
168 * @radius: band radius
169 * @amplitude_cutoff: amplitude threshold
170 * @...: %NULL-terminated list of optional named arguments
171 *
172 * Optional arguments:
173 *
174 * * @nodc: don't set the DC pixel
175 * * @reject: invert the filter sense
176 * * @optical: coordinates in optical space
177 * * @uchar: output a uchar image
178 *
179 * Make an butterworth band-pass or band-reject filter, that is, one with a
180 * variable, smooth transition positioned at @frequency_cutoff_x,
181 * @frequency_cutoff_y, of radius @radius.
182 * The shape of the curve is controlled by
183 * @order --- higher values give a sharper transition. See Gonzalez and Wintz,
184 * Digital Image Processing, 1987.
185 *
186 * See also: vips_mask_ideal().
187 *
188 * Returns: 0 on success, -1 on error
189 */
190 int
vips_mask_butterworth_band(VipsImage ** out,int width,int height,double order,double frequency_cutoff_x,double frequency_cutoff_y,double radius,double amplitude_cutoff,...)191 vips_mask_butterworth_band( VipsImage **out, int width, int height,
192 double order, double frequency_cutoff_x, double frequency_cutoff_y,
193 double radius, double amplitude_cutoff, ... )
194 {
195 va_list ap;
196 int result;
197
198 va_start( ap, amplitude_cutoff );
199 result = vips_call_split( "mask_butterworth_band", ap,
200 out, width, height,
201 order, frequency_cutoff_x, frequency_cutoff_y, radius,
202 amplitude_cutoff );
203 va_end( ap );
204
205 return( result );
206 }
207