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 2005 Øyvind Kolås <pippin@gimp.org>,
17 * 2007 Øyvind Kolås <oeyvindk@hig.no>
21 #include <glib/gi18n-lib.h>
24 #ifdef GEGL_PROPERTIES
26 property_double (blur_radius
, _("Blur radius"), 4.0)
27 description(_("Radius of square pixel region, (width and height will be radius*2+1)."))
28 value_range (0.0, 1000.0)
32 property_double (edge_preservation
, _("Edge preservation"), 8.0)
33 description (_("Amount of edge preservation"))
34 value_range (0.0, 100.0)
38 #define GEGL_OP_AREA_FILTER
39 #define GEGL_OP_NAME bilateral_filter
40 #define GEGL_OP_C_SOURCE bilateral-filter.c
45 bilateral_filter (GeglBuffer
*src
,
46 const GeglRectangle
*src_rect
,
48 const GeglRectangle
*dst_rect
,
55 static void prepare (GeglOperation
*operation
)
57 const Babl
*space
= gegl_operation_get_source_space (operation
, "input");
58 const Babl
*format
= babl_format_with_space ("RGBA float", space
);
59 GeglOperationAreaFilter
*area
= GEGL_OPERATION_AREA_FILTER (operation
);
60 GeglProperties
*o
= GEGL_PROPERTIES (operation
);
62 area
->left
= area
->right
= area
->top
= area
->bottom
= ceil (o
->blur_radius
);
63 gegl_operation_set_format (operation
, "input", format
);
64 gegl_operation_set_format (operation
, "output", format
);
67 #include "opencl/gegl-cl.h"
68 #include "gegl-buffer-cl-iterator.h"
70 #include "opencl/bilateral-filter.cl.h"
72 static GeglClRunData
*cl_data
= NULL
;
75 cl_bilateral_filter (cl_mem in_tex
,
77 size_t global_worksize
,
78 const GeglRectangle
*roi
,
87 const char *kernel_name
[] = {"bilateral_filter", NULL
};
88 cl_data
= gegl_cl_compile_and_build (bilateral_filter_cl_source
, kernel_name
);
90 if (!cl_data
) return TRUE
;
92 global_ws
[0] = roi
->width
;
93 global_ws
[1] = roi
->height
;
95 cl_err
= gegl_clSetKernelArg(cl_data
->kernel
[0], 0, sizeof(cl_mem
), (void*)&in_tex
);
97 cl_err
= gegl_clSetKernelArg(cl_data
->kernel
[0], 1, sizeof(cl_mem
), (void*)&out_tex
);
99 cl_err
= gegl_clSetKernelArg(cl_data
->kernel
[0], 2, sizeof(cl_float
), (void*)&radius
);
101 cl_err
= gegl_clSetKernelArg(cl_data
->kernel
[0], 3, sizeof(cl_float
), (void*)&preserve
);
104 cl_err
= gegl_clEnqueueNDRangeKernel(gegl_cl_get_command_queue (),
105 cl_data
->kernel
[0], 2,
106 NULL
, global_ws
, NULL
,
117 cl_process (GeglOperation
*operation
,
120 const GeglRectangle
*result
)
122 const Babl
*in_format
= gegl_operation_get_format (operation
, "input");
123 const Babl
*out_format
= gegl_operation_get_format (operation
, "output");
126 GeglOperationAreaFilter
*op_area
= GEGL_OPERATION_AREA_FILTER (operation
);
127 GeglProperties
*o
= GEGL_PROPERTIES (operation
);
129 GeglBufferClIterator
*i
= gegl_buffer_cl_iterator_new (output
,
132 GEGL_CL_BUFFER_WRITE
);
134 gint read
= gegl_buffer_cl_iterator_add_2 (i
,
145 while (gegl_buffer_cl_iterator_next (i
, &err
))
147 if (err
) return FALSE
;
149 err
= cl_bilateral_filter(i
->tex
[read
],
153 ceil(o
->blur_radius
),
154 o
->edge_preservation
);
156 if (err
) return FALSE
;
163 process (GeglOperation
*operation
,
166 const GeglRectangle
*result
,
169 GeglProperties
*o
= GEGL_PROPERTIES (operation
);
170 GeglRectangle compute
;
171 const Babl
*format
= gegl_operation_get_format (operation
, "output");
173 if (o
->blur_radius
>= 1.0 && gegl_operation_use_opencl (operation
))
174 if (cl_process (operation
, input
, output
, result
))
177 compute
= gegl_operation_get_required_for_output (operation
, "input",result
);
179 if (o
->blur_radius
< 1.0)
181 gegl_buffer_copy (input
, result
, GEGL_ABYSS_NONE
,
186 bilateral_filter (input
, &compute
, output
, result
, o
->blur_radius
, o
->edge_preservation
, format
);
193 bilateral_filter (GeglBuffer
*src
,
194 const GeglRectangle
*src_rect
,
196 const GeglRectangle
*dst_rect
,
206 gint width
= (gint
) radius
* 2 + 1;
207 gint iradius
= radius
;
208 gint src_width
= src_rect
->width
;
209 gint src_height
= src_rect
->height
;
211 gauss
= g_newa (gfloat
, width
* width
);
212 src_buf
= g_new0 (gfloat
, src_rect
->width
* src_rect
->height
* 4);
213 dst_buf
= g_new0 (gfloat
, dst_rect
->width
* dst_rect
->height
* 4);
215 gegl_buffer_get (src
, src_rect
, 1.0, format
, src_buf
, GEGL_AUTO_ROWSTRIDE
,
220 #define POW2(a) ((a)*(a))
221 for (y
=-iradius
;y
<=iradius
;y
++)
222 for (x
=-iradius
;x
<=iradius
;x
++)
224 gauss
[x
+(int)radius
+ (y
+(int)radius
)*width
] = exp(- 0.5*(POW2(x
)+POW2(y
))/radius
);
227 for (y
=0; y
<dst_rect
->height
; y
++)
228 for (x
=0; x
<dst_rect
->width
; x
++)
231 gfloat
*center_pix
= src_buf
+ ((x
+iradius
)+((y
+iradius
) * src_width
)) * 4;
232 gfloat accumulated
[4]={0,0,0,0};
235 for (v
=-iradius
;v
<=iradius
;v
++)
236 for (u
=-iradius
;u
<=iradius
;u
++)
241 if (i
>= 0 && i
< src_width
&&
242 j
>= 0 && j
< src_height
)
246 gfloat
*src_pix
= src_buf
+ (i
+ j
* src_width
) * 4;
248 gfloat diff_map
= exp (- (POW2(center_pix
[0] - src_pix
[0])+
249 POW2(center_pix
[1] - src_pix
[1])+
250 POW2(center_pix
[2] - src_pix
[2])) * preserve
252 gfloat gaussian_weight
;
255 gaussian_weight
= gauss
[u
+(int)radius
+(v
+(int)radius
)*width
];
257 weight
= diff_map
* gaussian_weight
;
261 accumulated
[c
] += src_pix
[c
] * weight
;
268 dst_buf
[offset
*4+u
] = accumulated
[u
]/count
;
271 gegl_buffer_set (dst
, dst_rect
, 0, format
, dst_buf
,
272 GEGL_AUTO_ROWSTRIDE
);
279 gegl_op_class_init (GeglOpClass
*klass
)
281 GeglOperationClass
*operation_class
;
282 GeglOperationFilterClass
*filter_class
;
284 operation_class
= GEGL_OPERATION_CLASS (klass
);
285 filter_class
= GEGL_OPERATION_FILTER_CLASS (klass
);
287 filter_class
->process
= process
;
288 operation_class
->prepare
= prepare
;
290 operation_class
->opencl_support
= TRUE
;
292 gegl_operation_class_set_keys (operation_class
,
293 "name", "gegl:bilateral-filter",
294 "title", _("Bilateral Filter"),
295 "categories", "enhance:noise-reduction",
296 "reference-hash", "e19155c5d467143d11f259cc25fdec80",
298 _("Like a gaussian blur; but where the contribution for each neighborhood "
299 "pixel is also weighted by the color difference with the original center pixel."),