Update Chinese (China) translation
[gegl.git] / operations / common / convolution-matrix.c
blob2ce65e670239d3e86a2b573d3c3110ad140325b9
1 /* This file is an image processing operation for GEGL
3 * GEGL is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 3 of the License, or (at your option) any later version.
8 * GEGL is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
16 * Copyright (C) 1997 Lauri Alanko <la@iki.fi>
17 * Copyright 2011 Robert Sasu (sasu.robert@gmail.com)
20 #include "config.h"
21 #include <glib/gi18n-lib.h>
23 #ifdef GEGL_PROPERTIES
25 property_double (a1, _("(1,1)"), 0.0)
26 property_double (a2, _("(1,2)"), 0.0)
27 property_double (a3, _("(1,3)"), 0.0)
28 property_double (a4, _("(1,4)"), 0.0)
29 property_double (a5, _("(1,5)"), 0.0)
30 property_double (b1, _("(2,1)"), 0.0)
31 property_double (b2, _("(2,2)"), 0.0)
32 property_double (b3, _("(2,3)"), 0.0)
33 property_double (b4, _("(2,4)"), 0.0)
34 property_double (b5, _("(2,5)"), 0.0)
35 property_double (c1, _("(3,1)"), 0.0)
36 property_double (c2, _("(3,2)"), 0.0)
37 property_double (c3, _("(3,3)"), 1.0)
38 property_double (c4, _("(3,4)"), 0.0)
39 property_double (c5, _("(3,5)"), 0.0)
40 property_double (d1, _("(4,1)"), 0.0)
41 property_double (d2, _("(4,2)"), 0.0)
42 property_double (d3, _("(4,3)"), 0.0)
43 property_double (d4, _("(4,4)"), 0.0)
44 property_double (d5, _("(4,5)"), 0.0)
45 property_double (e1, _("(5,1)"), 0.0)
46 property_double (e2, _("(5,2)"), 0.0)
47 property_double (e3, _("(5,3)"), 0.0)
48 property_double (e4, _("(5,4)"), 0.0)
49 property_double (e5, _("(5,5)"), 0.0)
51 property_double (divisor, _("Divisor"), 1.0)
52 ui_range (-1000.0, 1000.0)
53 ui_meta ("sensitive", "! normalize")
55 property_double (offset, _("Offset"), 0.0)
56 value_range (-1.0, 1.0)
57 ui_meta ("sensitive", "! normalize")
59 property_boolean (red, _("Red channel"), TRUE)
60 property_boolean (green, _("Green channel"), TRUE)
61 property_boolean (blue, _("Blue channel"), TRUE)
62 property_boolean (alpha, _("Alpha channel"), TRUE)
64 property_boolean (normalize, _("Normalize"), TRUE)
65 property_boolean (alpha_weight, _("Alpha-weighting"), TRUE)
67 property_enum (border, _("Border"),
68 GeglAbyssPolicy, gegl_abyss_policy,
69 GEGL_ABYSS_CLAMP)
71 #else
73 #define GEGL_OP_AREA_FILTER
74 #define GEGL_OP_NAME convolution_matrix
75 #define GEGL_OP_C_SOURCE convolution-matrix.c
77 #include "gegl-op.h"
78 #include <stdio.h>
80 #define MAX_MATRIX_SIZE 5
82 static gboolean
83 enough_with_3x3 (GeglProperties *o)
85 if (o->a1 == 0.0 &&
86 o->a2 == 0.0 &&
87 o->a3 == 0.0 &&
88 o->a4 == 0.0 &&
89 o->a5 == 0.0 &&
90 o->b1 == 0.0 &&
91 o->b5 == 0.0 &&
92 o->c1 == 0.0 &&
93 o->c5 == 0.0 &&
94 o->d1 == 0.0 &&
95 o->d5 == 0.0 &&
96 o->e1 == 0.0 &&
97 o->e2 == 0.0 &&
98 o->e3 == 0.0 &&
99 o->e4 == 0.0 &&
100 o->e5 == 0.0)
102 return TRUE;
104 return FALSE;
107 static void
108 prepare (GeglOperation *operation)
110 const Babl *space = gegl_operation_get_source_space (operation, "input");
112 GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);
114 GeglProperties *o = GEGL_PROPERTIES (operation);
115 if (enough_with_3x3 (o))
116 op_area->left = op_area->right = op_area->top = op_area->bottom = 1; /* 3 */
117 else
118 op_area->left = op_area->right = op_area->top = op_area->bottom = 2; /* 5 */
120 gegl_operation_set_format (operation, "output",
121 babl_format_with_space ("RGBA float", space));
124 static void
125 make_matrix (GeglProperties *o,
126 gfloat matrix[MAX_MATRIX_SIZE][MAX_MATRIX_SIZE],
127 gint matrix_size)
129 if (matrix_size == 3)
131 matrix[0][0] = o->b2;
132 matrix[0][1] = o->b3;
133 matrix[0][2] = o->b4;
135 matrix[1][0] = o->c2;
136 matrix[1][1] = o->c3;
137 matrix[1][2] = o->c4;
139 matrix[2][0] = o->d2;
140 matrix[2][1] = o->d3;
141 matrix[2][2] = o->d4;
143 else
145 matrix[0][0] = o->a1;
146 matrix[0][1] = o->a2;
147 matrix[0][2] = o->a3;
148 matrix[0][3] = o->a4;
149 matrix[0][4] = o->a5;
151 matrix[1][0] = o->b1;
152 matrix[1][1] = o->b2;
153 matrix[1][2] = o->b3;
154 matrix[1][3] = o->b4;
155 matrix[1][4] = o->b5;
157 matrix[2][0] = o->c1;
158 matrix[2][1] = o->c2;
159 matrix[2][2] = o->c3;
160 matrix[2][3] = o->c4;
161 matrix[2][4] = o->c5;
163 matrix[3][0] = o->d1;
164 matrix[3][1] = o->d2;
165 matrix[3][2] = o->d3;
166 matrix[3][3] = o->d4;
167 matrix[3][4] = o->d5;
169 matrix[4][0] = o->e1;
170 matrix[4][1] = o->e2;
171 matrix[4][2] = o->e3;
172 matrix[4][3] = o->e4;
173 matrix[4][4] = o->e5;
177 static gboolean
178 normalize_div_off (gfloat matrix[MAX_MATRIX_SIZE][MAX_MATRIX_SIZE],
179 gint matrix_size,
180 gfloat *divisor,
181 gfloat *offset)
183 gint x, y;
184 gboolean valid = FALSE;
185 gfloat sum = 0.0;
187 for (y = 0; y < matrix_size; y++)
188 for (x = 0; x < matrix_size; x++)
190 sum += matrix[x][y];
191 if (matrix[x][y] != 0.0)
192 valid = TRUE;
195 if (sum > 0)
197 *offset = 0.0;
198 *divisor = sum;
200 else if (sum < 0)
202 *offset = 1.0;
203 *divisor = -sum;
205 else
207 *offset = 0.5;
208 *divisor = 1;
211 return valid;
214 static gint inline
215 matrix_center_offset (const GeglRectangle *extended,
216 gint matrix_size)
218 return (extended->width + 1) * (matrix_size / 2);
221 static void inline
222 convolve_pixel_componentwise (GeglProperties *o,
223 gfloat *src_buf,
224 gfloat *dst_buf,
225 const GeglRectangle *result,
226 const GeglRectangle *extended,
227 gfloat matrix[MAX_MATRIX_SIZE][MAX_MATRIX_SIZE],
228 gint matrix_size,
229 gint d_offset,
230 gint ss_offset,
231 gint xx,
232 gint yy,
233 gfloat matrixsum,
234 gfloat inv_divisor,
235 gfloat offset)
237 gint i;
238 gint s_stride = (extended->width - matrix_size) * 4;
239 for (i = 0; i < 4; i++)
241 gfloat sum = 0.0;
242 gint s_offset = ss_offset;
244 if ((i == 0 && o->red) ||
245 (i == 1 && o->green) ||
246 (i == 2 && o->blue) ||
247 (i == 3 && o->alpha))
249 gint x, y;
250 for (y = 0; y < matrix_size; y++)
252 for (x = 0; x < matrix_size; x++)
254 sum += matrix[x][y] * src_buf[s_offset + i];
255 s_offset += 4;
257 s_offset += s_stride;
259 sum = sum * inv_divisor;
260 sum += offset;
261 dst_buf[d_offset + i] = sum;
263 else
265 s_offset += 4 * matrix_center_offset (extended, matrix_size);
266 dst_buf[d_offset + i] = src_buf[s_offset + i];
271 static void inline
272 convolve_pixel (GeglProperties *o,
273 gfloat *src_buf,
274 gfloat *dst_buf,
275 const GeglRectangle *result,
276 const GeglRectangle *extended,
277 gfloat matrix[MAX_MATRIX_SIZE][MAX_MATRIX_SIZE],
278 gint matrix_size,
279 gint d_offset,
280 gint ss_offset,
281 gint xx,
282 gint yy,
283 gfloat matrixsum,
284 gfloat inv_divisor,
285 gfloat offset)
287 gint i;
288 gint s_stride = (extended->width - matrix_size) * 4;
289 for (i = 0; i < 4; i++)
291 gfloat sum = 0.0;
292 gint s_offset = ss_offset;
293 gint x, y;
294 for (y = 0; y < matrix_size; y++)
296 for (x = 0; x < matrix_size; x++)
298 sum += matrix[x][y] * src_buf[s_offset + i];
299 s_offset += 4;
301 s_offset += s_stride;
303 sum = sum * inv_divisor;
304 sum += offset;
305 dst_buf[d_offset + i] = sum;
309 static void inline
310 convolve_pixel_alpha_weight (GeglProperties *o,
311 gfloat *src_buf,
312 gfloat *dst_buf,
313 const GeglRectangle *result,
314 const GeglRectangle *extended,
315 gfloat matrix[MAX_MATRIX_SIZE][MAX_MATRIX_SIZE],
316 gint matrix_size,
317 gint d_offset,
318 gint ss_offset,
319 gint xx,
320 gint yy,
321 gfloat matrixsum,
322 gfloat inv_divisor,
323 gfloat offset)
325 gint i;
326 gint s_stride = (extended->width - matrix_size) * 4;
328 for (i = 0; i < 3; i++)
330 gfloat sum = 0.0;
331 gint s_offset = ss_offset;
332 gint x, y;
333 for (y = 0; y < matrix_size; y++)
335 for (x = 0; x < matrix_size; x++)
337 sum += matrix[x][y] * src_buf[s_offset + i] * src_buf[s_offset + 3];
338 s_offset += 4;
340 s_offset += s_stride;
342 sum = sum * inv_divisor + offset;
343 dst_buf[d_offset + i] = sum;
346 gfloat sum = 0.0;
347 gfloat alphasum = 0.0;
348 gint s_offset = ss_offset;
349 gint x, y;
351 for (y = 0; y < matrix_size; y++)
353 for (x = 0; x < matrix_size; x++)
355 float val = matrix[x][y] * src_buf[s_offset + i];
356 sum += val;
357 alphasum += fabsf (val);
358 s_offset += 4;
360 s_offset += s_stride;
363 if (alphasum > 0.0)
365 sum = sum * inv_divisor;
366 sum = sum * matrixsum / alphasum + offset;
368 else
369 sum = offset;
370 dst_buf[d_offset + i] = sum;
374 static void inline
375 convolve_pixel_alpha_weight_componentwise (GeglProperties *o,
376 gfloat *src_buf,
377 gfloat *dst_buf,
378 const GeglRectangle *result,
379 const GeglRectangle *extended,
380 gfloat matrix[MAX_MATRIX_SIZE][MAX_MATRIX_SIZE],
381 gint matrix_size,
382 gint d_offset,
383 gint ss_offset,
384 gint xx,
385 gint yy,
386 gfloat matrixsum,
387 gfloat inv_divisor,
388 gfloat offset)
390 gint i;
391 gint s_stride = (extended->width - matrix_size) * 4;
393 for (i = 0; i < 3; i++)
395 gfloat sum = 0.0;
396 gint s_offset = ss_offset;
398 if ((i == 0 && o->red) ||
399 (i == 1 && o->green) ||
400 (i == 2 && o->blue))
402 gint x, y;
403 for (y = 0; y < matrix_size; y++)
405 for (x = 0; x < matrix_size; x++)
407 sum += matrix[x][y] * src_buf[s_offset + i] * src_buf[s_offset + 3];
408 s_offset += 4;
410 s_offset += s_stride;
412 sum = sum * inv_divisor + offset;
414 else
416 s_offset += 4 * matrix_center_offset (extended, matrix_size);
417 sum = src_buf[s_offset + i];
419 dst_buf[d_offset + i] = sum;
422 gfloat sum = 0.0;
423 gfloat alphasum = 0.0;
424 gint s_offset = ss_offset;
426 if (o->alpha)
428 gint x, y;
430 for (y = 0; y < matrix_size; y++)
432 for (x = 0; x < matrix_size; x++)
434 float val = matrix[x][y] * src_buf[s_offset + i];
435 sum += val;
436 alphasum += fabsf (val);
437 s_offset += 4;
439 s_offset += s_stride;
443 if (alphasum != 0)
445 sum = sum * inv_divisor;
446 sum = sum * matrixsum / alphasum + offset;
448 else
449 sum = offset;
451 else
453 s_offset += 4 * matrix_center_offset (extended, matrix_size);
454 sum = src_buf[s_offset + i];
456 dst_buf[d_offset + i] = sum;
460 static gboolean
461 process (GeglOperation *operation,
462 GeglBuffer *input,
463 GeglBuffer *output,
464 const GeglRectangle *result,
465 gint level)
467 GeglProperties *o = GEGL_PROPERTIES (operation);
468 GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);
469 const Babl *format = gegl_operation_get_format (operation, "output");
470 GeglRectangle rect;
471 gfloat *src_buf;
472 gfloat *dst_buf;
473 gfloat matrix[MAX_MATRIX_SIZE][MAX_MATRIX_SIZE]={{0,}};
474 gfloat matrixsum = 0.0;
475 gfloat divisor = o->divisor;
476 gfloat offset = o->offset;
477 gfloat inv_divisor;
478 gint x, y;
479 gint matrix_size = MAX_MATRIX_SIZE;
481 if (enough_with_3x3 (o))
482 matrix_size = 3;
484 make_matrix (o, matrix, matrix_size);
486 if (o->normalize)
487 normalize_div_off (matrix, matrix_size, &divisor, &offset);
488 inv_divisor = 1.0 / divisor;
490 for (x = 0; x < matrix_size; x++)
491 for (y = 0; y < matrix_size; y++)
492 matrixsum += fabsf (matrix[x][y]);
494 rect.x = result->x - op_area->left;
495 rect.width = result->width + op_area->left + op_area->right;
496 rect.y = result->y - op_area->top;
497 rect.height = result->height + op_area->top + op_area->bottom;
499 src_buf = g_new (gfloat, rect.width * rect.height * 4);
500 dst_buf = g_new (gfloat, result->width * result->height * 4);
502 gegl_buffer_get (input, &rect, 1.0, format, src_buf,
503 GEGL_AUTO_ROWSTRIDE, o->border);
505 if (o->divisor != 0)
507 gint ss_offset = (result->y - matrix_size/2 - rect.y) * rect.width * 4 +
508 (result->x - matrix_size/2 - rect.x) * 4;
509 int d_offset = 0;
510 if (o->alpha_weight)
512 if (o->red == FALSE || o->green == FALSE || o->blue == FALSE || o->alpha == FALSE)
514 gint x, y;
515 for (y = result->y; y < result->height + result->y; y++)
517 for (x = result->x; x < result->width + result->x; x++)
519 convolve_pixel_alpha_weight_componentwise (o, src_buf, dst_buf, result, &rect,
520 matrix, matrix_size, d_offset, ss_offset, x, y, matrixsum, inv_divisor, offset);
521 d_offset += 4;
522 ss_offset += 4;
524 ss_offset += (rect.width - result->width) * 4;
527 else
529 gint x, y;
530 for (y = result->y; y < result->height + result->y; y++)
532 for (x = result->x; x < result->width + result->x; x++)
534 convolve_pixel_alpha_weight (o, src_buf, dst_buf, result, &rect,
535 matrix, matrix_size, d_offset, ss_offset, x, y, matrixsum, inv_divisor, offset);
536 d_offset += 4;
537 ss_offset += 4;
539 ss_offset += (rect.width - result->width) * 4;
543 else
545 if (o->red == FALSE || o->green == FALSE || o->blue == FALSE || o->alpha == FALSE)
547 gint x, y;
548 for (y = result->y; y < result->height + result->y; y++)
550 for (x = result->x; x < result->width + result->x; x++)
552 convolve_pixel_componentwise (o, src_buf, dst_buf, result, &rect,
553 matrix, matrix_size, d_offset, ss_offset, x, y, matrixsum, inv_divisor, offset);
554 d_offset += 4;
555 ss_offset += 4;
557 ss_offset += (rect.width - result->width) * 4;
560 else
562 gint x, y;
563 for (y = result->y; y < result->height + result->y; y++)
565 for (x = result->x; x < result->width + result->x; x++)
567 convolve_pixel (o, src_buf, dst_buf, result, &rect,
568 matrix, matrix_size, d_offset, ss_offset, x, y, matrixsum, inv_divisor, offset);
569 d_offset += 4;
570 ss_offset += 4;
572 ss_offset += (rect.width - result->width) * 4;
576 gegl_buffer_set (output, result, 0, format,
577 dst_buf, GEGL_AUTO_ROWSTRIDE);
579 else
581 gegl_buffer_set (output, &rect, 0, format,
582 src_buf, GEGL_AUTO_ROWSTRIDE);
585 g_free (src_buf);
586 g_free (dst_buf);
588 return TRUE;
591 static GeglRectangle
592 get_bounding_box (GeglOperation *operation)
594 GeglRectangle result = { 0, };
595 GeglRectangle *in_rect;
597 in_rect = gegl_operation_source_get_bounding_box (operation, "input");
598 if (!in_rect)
599 return result;
601 return *in_rect;
604 static GeglAbyssPolicy
605 get_abyss_policy (GeglOperation *operation,
606 const gchar *input_pad)
608 GeglProperties *o = GEGL_PROPERTIES (operation);
610 return o->border;
613 static void
614 gegl_op_class_init (GeglOpClass *klass)
616 GeglOperationClass *operation_class;
617 GeglOperationFilterClass *filter_class;
618 GeglOperationAreaFilterClass *area_class;
620 operation_class = GEGL_OPERATION_CLASS (klass);
621 filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
622 area_class = GEGL_OPERATION_AREA_FILTER_CLASS (klass);
624 area_class->get_abyss_policy = get_abyss_policy;
625 filter_class->process = process;
626 operation_class->prepare = prepare;
627 operation_class->get_bounding_box = get_bounding_box;
629 gegl_operation_class_set_keys (operation_class,
630 "categories", "generic",
631 "name", "gegl:convolution-matrix",
632 "reference-hash", "22d2d47a2da3d3e7cd402ea9fa1a3a25",
633 "reference-hashB", "4eddc0aaa970a59ee8a813627874cdf3",
634 "title", _("Convolution Matrix"),
635 "description", _("Apply a generic 5x5 convolution matrix"),
636 NULL);
639 #endif