/src/libvips/libvips/arithmetic/relational.c
Line | Count | Source |
1 | | /* relational.c -- various relational operations |
2 | | * |
3 | | * Modified: |
4 | | * 26/7/93 JC |
5 | | * - >,<,>=,<= tests now as (double) to prevent compiler warnings. Should |
6 | | * split into int/float cases really for speed. |
7 | | * 25/1/95 JC |
8 | | * - partialized |
9 | | * - updated |
10 | | * 7/2/95 JC |
11 | | * - oops! bug with doubles fixed |
12 | | * 3/7/98 JC |
13 | | * - vector versions added ... im_equal_vec(), im_lesseq_vec() etc |
14 | | * - small tidies |
15 | | * - should be a bit faster, lots of *q++ changed to q[x] |
16 | | * 10/3/03 JC |
17 | | * - reworked to remove nested #defines: a bit slower, but much smaller |
18 | | * - all except _vec forms now work on complex |
19 | | * 31/7/03 JC |
20 | | * - oops, relational_format was broken for some combinations |
21 | | * 23/9/09 |
22 | | * - gtkdoc |
23 | | * - use new im__arith_binary*() functions |
24 | | * - more meta-programming |
25 | | * 23/6/10 |
26 | | * - oops, moreconst and moreeqconst were the same |
27 | | * 4/11/11 |
28 | | * - redone as a class |
29 | | * 1/2/12 |
30 | | * - complex ==, != were broken |
31 | | * 16/7/12 |
32 | | * - im1 > im2, im1 >= im2 were broken |
33 | | * 17/9/14 |
34 | | * - im1 > im2, im1 >= im2 were still broken, but in a more subtle way |
35 | | */ |
36 | | |
37 | | /* |
38 | | |
39 | | Copyright (C) 1991-2005 The National Gallery |
40 | | |
41 | | This library is free software; you can redistribute it and/or |
42 | | modify it under the terms of the GNU Lesser General Public |
43 | | License as published by the Free Software Foundation; either |
44 | | version 2.1 of the License, or (at your option) any later version. |
45 | | |
46 | | This library is distributed in the hope that it will be useful, |
47 | | but WITHOUT ANY WARRANTY; without even the implied warranty of |
48 | | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
49 | | Lesser General Public License for more details. |
50 | | |
51 | | You should have received a copy of the GNU Lesser General Public |
52 | | License along with this library; if not, write to the Free Software |
53 | | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
54 | | 02110-1301 USA |
55 | | |
56 | | */ |
57 | | |
58 | | /* |
59 | | |
60 | | These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk |
61 | | |
62 | | */ |
63 | | |
64 | | /* |
65 | | #define DEBUG |
66 | | */ |
67 | | |
68 | | #ifdef HAVE_CONFIG_H |
69 | | #include <config.h> |
70 | | #endif /*HAVE_CONFIG_H*/ |
71 | | #include <glib/gi18n-lib.h> |
72 | | |
73 | | #include <stdio.h> |
74 | | #include <stdlib.h> |
75 | | |
76 | | #include <vips/vips.h> |
77 | | |
78 | | #include "binary.h" |
79 | | #include "unaryconst.h" |
80 | | |
81 | | typedef struct _VipsRelational { |
82 | | VipsBinary parent_instance; |
83 | | |
84 | | VipsOperationRelational relational; |
85 | | |
86 | | } VipsRelational; |
87 | | |
88 | | typedef VipsBinaryClass VipsRelationalClass; |
89 | | |
90 | 34 | G_DEFINE_TYPE(VipsRelational, vips_relational, VIPS_TYPE_BINARY); |
91 | 34 | |
92 | 34 | #define RLOOP(TYPE, ROP) \ |
93 | 34 | { \ |
94 | 0 | TYPE *restrict left = (TYPE *) in0; \ |
95 | 0 | TYPE *restrict right = (TYPE *) in1; \ |
96 | 0 | VipsPel *restrict q = (VipsPel *) out; \ |
97 | 0 | \ |
98 | 0 | for (x = 0; x < sz; x++) \ |
99 | 0 | q[x] = (left[x] ROP right[x]) ? 255 : 0; \ |
100 | 0 | } |
101 | | |
102 | | #define CLOOP(TYPE, COP) \ |
103 | 0 | { \ |
104 | 0 | TYPE *restrict left = (TYPE *) in0; \ |
105 | 0 | TYPE *restrict right = (TYPE *) in1; \ |
106 | 0 | VipsPel *restrict q = (VipsPel *) out; \ |
107 | 0 | \ |
108 | 0 | for (x = 0; x < sz; x++) { \ |
109 | 0 | q[x] = COP(left[0], left[1], right[0], right[1]) ? 255 : 0; \ |
110 | 0 | \ |
111 | 0 | left += 2; \ |
112 | 0 | right += 2; \ |
113 | 0 | } \ |
114 | 0 | } |
115 | | |
116 | | #define SWITCH(R, C, ROP, COP) \ |
117 | 187k | switch (vips_image_get_format(im)) { \ |
118 | 0 | case VIPS_FORMAT_UCHAR: \ |
119 | 0 | R(unsigned char, ROP); \ |
120 | 0 | break; \ |
121 | 0 | case VIPS_FORMAT_CHAR: \ |
122 | 0 | R(signed char, ROP); \ |
123 | 0 | break; \ |
124 | 0 | case VIPS_FORMAT_USHORT: \ |
125 | 0 | R(unsigned short, ROP); \ |
126 | 0 | break; \ |
127 | 0 | case VIPS_FORMAT_SHORT: \ |
128 | 0 | R(signed short, ROP); \ |
129 | 0 | break; \ |
130 | 0 | case VIPS_FORMAT_UINT: \ |
131 | 0 | R(unsigned int, ROP); \ |
132 | 0 | break; \ |
133 | 0 | case VIPS_FORMAT_INT: \ |
134 | 0 | R(signed int, ROP); \ |
135 | 0 | break; \ |
136 | 187k | case VIPS_FORMAT_FLOAT: \ |
137 | 187k | R(float, ROP); \ |
138 | 187k | break; \ |
139 | 0 | case VIPS_FORMAT_DOUBLE: \ |
140 | 0 | R(double, ROP); \ |
141 | 0 | break; \ |
142 | 0 | case VIPS_FORMAT_COMPLEX: \ |
143 | 0 | C(float, COP); \ |
144 | 0 | break; \ |
145 | 0 | case VIPS_FORMAT_DPCOMPLEX: \ |
146 | 0 | C(double, COP); \ |
147 | 0 | break; \ |
148 | 0 | \ |
149 | 0 | default: \ |
150 | 0 | g_assert_not_reached(); \ |
151 | 187k | } |
152 | | |
153 | 0 | #define CEQUAL(x1, y1, x2, y2) (x1 == x2 && y1 == y2) |
154 | 0 | #define CNOTEQ(x1, y1, x2, y2) (x1 != x2 || y1 != y2) |
155 | 0 | #define CLESS(x1, y1, x2, y2) (x1 * x1 + y1 * y1 < x2 * x2 + y2 * y2) |
156 | 0 | #define CLESSEQ(x1, y1, x2, y2) (x1 * x1 + y1 * y1 <= x2 * x2 + y2 * y2) |
157 | 0 | #define CMORE(x1, y1, x2, y2) (x1 * x1 + y1 * y1 > x2 * x2 + y2 * y2) |
158 | 0 | #define CMOREEQ(x1, y1, x2, y2) (x1 * x1 + y1 * y1 >= x2 * x2 + y2 * y2) |
159 | | |
160 | | static void |
161 | | vips_relational_buffer(VipsArithmetic *arithmetic, |
162 | | VipsPel *out, VipsPel **in, int width) |
163 | 0 | { |
164 | 0 | VipsRelational *relational = (VipsRelational *) arithmetic; |
165 | 0 | VipsImage *im = arithmetic->ready[0]; |
166 | 0 | const int sz = width * vips_image_get_bands(im); |
167 | |
|
168 | 0 | VipsOperationRelational op; |
169 | 0 | VipsPel *in0; |
170 | 0 | VipsPel *in1; |
171 | 0 | int x; |
172 | |
|
173 | 0 | in0 = in[0]; |
174 | 0 | in1 = in[1]; |
175 | 0 | op = relational->relational; |
176 | |
|
177 | 0 | if (op == VIPS_OPERATION_RELATIONAL_MORE) { |
178 | 0 | op = VIPS_OPERATION_RELATIONAL_LESS; |
179 | 0 | VIPS_SWAP(VipsPel *, in0, in1); |
180 | 0 | } |
181 | |
|
182 | 0 | if (op == VIPS_OPERATION_RELATIONAL_MOREEQ) { |
183 | 0 | op = VIPS_OPERATION_RELATIONAL_LESSEQ; |
184 | 0 | VIPS_SWAP(VipsPel *, in0, in1); |
185 | 0 | } |
186 | |
|
187 | 0 | switch (op) { |
188 | 0 | case VIPS_OPERATION_RELATIONAL_EQUAL: |
189 | 0 | SWITCH(RLOOP, CLOOP, ==, CEQUAL); |
190 | 0 | break; |
191 | | |
192 | 0 | case VIPS_OPERATION_RELATIONAL_NOTEQ: |
193 | 0 | SWITCH(RLOOP, CLOOP, !=, CNOTEQ); |
194 | 0 | break; |
195 | | |
196 | 0 | case VIPS_OPERATION_RELATIONAL_LESS: |
197 | 0 | SWITCH(RLOOP, CLOOP, <, CLESS); |
198 | 0 | break; |
199 | | |
200 | 0 | case VIPS_OPERATION_RELATIONAL_LESSEQ: |
201 | 0 | SWITCH(RLOOP, CLOOP, <=, CLESSEQ); |
202 | 0 | break; |
203 | | |
204 | 0 | default: |
205 | 0 | g_assert_not_reached(); |
206 | 0 | } |
207 | 0 | } |
208 | | |
209 | | /* Save a bit of typing. |
210 | | */ |
211 | | #define UC VIPS_FORMAT_UCHAR |
212 | | #define C VIPS_FORMAT_CHAR |
213 | | #define US VIPS_FORMAT_USHORT |
214 | | #define S VIPS_FORMAT_SHORT |
215 | | #define UI VIPS_FORMAT_UINT |
216 | | #define I VIPS_FORMAT_INT |
217 | | #define F VIPS_FORMAT_FLOAT |
218 | | #define X VIPS_FORMAT_COMPLEX |
219 | | #define D VIPS_FORMAT_DOUBLE |
220 | | #define DX VIPS_FORMAT_DPCOMPLEX |
221 | | |
222 | | static const VipsBandFormat vips_relational_format_table[10] = { |
223 | | /* Band format: UC C US S UI I F X D DX */ |
224 | | /* Promotion: */ UC, UC, UC, UC, UC, UC, UC, UC, UC, UC |
225 | | }; |
226 | | |
227 | | static void |
228 | | vips_relational_class_init(VipsRelationalClass *class) |
229 | 17 | { |
230 | 17 | GObjectClass *gobject_class = G_OBJECT_CLASS(class); |
231 | 17 | VipsObjectClass *object_class = (VipsObjectClass *) class; |
232 | 17 | VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); |
233 | | |
234 | 17 | gobject_class->set_property = vips_object_set_property; |
235 | 17 | gobject_class->get_property = vips_object_get_property; |
236 | | |
237 | 17 | object_class->nickname = "relational"; |
238 | 17 | object_class->description = _("relational operation on two images"); |
239 | | |
240 | 17 | aclass->process_line = vips_relational_buffer; |
241 | | |
242 | 17 | vips_arithmetic_set_format_table(aclass, |
243 | 17 | vips_relational_format_table); |
244 | | |
245 | 17 | VIPS_ARG_ENUM(class, "relational", 200, |
246 | 17 | _("Operation"), |
247 | 17 | _("Relational to perform"), |
248 | 17 | VIPS_ARGUMENT_REQUIRED_INPUT, |
249 | 17 | G_STRUCT_OFFSET(VipsRelational, relational), |
250 | 17 | VIPS_TYPE_OPERATION_RELATIONAL, |
251 | 17 | VIPS_OPERATION_RELATIONAL_EQUAL); |
252 | 17 | } |
253 | | |
254 | | static void |
255 | | vips_relational_init(VipsRelational *relational) |
256 | 0 | { |
257 | 0 | } |
258 | | |
259 | | static int |
260 | | vips_relationalv(VipsImage *left, VipsImage *right, VipsImage **out, |
261 | | VipsOperationRelational relational, va_list ap) |
262 | 0 | { |
263 | 0 | return vips_call_split("relational", ap, left, right, out, |
264 | 0 | relational); |
265 | 0 | } |
266 | | |
267 | | /** |
268 | | * vips_relational: (method) |
269 | | * @left: left-hand input [class@Image] |
270 | | * @right: right-hand input [class@Image] |
271 | | * @out: (out): output [class@Image] |
272 | | * @relational: relational operation to perform |
273 | | * @...: `NULL`-terminated list of optional named arguments |
274 | | * |
275 | | * Perform various relational operations on pairs of images. |
276 | | * |
277 | | * The output type is always uchar, with 0 for `FALSE` and 255 for `TRUE`. |
278 | | * |
279 | | * Less-than and greater-than for complex images compare the modulus. |
280 | | * |
281 | | * If the images differ in size, the smaller image is enlarged to match the |
282 | | * larger by adding zero pixels along the bottom and right. |
283 | | * |
284 | | * If the number of bands differs, one of the images |
285 | | * must have one band. In this case, an n-band image is formed from the |
286 | | * one-band image by joining n copies of the one-band image together, and then |
287 | | * the two n-band images are operated upon. |
288 | | * |
289 | | * The two input images are cast up to the smallest common format (see table |
290 | | * Smallest common format in |
291 | | * [arithmetic](libvips-arithmetic.html)). |
292 | | * |
293 | | * To decide if pixels match exactly, that is have the same value in every |
294 | | * band, use [method@Image.bandbool] after this operation to AND or OR image |
295 | | * bands together. |
296 | | * |
297 | | * ::: seealso |
298 | | * [method@Image.boolean], [method@Image.bandbool], |
299 | | * [method@Image.relational_const]. |
300 | | * |
301 | | * Returns: 0 on success, -1 on error |
302 | | */ |
303 | | int |
304 | | vips_relational(VipsImage *left, VipsImage *right, VipsImage **out, |
305 | | VipsOperationRelational relational, ...) |
306 | 0 | { |
307 | 0 | va_list ap; |
308 | 0 | int result; |
309 | |
|
310 | 0 | va_start(ap, relational); |
311 | 0 | result = vips_relationalv(left, right, out, relational, ap); |
312 | 0 | va_end(ap); |
313 | |
|
314 | 0 | return result; |
315 | 0 | } |
316 | | |
317 | | /** |
318 | | * vips_equal: (method) |
319 | | * @left: left-hand input [class@Image] |
320 | | * @right: right-hand input [class@Image] |
321 | | * @out: (out): output [class@Image] |
322 | | * @...: `NULL`-terminated list of optional named arguments |
323 | | * |
324 | | * Perform [enum@Vips.OperationRelational.EQUAL] on a pair of images. See |
325 | | * [method@Image.relational]. |
326 | | * |
327 | | * Returns: 0 on success, -1 on error |
328 | | */ |
329 | | int |
330 | | vips_equal(VipsImage *left, VipsImage *right, VipsImage **out, ...) |
331 | 0 | { |
332 | 0 | va_list ap; |
333 | 0 | int result; |
334 | |
|
335 | 0 | va_start(ap, out); |
336 | 0 | result = vips_relationalv(left, right, out, |
337 | 0 | VIPS_OPERATION_RELATIONAL_EQUAL, ap); |
338 | 0 | va_end(ap); |
339 | |
|
340 | 0 | return result; |
341 | 0 | } |
342 | | |
343 | | /** |
344 | | * vips_notequal: (method) |
345 | | * @left: left-hand input [class@Image] |
346 | | * @right: right-hand input [class@Image] |
347 | | * @out: (out): output [class@Image] |
348 | | * @...: `NULL`-terminated list of optional named arguments |
349 | | * |
350 | | * Perform [enum@Vips.OperationRelational.NOTEQ] on a pair of images. See |
351 | | * [method@Image.relational]. |
352 | | * |
353 | | * Returns: 0 on success, -1 on error |
354 | | */ |
355 | | int |
356 | | vips_notequal(VipsImage *left, VipsImage *right, VipsImage **out, ...) |
357 | 0 | { |
358 | 0 | va_list ap; |
359 | 0 | int result; |
360 | |
|
361 | 0 | va_start(ap, out); |
362 | 0 | result = vips_relationalv(left, right, out, |
363 | 0 | VIPS_OPERATION_RELATIONAL_NOTEQ, ap); |
364 | 0 | va_end(ap); |
365 | |
|
366 | 0 | return result; |
367 | 0 | } |
368 | | |
369 | | /** |
370 | | * vips_more: (method) |
371 | | * @left: left-hand input [class@Image] |
372 | | * @right: right-hand input [class@Image] |
373 | | * @out: (out): output [class@Image] |
374 | | * @...: `NULL`-terminated list of optional named arguments |
375 | | * |
376 | | * Perform [enum@Vips.OperationRelational.MORE] on a pair of images. See |
377 | | * [method@Image.relational]. |
378 | | * |
379 | | * Returns: 0 on success, -1 on error |
380 | | */ |
381 | | int |
382 | | vips_more(VipsImage *left, VipsImage *right, VipsImage **out, ...) |
383 | 0 | { |
384 | 0 | va_list ap; |
385 | 0 | int result; |
386 | |
|
387 | 0 | va_start(ap, out); |
388 | 0 | result = vips_relationalv(left, right, out, |
389 | 0 | VIPS_OPERATION_RELATIONAL_MORE, ap); |
390 | 0 | va_end(ap); |
391 | |
|
392 | 0 | return result; |
393 | 0 | } |
394 | | |
395 | | /** |
396 | | * vips_moreeq: (method) |
397 | | * @left: left-hand input [class@Image] |
398 | | * @right: right-hand input [class@Image] |
399 | | * @out: (out): output [class@Image] |
400 | | * @...: `NULL`-terminated list of optional named arguments |
401 | | * |
402 | | * Perform [enum@Vips.OperationRelational.MOREEQ] on a pair of images. See |
403 | | * [method@Image.relational]. |
404 | | * |
405 | | * Returns: 0 on success, -1 on error |
406 | | */ |
407 | | int |
408 | | vips_moreeq(VipsImage *left, VipsImage *right, VipsImage **out, ...) |
409 | 0 | { |
410 | 0 | va_list ap; |
411 | 0 | int result; |
412 | |
|
413 | 0 | va_start(ap, out); |
414 | 0 | result = vips_relationalv(left, right, out, |
415 | 0 | VIPS_OPERATION_RELATIONAL_MOREEQ, ap); |
416 | 0 | va_end(ap); |
417 | |
|
418 | 0 | return result; |
419 | 0 | } |
420 | | |
421 | | /** |
422 | | * vips_less: (method) |
423 | | * @left: left-hand input [class@Image] |
424 | | * @right: right-hand input [class@Image] |
425 | | * @out: (out): output [class@Image] |
426 | | * @...: `NULL`-terminated list of optional named arguments |
427 | | * |
428 | | * Perform [enum@Vips.OperationRelational.LESS] on a pair of images. See |
429 | | * [method@Image.relational]. |
430 | | * |
431 | | * Returns: 0 on success, -1 on error |
432 | | */ |
433 | | int |
434 | | vips_less(VipsImage *left, VipsImage *right, VipsImage **out, ...) |
435 | 0 | { |
436 | 0 | va_list ap; |
437 | 0 | int result; |
438 | |
|
439 | 0 | va_start(ap, out); |
440 | 0 | result = vips_relationalv(left, right, out, |
441 | 0 | VIPS_OPERATION_RELATIONAL_LESS, ap); |
442 | 0 | va_end(ap); |
443 | |
|
444 | 0 | return result; |
445 | 0 | } |
446 | | |
447 | | /** |
448 | | * vips_lesseq: (method) |
449 | | * @left: left-hand input [class@Image] |
450 | | * @right: right-hand input [class@Image] |
451 | | * @out: (out): output [class@Image] |
452 | | * @...: `NULL`-terminated list of optional named arguments |
453 | | * |
454 | | * Perform [enum@Vips.OperationRelational.LESSEQ] on a pair of images. See |
455 | | * [method@Image.relational]. |
456 | | * |
457 | | * Returns: 0 on success, -1 on error |
458 | | */ |
459 | | int |
460 | | vips_lesseq(VipsImage *left, VipsImage *right, VipsImage **out, ...) |
461 | 0 | { |
462 | 0 | va_list ap; |
463 | 0 | int result; |
464 | |
|
465 | 0 | va_start(ap, out); |
466 | 0 | result = vips_relationalv(left, right, out, |
467 | 0 | VIPS_OPERATION_RELATIONAL_LESSEQ, ap); |
468 | 0 | va_end(ap); |
469 | |
|
470 | 0 | return result; |
471 | 0 | } |
472 | | |
473 | | typedef struct _VipsRelationalConst { |
474 | | VipsUnaryConst parent_instance; |
475 | | |
476 | | VipsOperationRelational relational; |
477 | | } VipsRelationalConst; |
478 | | |
479 | | typedef VipsUnaryConstClass VipsRelationalConstClass; |
480 | | |
481 | 34 | G_DEFINE_TYPE(VipsRelationalConst, |
482 | 34 | vips_relational_const, VIPS_TYPE_UNARY_CONST); |
483 | 34 | |
484 | 34 | #define RLOOPCI(TYPE, OP) \ |
485 | 34 | { \ |
486 | 0 | TYPE *restrict p = (TYPE *) in[0]; \ |
487 | 0 | int *restrict c = uconst->c_int; \ |
488 | 0 | \ |
489 | 0 | for (i = 0, x = 0; x < width; x++) \ |
490 | 0 | for (b = 0; b < bands; b++, i++) \ |
491 | 0 | out[i] = (p[i] OP c[b]) ? 255 : 0; \ |
492 | 0 | } |
493 | | |
494 | | #define RLOOPCF(TYPE, OP) \ |
495 | 187k | { \ |
496 | 187k | TYPE *restrict p = (TYPE *) in[0]; \ |
497 | 187k | double *restrict c = uconst->c_double; \ |
498 | 187k | \ |
499 | 6.18M | for (i = 0, x = 0; x < width; x++) \ |
500 | 11.9M | for (b = 0; b < bands; b++, i++) \ |
501 | 5.99M | out[i] = (p[i] OP c[b]) ? 255 : 0; \ |
502 | 187k | } |
503 | | |
504 | | #define CLOOPC(TYPE, OP) \ |
505 | 0 | { \ |
506 | 0 | TYPE *restrict p = (TYPE *) in[0]; \ |
507 | 0 | \ |
508 | 0 | for (i = 0, x = 0; x < width; x++) { \ |
509 | 0 | double *restrict c = uconst->c_double; \ |
510 | 0 | \ |
511 | 0 | for (b = 0; b < bands; b++, i++) { \ |
512 | 0 | out[i] = OP(p[0], p[1], c[0], c[1]) ? 255 : 0; \ |
513 | 0 | \ |
514 | 0 | p += 2; \ |
515 | 0 | c += 2; \ |
516 | 0 | } \ |
517 | 0 | } \ |
518 | 0 | } |
519 | | |
520 | | static void |
521 | | vips_relational_const_buffer(VipsArithmetic *arithmetic, |
522 | | VipsPel *out, VipsPel **in, int width) |
523 | 187k | { |
524 | 187k | VipsUnaryConst *uconst = (VipsUnaryConst *) arithmetic; |
525 | 187k | VipsRelationalConst *rconst = (VipsRelationalConst *) arithmetic; |
526 | 187k | VipsImage *im = arithmetic->ready[0]; |
527 | 187k | int bands = im->Bands; |
528 | 187k | gboolean is_int = uconst->is_int && |
529 | 187k | vips_band_format_isint(im->BandFmt); |
530 | | |
531 | 187k | int i, x, b; |
532 | | |
533 | 187k | switch (rconst->relational) { |
534 | 0 | case VIPS_OPERATION_RELATIONAL_EQUAL: |
535 | 0 | if (is_int) { |
536 | 0 | SWITCH(RLOOPCI, CLOOPC, ==, CEQUAL); |
537 | 0 | } |
538 | 0 | else { |
539 | 0 | SWITCH(RLOOPCF, CLOOPC, ==, CEQUAL); |
540 | 0 | } |
541 | 0 | break; |
542 | | |
543 | 0 | case VIPS_OPERATION_RELATIONAL_NOTEQ: |
544 | 0 | if (is_int) { |
545 | 0 | SWITCH(RLOOPCI, CLOOPC, !=, CNOTEQ); |
546 | 0 | } |
547 | 0 | else { |
548 | 0 | SWITCH(RLOOPCF, CLOOPC, !=, CNOTEQ); |
549 | 0 | } |
550 | 0 | break; |
551 | | |
552 | 0 | case VIPS_OPERATION_RELATIONAL_LESS: |
553 | 0 | if (is_int) { |
554 | 0 | SWITCH(RLOOPCI, CLOOPC, <, CLESS); |
555 | 0 | } |
556 | 0 | else { |
557 | 0 | SWITCH(RLOOPCF, CLOOPC, <, CLESS); |
558 | 0 | } |
559 | 0 | break; |
560 | | |
561 | 0 | case VIPS_OPERATION_RELATIONAL_LESSEQ: |
562 | 0 | if (is_int) { |
563 | 0 | SWITCH(RLOOPCI, CLOOPC, <=, CLESSEQ); |
564 | 0 | } |
565 | 0 | else { |
566 | 0 | SWITCH(RLOOPCF, CLOOPC, <=, CLESSEQ); |
567 | 0 | } |
568 | 0 | break; |
569 | | |
570 | 187k | case VIPS_OPERATION_RELATIONAL_MORE: |
571 | 187k | if (is_int) { |
572 | 0 | SWITCH(RLOOPCI, CLOOPC, >, CMORE); |
573 | 0 | } |
574 | 187k | else { |
575 | 187k | SWITCH(RLOOPCF, CLOOPC, >, CMORE); |
576 | 187k | } |
577 | 187k | break; |
578 | | |
579 | 187k | case VIPS_OPERATION_RELATIONAL_MOREEQ: |
580 | 0 | if (is_int) { |
581 | 0 | SWITCH(RLOOPCI, CLOOPC, >=, CMOREEQ); |
582 | 0 | } |
583 | 0 | else { |
584 | 0 | SWITCH(RLOOPCF, CLOOPC, >=, CMOREEQ); |
585 | 0 | } |
586 | 0 | break; |
587 | | |
588 | 0 | default: |
589 | 0 | g_assert_not_reached(); |
590 | 187k | } |
591 | 187k | } |
592 | | |
593 | | static void |
594 | | vips_relational_const_class_init(VipsRelationalConstClass *class) |
595 | 17 | { |
596 | 17 | GObjectClass *gobject_class = G_OBJECT_CLASS(class); |
597 | 17 | VipsObjectClass *object_class = (VipsObjectClass *) class; |
598 | 17 | VipsArithmeticClass *aclass = VIPS_ARITHMETIC_CLASS(class); |
599 | | |
600 | 17 | gobject_class->set_property = vips_object_set_property; |
601 | 17 | gobject_class->get_property = vips_object_get_property; |
602 | | |
603 | 17 | object_class->nickname = "relational_const"; |
604 | 17 | object_class->description = |
605 | 17 | _("relational operations against a constant"); |
606 | | |
607 | 17 | aclass->process_line = vips_relational_const_buffer; |
608 | | |
609 | 17 | vips_arithmetic_set_format_table(aclass, |
610 | 17 | vips_relational_format_table); |
611 | | |
612 | 17 | VIPS_ARG_ENUM(class, "relational", 200, |
613 | 17 | _("Operation"), |
614 | 17 | _("Relational to perform"), |
615 | 17 | VIPS_ARGUMENT_REQUIRED_INPUT, |
616 | 17 | G_STRUCT_OFFSET(VipsRelationalConst, relational), |
617 | 17 | VIPS_TYPE_OPERATION_RELATIONAL, |
618 | 17 | VIPS_OPERATION_RELATIONAL_EQUAL); |
619 | 17 | } |
620 | | |
621 | | static void |
622 | | vips_relational_const_init(VipsRelationalConst *relational_const) |
623 | 15.1k | { |
624 | 15.1k | } |
625 | | |
626 | | static int |
627 | | vips_relational_constv(VipsImage *in, VipsImage **out, |
628 | | VipsOperationRelational relational, const double *c, int n, va_list ap) |
629 | 15.1k | { |
630 | 15.1k | VipsArea *area_c; |
631 | 15.1k | double *array; |
632 | 15.1k | int result; |
633 | 15.1k | int i; |
634 | | |
635 | 15.1k | area_c = vips_area_new_array(G_TYPE_DOUBLE, sizeof(double), n); |
636 | 15.1k | array = (double *) area_c->data; |
637 | 30.2k | for (i = 0; i < n; i++) |
638 | 15.1k | array[i] = c[i]; |
639 | | |
640 | 15.1k | result = vips_call_split("relational_const", ap, |
641 | 15.1k | in, out, relational, area_c); |
642 | | |
643 | 15.1k | vips_area_unref(area_c); |
644 | | |
645 | 15.1k | return result; |
646 | 15.1k | } |
647 | | |
648 | | /** |
649 | | * vips_relational_const: (method) |
650 | | * @in: input image |
651 | | * @out: (out): output image |
652 | | * @relational: relational operation to perform |
653 | | * @c: (array length=n): array of constants |
654 | | * @n: number of constants in @c |
655 | | * @...: `NULL`-terminated list of optional named arguments |
656 | | * |
657 | | * Perform various relational operations on an image and an array of |
658 | | * constants. |
659 | | * |
660 | | * The output type is always uchar, with 0 for `FALSE` and 255 for `TRUE`. |
661 | | * |
662 | | * If the array of constants has just one element, that constant is used for |
663 | | * all image bands. If the array has more than one element and they have |
664 | | * the same number of elements as there are bands in the image, then |
665 | | * one array element is used for each band. If the arrays have more than one |
666 | | * element and the image only has a single band, the result is a many-band |
667 | | * image where each band corresponds to one array element. |
668 | | * |
669 | | * ::: seealso |
670 | | * [method@Image.boolean], [method@Image.relational]. |
671 | | * |
672 | | * Returns: 0 on success, -1 on error |
673 | | */ |
674 | | int |
675 | | vips_relational_const(VipsImage *in, VipsImage **out, |
676 | | VipsOperationRelational relational, const double *c, int n, ...) |
677 | 0 | { |
678 | 0 | va_list ap; |
679 | 0 | int result; |
680 | |
|
681 | 0 | va_start(ap, n); |
682 | 0 | result = vips_relational_constv(in, out, relational, c, n, ap); |
683 | 0 | va_end(ap); |
684 | |
|
685 | 0 | return result; |
686 | 0 | } |
687 | | |
688 | | /** |
689 | | * vips_equal_const: (method) |
690 | | * @in: input [class@Image] |
691 | | * @out: (out): output [class@Image] |
692 | | * @c: (array length=n): array of constants |
693 | | * @n: number of constants in @c |
694 | | * @...: `NULL`-terminated list of optional named arguments |
695 | | * |
696 | | * Perform [enum@Vips.OperationRelational.EQUAL] on an image and a constant. See |
697 | | * [method@Image.relational_const]. |
698 | | * |
699 | | * Returns: 0 on success, -1 on error |
700 | | */ |
701 | | int |
702 | | vips_equal_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) |
703 | 0 | { |
704 | 0 | va_list ap; |
705 | 0 | int result; |
706 | |
|
707 | 0 | va_start(ap, n); |
708 | 0 | result = vips_relational_constv(in, out, |
709 | 0 | VIPS_OPERATION_RELATIONAL_EQUAL, c, n, ap); |
710 | 0 | va_end(ap); |
711 | |
|
712 | 0 | return result; |
713 | 0 | } |
714 | | |
715 | | /** |
716 | | * vips_notequal_const: (method) |
717 | | * @in: input [class@Image] |
718 | | * @out: (out): output [class@Image] |
719 | | * @c: (array length=n): array of constants |
720 | | * @n: number of constants in @c |
721 | | * @...: `NULL`-terminated list of optional named arguments |
722 | | * |
723 | | * Perform [enum@Vips.OperationRelational.NOTEQ] on an image and a constant. See |
724 | | * [method@Image.relational_const]. |
725 | | * |
726 | | * Returns: 0 on success, -1 on error |
727 | | */ |
728 | | int |
729 | | vips_notequal_const(VipsImage *in, VipsImage **out, |
730 | | const double *c, int n, ...) |
731 | 0 | { |
732 | 0 | va_list ap; |
733 | 0 | int result; |
734 | |
|
735 | 0 | va_start(ap, n); |
736 | 0 | result = vips_relational_constv(in, out, |
737 | 0 | VIPS_OPERATION_RELATIONAL_NOTEQ, c, n, ap); |
738 | 0 | va_end(ap); |
739 | |
|
740 | 0 | return result; |
741 | 0 | } |
742 | | |
743 | | /** |
744 | | * vips_less_const: (method) |
745 | | * @in: input [class@Image] |
746 | | * @out: (out): output [class@Image] |
747 | | * @c: (array length=n): array of constants |
748 | | * @n: number of constants in @c |
749 | | * @...: `NULL`-terminated list of optional named arguments |
750 | | * |
751 | | * Perform [enum@Vips.OperationRelational.LESS] on an image and a constant. See |
752 | | * [method@Image.relational_const]. |
753 | | * |
754 | | * Returns: 0 on success, -1 on error |
755 | | */ |
756 | | int |
757 | | vips_less_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) |
758 | 0 | { |
759 | 0 | va_list ap; |
760 | 0 | int result; |
761 | |
|
762 | 0 | va_start(ap, n); |
763 | 0 | result = vips_relational_constv(in, out, |
764 | 0 | VIPS_OPERATION_RELATIONAL_LESS, c, n, ap); |
765 | 0 | va_end(ap); |
766 | |
|
767 | 0 | return result; |
768 | 0 | } |
769 | | |
770 | | /** |
771 | | * vips_lesseq_const: (method) |
772 | | * @in: input [class@Image] |
773 | | * @out: (out): output [class@Image] |
774 | | * @c: (array length=n): array of constants |
775 | | * @n: number of constants in @c |
776 | | * @...: `NULL`-terminated list of optional named arguments |
777 | | * |
778 | | * Perform [enum@Vips.OperationRelational.LESSEQ] on an image and a constant. See |
779 | | * [method@Image.relational_const]. |
780 | | * |
781 | | * Returns: 0 on success, -1 on error |
782 | | */ |
783 | | int |
784 | | vips_lesseq_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) |
785 | 0 | { |
786 | 0 | va_list ap; |
787 | 0 | int result; |
788 | |
|
789 | 0 | va_start(ap, n); |
790 | 0 | result = vips_relational_constv(in, out, |
791 | 0 | VIPS_OPERATION_RELATIONAL_LESSEQ, c, n, ap); |
792 | 0 | va_end(ap); |
793 | |
|
794 | 0 | return result; |
795 | 0 | } |
796 | | |
797 | | /** |
798 | | * vips_more_const: (method) |
799 | | * @in: input [class@Image] |
800 | | * @out: (out): output [class@Image] |
801 | | * @c: (array length=n): array of constants |
802 | | * @n: number of constants in @c |
803 | | * @...: `NULL`-terminated list of optional named arguments |
804 | | * |
805 | | * Perform [enum@Vips.OperationRelational.MORE] on an image and a constant. See |
806 | | * [method@Image.relational_const]. |
807 | | * |
808 | | * Returns: 0 on success, -1 on error |
809 | | */ |
810 | | int |
811 | | vips_more_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) |
812 | 0 | { |
813 | 0 | va_list ap; |
814 | 0 | int result; |
815 | |
|
816 | 0 | va_start(ap, n); |
817 | 0 | result = vips_relational_constv(in, out, |
818 | 0 | VIPS_OPERATION_RELATIONAL_MORE, c, n, ap); |
819 | 0 | va_end(ap); |
820 | |
|
821 | 0 | return result; |
822 | 0 | } |
823 | | |
824 | | /** |
825 | | * vips_moreeq_const: (method) |
826 | | * @in: input [class@Image] |
827 | | * @out: (out): output [class@Image] |
828 | | * @c: (array length=n): array of constants |
829 | | * @n: number of constants in @c |
830 | | * @...: `NULL`-terminated list of optional named arguments |
831 | | * |
832 | | * Perform [enum@Vips.OperationRelational.MOREEQ] on an image and a constant. See |
833 | | * [method@Image.relational_const]. |
834 | | * |
835 | | * Returns: 0 on success, -1 on error |
836 | | */ |
837 | | int |
838 | | vips_moreeq_const(VipsImage *in, VipsImage **out, const double *c, int n, ...) |
839 | 0 | { |
840 | 0 | va_list ap; |
841 | 0 | int result; |
842 | |
|
843 | 0 | va_start(ap, n); |
844 | 0 | result = vips_relational_constv(in, out, |
845 | 0 | VIPS_OPERATION_RELATIONAL_MOREEQ, c, n, ap); |
846 | 0 | va_end(ap); |
847 | |
|
848 | 0 | return result; |
849 | 0 | } |
850 | | |
851 | | /** |
852 | | * vips_relational_const1: (method) |
853 | | * @in: input image |
854 | | * @out: (out): output image |
855 | | * @relational: relational operation to perform |
856 | | * @c: constant |
857 | | * @...: `NULL`-terminated list of optional named arguments |
858 | | * |
859 | | * Perform various relational operations on an image and a constant. See |
860 | | * [method@Image.relational_const]. |
861 | | * |
862 | | * ::: seealso |
863 | | * [method@Image.boolean], [method@Image.relational]. |
864 | | * |
865 | | * Returns: 0 on success, -1 on error |
866 | | */ |
867 | | int |
868 | | vips_relational_const1(VipsImage *in, VipsImage **out, |
869 | | VipsOperationRelational relational, double c, ...) |
870 | 0 | { |
871 | 0 | va_list ap; |
872 | 0 | int result; |
873 | |
|
874 | 0 | va_start(ap, c); |
875 | 0 | result = vips_relational_constv(in, out, relational, &c, 1, ap); |
876 | 0 | va_end(ap); |
877 | |
|
878 | 0 | return result; |
879 | 0 | } |
880 | | |
881 | | /** |
882 | | * vips_equal_const1: (method) |
883 | | * @in: input image |
884 | | * @out: (out): output image |
885 | | * @c: constant |
886 | | * @...: `NULL`-terminated list of optional named arguments |
887 | | * |
888 | | * Perform [enum@Vips.OperationRelational.EQUAL] on an image and a constant. See |
889 | | * [method@Image.relational_const]. |
890 | | * |
891 | | * Returns: 0 on success, -1 on error |
892 | | */ |
893 | | int |
894 | | vips_equal_const1(VipsImage *in, VipsImage **out, double c, ...) |
895 | 0 | { |
896 | 0 | va_list ap; |
897 | 0 | int result; |
898 | |
|
899 | 0 | va_start(ap, c); |
900 | 0 | result = vips_relational_constv(in, out, |
901 | 0 | VIPS_OPERATION_RELATIONAL_EQUAL, &c, 1, ap); |
902 | 0 | va_end(ap); |
903 | |
|
904 | 0 | return result; |
905 | 0 | } |
906 | | |
907 | | /** |
908 | | * vips_notequal_const1: (method) |
909 | | * @in: input image |
910 | | * @out: (out): output image |
911 | | * @c: constant |
912 | | * @...: `NULL`-terminated list of optional named arguments |
913 | | * |
914 | | * Perform [enum@Vips.OperationRelational.NOTEQ] on an image and a constant. See |
915 | | * [method@Image.relational_const]. |
916 | | * |
917 | | * Returns: 0 on success, -1 on error |
918 | | */ |
919 | | int |
920 | | vips_notequal_const1(VipsImage *in, VipsImage **out, double c, ...) |
921 | 0 | { |
922 | 0 | va_list ap; |
923 | 0 | int result; |
924 | |
|
925 | 0 | va_start(ap, c); |
926 | 0 | result = vips_relational_constv(in, out, |
927 | 0 | VIPS_OPERATION_RELATIONAL_NOTEQ, &c, 1, ap); |
928 | 0 | va_end(ap); |
929 | |
|
930 | 0 | return result; |
931 | 0 | } |
932 | | |
933 | | /** |
934 | | * vips_less_const1: (method) |
935 | | * @in: input image |
936 | | * @out: (out): output image |
937 | | * @c: constant |
938 | | * @...: `NULL`-terminated list of optional named arguments |
939 | | * |
940 | | * Perform [enum@Vips.OperationRelational.LESS] on an image and a constant. See |
941 | | * [method@Image.relational_const]. |
942 | | * |
943 | | * Returns: 0 on success, -1 on error |
944 | | */ |
945 | | int |
946 | | vips_less_const1(VipsImage *in, VipsImage **out, double c, ...) |
947 | 0 | { |
948 | 0 | va_list ap; |
949 | 0 | int result; |
950 | |
|
951 | 0 | va_start(ap, c); |
952 | 0 | result = vips_relational_constv(in, out, |
953 | 0 | VIPS_OPERATION_RELATIONAL_LESS, &c, 1, ap); |
954 | 0 | va_end(ap); |
955 | |
|
956 | 0 | return result; |
957 | 0 | } |
958 | | |
959 | | /** |
960 | | * vips_lesseq_const1: (method) |
961 | | * @in: input image |
962 | | * @out: (out): output image |
963 | | * @c: constant |
964 | | * @...: `NULL`-terminated list of optional named arguments |
965 | | * |
966 | | * Perform [enum@Vips.OperationRelational.LESSEQ] on an image and a constant. See |
967 | | * [method@Image.relational_const]. |
968 | | * |
969 | | * Returns: 0 on success, -1 on error |
970 | | */ |
971 | | int |
972 | | vips_lesseq_const1(VipsImage *in, VipsImage **out, double c, ...) |
973 | 0 | { |
974 | 0 | va_list ap; |
975 | 0 | int result; |
976 | |
|
977 | 0 | va_start(ap, c); |
978 | 0 | result = vips_relational_constv(in, out, |
979 | 0 | VIPS_OPERATION_RELATIONAL_LESSEQ, &c, 1, ap); |
980 | 0 | va_end(ap); |
981 | |
|
982 | 0 | return result; |
983 | 0 | } |
984 | | |
985 | | /** |
986 | | * vips_more_const1: (method) |
987 | | * @in: input image |
988 | | * @out: (out): output image |
989 | | * @c: constant |
990 | | * @...: `NULL`-terminated list of optional named arguments |
991 | | * |
992 | | * Perform [enum@Vips.OperationRelational.MORE] on an image and a constant. See |
993 | | * [method@Image.relational_const]. |
994 | | * |
995 | | * Returns: 0 on success, -1 on error |
996 | | */ |
997 | | int |
998 | | vips_more_const1(VipsImage *in, VipsImage **out, double c, ...) |
999 | 15.1k | { |
1000 | 15.1k | va_list ap; |
1001 | 15.1k | int result; |
1002 | | |
1003 | 15.1k | va_start(ap, c); |
1004 | 15.1k | result = vips_relational_constv(in, out, |
1005 | 15.1k | VIPS_OPERATION_RELATIONAL_MORE, &c, 1, ap); |
1006 | 15.1k | va_end(ap); |
1007 | | |
1008 | 15.1k | return result; |
1009 | 15.1k | } |
1010 | | |
1011 | | /** |
1012 | | * vips_moreeq_const1: (method) |
1013 | | * @in: input image |
1014 | | * @out: (out): output image |
1015 | | * @c: constant |
1016 | | * @...: `NULL`-terminated list of optional named arguments |
1017 | | * |
1018 | | * Perform [enum@Vips.OperationRelational.MOREEQ] on an image and a constant. See |
1019 | | * [method@Image.relational_const]. |
1020 | | * |
1021 | | * Returns: 0 on success, -1 on error |
1022 | | */ |
1023 | | int |
1024 | | vips_moreeq_const1(VipsImage *in, VipsImage **out, double c, ...) |
1025 | 0 | { |
1026 | 0 | va_list ap; |
1027 | 0 | int result; |
1028 | |
|
1029 | 0 | va_start(ap, c); |
1030 | 0 | result = vips_relational_constv(in, out, |
1031 | 0 | VIPS_OPERATION_RELATIONAL_MOREEQ, &c, 1, ap); |
1032 | 0 | va_end(ap); |
1033 | |
|
1034 | 0 | return result; |
1035 | 0 | } |