Coverage Report

Created: 2025-01-28 06:32

/src/libvips/libvips/conversion/bandmean.c
Line
Count
Source (jump to first uncovered line)
1
/* average image bands
2
 *
3
 * Author: Simon Goodall
4
 * Written on: 17/7/07
5
 * 17/7/07 JC
6
 *  - hacked about a bit
7
 * 18/8/09
8
 *  - gtkdoc
9
 *  - get rid of the complex case, just double the width
10
 * 19/11/11
11
 *  - redo as a class
12
 */
13
14
/*
15
16
  Copyright (C) 1991-2005 The National Gallery
17
18
  This library is free software; you can redistribute it and/or
19
  modify it under the terms of the GNU Lesser General Public
20
  License as published by the Free Software Foundation; either
21
  version 2.1 of the License, or (at your option) any later version.
22
23
  This library is distributed in the hope that it will be useful,
24
  but WITHOUT ANY WARRANTY; without even the implied warranty of
25
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
26
  Lesser General Public License for more details.
27
28
  You should have received a copy of the GNU Lesser General Public
29
  License along with this library; if not, write to the Free Software
30
  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
31
  02110-1301  USA
32
33
 */
34
35
/*
36
37
  These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
38
39
 */
40
41
/*
42
#define DEBUG
43
 */
44
45
#ifdef HAVE_CONFIG_H
46
#include <config.h>
47
#endif /*HAVE_CONFIG_H*/
48
#include <glib/gi18n-lib.h>
49
50
#include <stdio.h>
51
#include <stdlib.h>
52
#include <math.h>
53
54
#include <vips/vips.h>
55
56
#include "bandary.h"
57
58
typedef struct _VipsBandmean {
59
  VipsBandary parent_instance;
60
61
  VipsImage *in;
62
63
} VipsBandmean;
64
65
typedef VipsBandaryClass VipsBandmeanClass;
66
67
G_DEFINE_TYPE(VipsBandmean, vips_bandmean, VIPS_TYPE_BANDARY);
68
69
/* Unsigned int types. Round, keep sum in a larger variable.
70
 */
71
#define UILOOP(TYPE, STYPE) \
72
0
  { \
73
0
    TYPE *p = (TYPE *) in[0]; \
74
0
    TYPE *q = (TYPE *) out; \
75
0
\
76
0
    for (i = 0; i < sz; i++) { \
77
0
      STYPE sum; \
78
0
\
79
0
      sum = 0; \
80
0
      for (j = 0; j < bands; j++) \
81
0
        sum += p[j]; \
82
0
      q[i] = (sum + bands / 2) / bands; \
83
0
      p += bands; \
84
0
    } \
85
0
  }
86
87
/* Signed int types. Round, keep sum in a larger variable.
88
 */
89
#define SILOOP(TYPE, STYPE) \
90
0
  { \
91
0
    TYPE *p = (TYPE *) in[0]; \
92
0
    TYPE *q = (TYPE *) out; \
93
0
\
94
0
    for (i = 0; i < sz; i++) { \
95
0
      STYPE sum; \
96
0
\
97
0
      sum = 0; \
98
0
      for (j = 0; j < bands; j++) \
99
0
        sum += p[j]; \
100
0
      q[i] = sum > 0 \
101
0
        ? (sum + bands / 2) / bands \
102
0
        : (sum - bands / 2) / bands; \
103
0
      p += bands; \
104
0
    } \
105
0
  }
106
107
/* Float loop. No rounding, sum in same container.
108
 */
109
#define FLOOP(TYPE) \
110
0
  { \
111
0
    TYPE *p = (TYPE *) in[0]; \
112
0
    TYPE *q = (TYPE *) out; \
113
0
\
114
0
    for (i = 0; i < sz; i++) { \
115
0
      TYPE sum; \
116
0
\
117
0
      sum = 0; \
118
0
      for (j = 0; j < bands; j++) \
119
0
        sum += p[j]; \
120
0
      q[i] = sum / bands; \
121
0
      p += bands; \
122
0
    } \
123
0
  }
124
125
static void
126
vips_bandmean_buffer(VipsBandarySequence *seq,
127
  VipsPel *out, VipsPel **in, int width)
128
0
{
129
0
  VipsBandary *bandary = seq->bandary;
130
0
  VipsImage *im = bandary->ready[0];
131
0
  const int bands = im->Bands;
132
0
  const int sz = width *
133
0
    (vips_band_format_iscomplex(im->BandFmt) ? 2 : 1);
134
135
0
  int i, j;
136
137
0
  switch (vips_image_get_format(im)) {
138
0
  case VIPS_FORMAT_CHAR:
139
0
    SILOOP(signed char, int);
140
0
    break;
141
0
  case VIPS_FORMAT_UCHAR:
142
0
    UILOOP(unsigned char, unsigned int);
143
0
    break;
144
0
  case VIPS_FORMAT_SHORT:
145
0
    SILOOP(signed short, int);
146
0
    break;
147
0
  case VIPS_FORMAT_USHORT:
148
0
    UILOOP(unsigned short, unsigned int);
149
0
    break;
150
0
  case VIPS_FORMAT_INT:
151
0
    SILOOP(signed int, int);
152
0
    break;
153
0
  case VIPS_FORMAT_UINT:
154
0
    UILOOP(unsigned int, unsigned int);
155
0
    break;
156
0
  case VIPS_FORMAT_FLOAT:
157
0
    FLOOP(float);
158
0
    break;
159
0
  case VIPS_FORMAT_DOUBLE:
160
0
    FLOOP(double);
161
0
    break;
162
0
  case VIPS_FORMAT_COMPLEX:
163
0
    FLOOP(float);
164
0
    break;
165
0
  case VIPS_FORMAT_DPCOMPLEX:
166
0
    FLOOP(double);
167
0
    break;
168
169
0
  default:
170
0
    g_assert_not_reached();
171
0
  }
172
0
}
173
174
static int
175
vips_bandmean_build(VipsObject *object)
176
0
{
177
0
  VipsBandary *bandary = (VipsBandary *) object;
178
0
  VipsBandmean *bandmean = (VipsBandmean *) object;
179
180
0
  bandary->n = 1;
181
0
  bandary->in = &bandmean->in;
182
183
0
  if (bandmean->in &&
184
0
    bandmean->in->Bands == 1)
185
0
    return vips_bandary_copy(bandary);
186
187
0
  bandary->out_bands = 1;
188
189
0
  if (VIPS_OBJECT_CLASS(vips_bandmean_parent_class)->build(object))
190
0
    return -1;
191
192
0
  return 0;
193
0
}
194
195
static void
196
vips_bandmean_class_init(VipsBandmeanClass *class)
197
1
{
198
1
  GObjectClass *gobject_class = G_OBJECT_CLASS(class);
199
1
  VipsObjectClass *object_class = (VipsObjectClass *) class;
200
1
  VipsBandaryClass *bandary_class = VIPS_BANDARY_CLASS(class);
201
202
1
  gobject_class->set_property = vips_object_set_property;
203
1
  gobject_class->get_property = vips_object_get_property;
204
205
1
  object_class->nickname = "bandmean";
206
1
  object_class->description = _("band-wise average");
207
1
  object_class->build = vips_bandmean_build;
208
209
1
  bandary_class->process_line = vips_bandmean_buffer;
210
211
1
  VIPS_ARG_IMAGE(class, "in", 0,
212
1
    _("Input"),
213
1
    _("Input image argument"),
214
1
    VIPS_ARGUMENT_REQUIRED_INPUT,
215
1
    G_STRUCT_OFFSET(VipsBandmean, in));
216
1
}
217
218
static void
219
vips_bandmean_init(VipsBandmean *bandmean)
220
0
{
221
0
}
222
223
/**
224
 * vips_bandmean: (method)
225
 * @in: input image
226
 * @out: (out): output image
227
 * @...: %NULL-terminated list of optional named arguments
228
 *
229
 * This operation writes a one-band image where each pixel is the average of
230
 * the bands for that pixel in the input image. The output band format is
231
 * the same as the input band format. Integer types use round-to-nearest
232
 * averaging.
233
 *
234
 * See also: vips_add(), vips_avg(), vips_recomb()
235
 *
236
 * Returns: 0 on success, -1 on error
237
 */
238
int
239
vips_bandmean(VipsImage *in, VipsImage **out, ...)
240
0
{
241
0
  va_list ap;
242
0
  int result;
243
244
0
  va_start(ap, out);
245
0
  result = vips_call_split("bandmean", ap, in, out);
246
0
  va_end(ap);
247
248
0
  return result;
249
0
}