/src/libvips/libvips/conversion/scale.c
Line | Count | Source |
1 | | /* im_scale |
2 | | * |
3 | | * Author: John Cupitt |
4 | | * Written on: 22/4/93 |
5 | | * Modified on: |
6 | | * 30/6/93 JC |
7 | | * - adapted for partial v2 |
8 | | * - ANSI |
9 | | * 31/8/93 JC |
10 | | * - calculation of offset now includes scale |
11 | | * 8/5/06 |
12 | | * - set Type on output too |
13 | | * 16/10/06 |
14 | | * - what? no, don't set Type, useful to be able to scale histograms, for |
15 | | * example |
16 | | * 1/2/10 |
17 | | * - gtkdoc |
18 | | * 30/5/13 |
19 | | * - redo as a class |
20 | | * - add log scale and exponent as an option |
21 | | * 14/1/14 |
22 | | * - use linear uchar mode |
23 | | * 14/7/14 |
24 | | * - round to nearest on uchar output |
25 | | * 29/12/18 kleisauke |
26 | | * - ... and round to nearest in log mode too |
27 | | */ |
28 | | |
29 | | /* |
30 | | |
31 | | This file is part of VIPS. |
32 | | |
33 | | VIPS is free software; you can redistribute it and/or modify |
34 | | it under the terms of the GNU Lesser General Public License as published by |
35 | | the Free Software Foundation; either version 2 of the License, or |
36 | | (at your option) any later version. |
37 | | |
38 | | This program is distributed in the hope that it will be useful, |
39 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
40 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
41 | | GNU Lesser General Public License for more details. |
42 | | |
43 | | You should have received a copy of the GNU Lesser General Public License |
44 | | along with this program; if not, write to the Free Software |
45 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
46 | | 02110-1301 USA |
47 | | |
48 | | */ |
49 | | |
50 | | /* |
51 | | |
52 | | These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk |
53 | | |
54 | | */ |
55 | | |
56 | | #ifdef HAVE_CONFIG_H |
57 | | #include <config.h> |
58 | | #endif /*HAVE_CONFIG_H*/ |
59 | | #include <glib/gi18n-lib.h> |
60 | | |
61 | | #include <stdio.h> |
62 | | #include <stdlib.h> |
63 | | #include <math.h> |
64 | | |
65 | | #include <vips/vips.h> |
66 | | |
67 | | #include "pconversion.h" |
68 | | |
69 | | typedef struct _VipsScale { |
70 | | VipsConversion parent_instance; |
71 | | |
72 | | VipsImage *in; |
73 | | |
74 | | gboolean log; |
75 | | double exp; |
76 | | |
77 | | } VipsScale; |
78 | | |
79 | | typedef VipsConversionClass VipsScaleClass; |
80 | | |
81 | 40 | G_DEFINE_TYPE(VipsScale, vips_scale, VIPS_TYPE_CONVERSION); |
82 | 40 | |
83 | 40 | static int |
84 | 40 | vips_scale_build(VipsObject *object) |
85 | 790 | { |
86 | 790 | VipsConversion *conversion = VIPS_CONVERSION(object); |
87 | 790 | VipsScale *scale = (VipsScale *) object; |
88 | 790 | VipsImage **t = (VipsImage **) vips_object_local_array(object, 7); |
89 | | |
90 | 790 | double mx; |
91 | 790 | double mn; |
92 | | |
93 | 790 | if (VIPS_OBJECT_CLASS(vips_scale_parent_class)->build(object)) |
94 | 0 | return -1; |
95 | | |
96 | 790 | if (vips_stats(scale->in, &t[0], NULL)) |
97 | 354 | return -1; |
98 | 436 | mn = *VIPS_MATRIX(t[0], 0, 0); |
99 | 436 | mx = *VIPS_MATRIX(t[0], 1, 0); |
100 | | |
101 | 436 | if (mn == mx) { |
102 | | /* Range of zero: just return black. |
103 | | */ |
104 | 201 | if (vips_black(&t[1], scale->in->Xsize, scale->in->Ysize, |
105 | 201 | "bands", scale->in->Bands, |
106 | 201 | NULL) || |
107 | 201 | vips_image_write(t[1], conversion->out)) |
108 | 0 | return -1; |
109 | 201 | } |
110 | 235 | else if (scale->log) { |
111 | 39 | double f = 255.0 / log10(1.0 + pow(mx, scale->exp)); |
112 | | |
113 | 39 | if (vips_pow_const1(scale->in, &t[2], scale->exp, NULL) || |
114 | 39 | vips_linear1(t[2], &t[3], 1.0, 1.0, NULL) || |
115 | 39 | vips_log10(t[3], &t[4], NULL) || |
116 | | /* Add 0.5 to get round to nearest. |
117 | | */ |
118 | 39 | vips_linear1(t[4], &t[5], f, 0.5, |
119 | 39 | "uchar", TRUE, |
120 | 39 | NULL) || |
121 | 39 | vips_image_write(t[5], conversion->out)) |
122 | 0 | return -1; |
123 | 39 | } |
124 | 196 | else { |
125 | 196 | double f = 255.0 / (mx - mn); |
126 | | |
127 | | /* Add .5 to get round-to-nearest. |
128 | | */ |
129 | 196 | double a = -(mn * f) + 0.5; |
130 | | |
131 | 196 | if (vips_linear1(scale->in, &t[2], f, a, |
132 | 196 | "uchar", TRUE, |
133 | 196 | NULL) || |
134 | 196 | vips_image_write(t[2], conversion->out)) |
135 | 0 | return -1; |
136 | 196 | } |
137 | | |
138 | 436 | return 0; |
139 | 436 | } |
140 | | |
141 | | static void |
142 | | vips_scale_class_init(VipsScaleClass *class) |
143 | 20 | { |
144 | 20 | GObjectClass *gobject_class = G_OBJECT_CLASS(class); |
145 | 20 | VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS(class); |
146 | | |
147 | 20 | gobject_class->set_property = vips_object_set_property; |
148 | 20 | gobject_class->get_property = vips_object_get_property; |
149 | | |
150 | 20 | vobject_class->nickname = "scale"; |
151 | 20 | vobject_class->description = _("scale an image to uchar"); |
152 | 20 | vobject_class->build = vips_scale_build; |
153 | | |
154 | 20 | VIPS_ARG_IMAGE(class, "in", 1, |
155 | 20 | _("Input"), |
156 | 20 | _("Input image"), |
157 | 20 | VIPS_ARGUMENT_REQUIRED_INPUT, |
158 | 20 | G_STRUCT_OFFSET(VipsScale, in)); |
159 | | |
160 | 20 | VIPS_ARG_BOOL(class, "log", 3, |
161 | 20 | _("Log"), |
162 | 20 | _("Log scale"), |
163 | 20 | VIPS_ARGUMENT_OPTIONAL_INPUT, |
164 | 20 | G_STRUCT_OFFSET(VipsScale, log), |
165 | 20 | FALSE); |
166 | | |
167 | 20 | VIPS_ARG_DOUBLE(class, "exp", 3, |
168 | 20 | _("Exponent"), |
169 | 20 | _("Exponent for log scale"), |
170 | 20 | VIPS_ARGUMENT_OPTIONAL_INPUT, |
171 | 20 | G_STRUCT_OFFSET(VipsScale, exp), |
172 | 20 | 0.00001, 10000, 0.25); |
173 | 20 | } |
174 | | |
175 | | static void |
176 | | vips_scale_init(VipsScale *scale) |
177 | 793 | { |
178 | 793 | scale->exp = 0.25; |
179 | 793 | } |
180 | | |
181 | | /** |
182 | | * vips_scale: (method) |
183 | | * @in: input image |
184 | | * @out: (out): output image |
185 | | * @...: `NULL`-terminated list of optional named arguments |
186 | | * |
187 | | * Search the image for the maximum and minimum value, then return the image |
188 | | * as unsigned 8-bit, scaled so that the maximum value is 255 and the |
189 | | * minimum is zero. |
190 | | * |
191 | | * If @log is set, transform with log10(1.0 + pow(x, @exp)) + .5, |
192 | | * then scale so max == 255. By default, @exp is 0.25. |
193 | | * |
194 | | * ::: tip "Optional arguments" |
195 | | * * @log: `gboolean`, log scale pixels |
196 | | * * @exp: `gdouble`, exponent for log scale |
197 | | * |
198 | | * ::: seealso |
199 | | * [method@Image.cast]. |
200 | | * |
201 | | * Returns: 0 on success, -1 on error |
202 | | */ |
203 | | int |
204 | | vips_scale(VipsImage *in, VipsImage **out, ...) |
205 | 764 | { |
206 | 764 | va_list ap; |
207 | 764 | int result; |
208 | | |
209 | 764 | va_start(ap, out); |
210 | 764 | result = vips_call_split("scale", ap, in, out); |
211 | 764 | va_end(ap); |
212 | | |
213 | 764 | return result; |
214 | 764 | } |