4 Pixel filters for 'GP_Context'.
6 The context filter is basically a function that operates on context pixels.
7 The result may be stored into a new bitmap or placed to bitmap passed as
8 argument or, in some cases, the filter could be used 'in place' so the result
9 is stored into the same context as the one passed as filter source.
14 For convenience, the filters API is unified:
16 * There are two functions for each filter
17 - first one takes destination as an argument
18 - second one allocates the destination and returns pointer to it
19 * First argument(s) are always source(s)
20 * Then, in case of second variant, destination
21 * Other parameters follow
22 * And the last argument is link:progress_callback.html[progress callback]
24 When using allocating version of the filter, pointer to the newly allocated
25 context is returned, or in case of failure 'NULL' is returned.
27 If 'malloc()' has failed 'NULL' is returned.
29 If filter has been interrupted by a callback, all allocated memory is freed,
30 and 'NULL' is returned.
32 When using non-allocating variant of the filter, the destination context must
33 have correct pixel type and the size must be big enough to store the result.
34 The return value from such filter is either zero, in case of success, or
35 non-zero when filter was interrupted by a callback.
37 For filters that work 'in-place' (which is explicitly said for each filter)
38 the source and the destination could be the same context. Note that this is
39 not expected to work if you do several overlapping sub-contexts and pass these
43 -------------------------------------------------------------------------------
47 int GP_FilterFoo(const GP_Context *src, GP_Context *dst,
49 GP_ProgressCallback *callback);
51 GP_Context *GP_FilterFooAlloc(const GP_Context *src,
53 GP_ProgressCallback *callback);
54 -------------------------------------------------------------------------------
57 Filters also exists in _Raw variant whose interface is similar to the first
58 type of filter function. These filter APIs are used for internal
59 implementation and shouldn't be called by user as the destination is expected
60 to be crafted exactly for storing the filter result and there are 'NO' sanity
63 'You could use these at your own risk'
66 -------------------------------------------------------------------------------
68 * Raw filter common API.
70 int GP_FilterFoo_Raw(const GP_Context *src, GP_Context *dst,
72 GP_ProgressCallback *callback);
73 -------------------------------------------------------------------------------
78 In order to pass, per-channel, filter parameters to a filter, structure called
79 GP_FilterParams was created.
82 -------------------------------------------------------------------------------
85 #include <filters/GP_FilterParam.h>
87 typedef union GP_FilterParamVal {
94 typedef struct GP_FilterParam {
96 union GP_FilterParamVal val;
98 -------------------------------------------------------------------------------
100 Some filters do take an empty channel_name terminated (empty channel_name is
101 empty string i.e. "\0") array of GP_FilterParam, which is used to describe
102 per-channel parameters.
105 There are two methods how to construct GP_FilterParam structure. First one is
106 to use macro that expands to a code which declares and initializes the array on
107 the stack second uses memory allocated by a malloc(). In both cases the
108 structure is has initialized channel names and terminator.
111 -------------------------------------------------------------------------------
114 #include <filters/GP_FilterParam.h>
116 #define GP_FILTER_PARAMS(pixel_type, name) \
117 GP_FilterParam name[GP_PixelTypes[pixel_type].numchannels + 1]; \
118 GP_FilterParamInitChannels(name, pixel_type);
119 -------------------------------------------------------------------------------
121 Macro that declares and initializes GP_FilterParam structure for a given
125 -------------------------------------------------------------------------------
128 #include <filters/GP_FilterParam.h>
130 GP_FilterParam *GP_FilterParamCreate(GP_PixelType pixel_type);
132 void GP_FilterParamDestroy(GP_FilterParam *self);
133 -------------------------------------------------------------------------------
135 Second possible way allocates memory using malloc().
137 Functions for manipulating and querying existing GP_FilterParam follows.
140 -------------------------------------------------------------------------------
143 #include <filters/GP_FilterParam.h>
145 void GP_FilterParamInitChannels(GP_FilterParam params[],
146 GP_PixelType pixel_type);
147 -------------------------------------------------------------------------------
149 Initializes filter param array channel names (accordingly to pixel type) and
150 terminator. The params array must be large enough to hold number of pixel type
154 -------------------------------------------------------------------------------
157 #include <filters/GP_FilterParam.h>
159 GP_FilterParam *GP_FilterParamChannel(GP_FilterParam params[],
160 const char *channel_name);
161 -------------------------------------------------------------------------------
163 Does lookup for a given channel name and returns, if found, corresponding
164 GP_FilterParam, otherwise 'NULL' is returned.
166 This function is primary used in filters, where filter, at the start, resolves
170 -------------------------------------------------------------------------------
173 #include <filters/GP_FilterParam.h>
175 int GP_FilterParamCheckPixelType(GP_FilterParam params[],
176 GP_PixelType pixel_type);
177 -------------------------------------------------------------------------------
179 Matches param structure against pixel_type. Returns zero if params describes
180 exactly same channels like pixel_type, non-zero otherwise.
183 -------------------------------------------------------------------------------
186 #include <filters/GP_FilterParam.h>
188 void GP_FilterParamSetIntAll(GP_FilterParam params[], int32_t val);
190 int GP_FilterParamSetInt(GP_FilterParam params[], const char *channel_name,
193 void GP_FilterParamSetFloatAll(GP_FilterParam params[], float val);
195 int GP_FilterParamSetFloat(GP_FilterParam params[], const char *channel_name,
198 void GP_FilterParamSetUIntAll(GP_FilterParam params[], uint32_t val);
200 int GP_FilterParamSetUInt(GP_FilterParam params[], const char *channel_name,
203 void GP_FilterParamSetPtrAll(GP_FilterParam params[], void *ptr);
205 int GP_FilterParamSetPtr(GP_FilterParam params[], const char *channel_name,
208 void GP_FilterParamFreePtrAll(GP_FilterParam params[]);
209 -------------------------------------------------------------------------------
211 Parameter setters. Those that sets individual value returns zero on success
212 (i.e. channel was found) and non-zero otherwise.
214 The last one calls free() on all param pointers, which is used to free
217 Point operation filters
218 ~~~~~~~~~~~~~~~~~~~~~~~
220 Point operations are filters that works with pixels as with independent values
221 (the value of destination pixel depends only on the pixel on the same
222 coordinates in source image). All of these filters works 'in-place' and the
223 result has always the same size as the source.
226 -------------------------------------------------------------------------------
227 #include <GP_Filters.h>
229 GP_Context *GP_FilterBrightness(const GP_Context *src, GP_Context *dst,
230 int32_t inc, GP_ProgressCallback *callback);
231 -------------------------------------------------------------------------------
233 Brightness filter, increments all pixel channels by a fixed value.
236 -------------------------------------------------------------------------------
237 #include <GP_Filters.h>
239 GP_Context *GP_FilterContrast(const GP_Context *src, GP_Context *dst,
240 float mul, GP_ProgressCallback *callback);
241 -------------------------------------------------------------------------------
243 Contrast filter, multiplies all pixel channels by a fixed value.
246 -------------------------------------------------------------------------------
247 #include <GP_Filters.h>
249 GP_Context *GP_FilterInvert(const GP_Context *src, GP_Context *dst,
250 GP_ProgressCallback *callback);
251 -------------------------------------------------------------------------------
253 Inverts the image, for each channel the result value is computed as "chan_max
256 include::filter_additive_gaussian_noise.txt[]
261 Arithmetic filters do take two contexts as an input and combines them into one
264 The pixel type of both input contexts must match.
266 If size of the input contexts differs, minimum is used.
269 -------------------------------------------------------------------------------
270 #include <filters/GP_Arithmetic.h>
274 int GP_FilterAddition(const GP_Context *src_a,
275 const GP_Context *src_b,
277 GP_ProgressCallback *callback);
279 GP_Context *GP_FilterAdditionAlloc(const GP_Context *src_a,
280 const GP_Context *src_b,
281 GP_ProgressCallback *callback);
282 -------------------------------------------------------------------------------
284 Produces saturated (clamped) addition of two contexts.
287 -------------------------------------------------------------------------------
288 #include <filters/GP_Arithmetic.h>
292 int GP_FilterMultiply(const GP_Context *src_a,
293 const GP_Context *src_b,
295 GP_ProgressCallback *callback);
297 GP_Context *GP_FilterMultiplyAlloc(const GP_Context *src_a,
298 const GP_Context *src_b,
299 GP_ProgressCallback *callback);
300 -------------------------------------------------------------------------------
302 Produces saturated (clamped) multiplication of two contexts.
305 -------------------------------------------------------------------------------
306 #include <filters/GP_Arigthmetic.h>
310 int GP_FilterDifference(const GP_Context *src_a,
311 const GP_Context *src_b,
313 GP_ProgressCallback *callback);
315 GP_Context *GP_FilterDifferenceAlloc(const GP_Context *src_a,
316 const GP_Context *src_b,
317 GP_ProgressCallback *callback);
319 -------------------------------------------------------------------------------
321 Produces symmetric difference (i.e. abs(a - b)).
324 -------------------------------------------------------------------------------
325 #include <filters/GP_Arigthmetic.h>
329 int GP_FilterMax(const GP_Context *src_a,
330 const GP_Context *src_b,
332 GP_ProgressCallback *callback);
334 GP_Context *GP_FilterMaxAlloc(const GP_Context *src_a,
335 const GP_Context *src_b,
336 GP_ProgressCallback *callback);
338 int GP_FilterMin(const GP_Context *src_a,
339 const GP_Context *src_b,
341 GP_ProgressCallback *callback);
343 GP_Context *GP_FilterMinAlloc(const GP_Context *src_a,
344 const GP_Context *src_b,
345 GP_ProgressCallback *callback);
346 -------------------------------------------------------------------------------
348 Maximum and minimum filter.
350 Rotation and Symmetry filters
351 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
354 -------------------------------------------------------------------------------
355 #include <filters/GP_Rotate.h>
359 int GP_FilterMirrorH(const GP_Context *src, GP_Context *dst,
360 GP_ProgressCallback *callback);
362 GP_Context *GP_FilterMirrorHAlloc(const GP_Context *src,
363 GP_ProgressCallback *callback);
364 -------------------------------------------------------------------------------
366 Mirrors context horizontally.
370 The destination has to have the same pixel type and the size must be at least
374 -------------------------------------------------------------------------------
375 #include <filters/GP_Rotate.h>
379 int GP_FilterMirrorV(const GP_Context *src, GP_Context *dst,
380 GP_ProgressCallback *callback);
382 GP_Context *GP_FilterMirrorVAlloc(const GP_Context *src,
383 GP_ProgressCallback *callback);
384 -------------------------------------------------------------------------------
386 Mirrors context vertically.
390 The destination has to have the same pixel type and the size must be at least
394 -------------------------------------------------------------------------------
395 #include <filters/GP_Rotate.h>
399 int GP_FilterRotate90(const GP_Context *src, GP_Context *dst,
400 GP_ProgressCallback *callback);
402 GP_Context *GP_FilterRotate90Alloc(const GP_Context *src,
403 GP_ProgressCallback *callback);
404 -------------------------------------------------------------------------------
406 Rotate context by 90 degrees.
408 Doesn't work 'in-place' (yet).
410 The destination has to have the same pixel type and size must be large enough to
411 fit rotated context (i.e. W and H are swapped).
414 -------------------------------------------------------------------------------
415 #include <filters/GP_Rotate.h>
419 int GP_FilterRotate180(const GP_Context *src, GP_Context *dst,
420 GP_ProgressCallback *callback);
422 GP_Context *GP_FilterRotate180Alloc(const GP_Context *src,
423 GP_ProgressCallback *callback);
424 -------------------------------------------------------------------------------
426 Rotate context by 180 degrees.
428 Doesn't work 'in-place' (yet).
430 The destination has to have the same pixel type and the size must be at least
434 -------------------------------------------------------------------------------
435 #include <filters/GP_Rotate.h>
439 int GP_FilterRotate270(const GP_Context *src, GP_Context *dst,
440 GP_ProgressCallback *callback);
442 GP_Context *GP_FilterRotate270Alloc(const GP_Context *src,
443 GP_ProgressCallback *callback);
444 -------------------------------------------------------------------------------
446 Rotate context by 270 degrees.
448 Doesn't work 'in-place' (yet).
450 The destination has to have the same pixel type and destination size must be
451 large enough to fit rotated context (i.e. W and H are swapped).
454 -------------------------------------------------------------------------------
455 #include <filters/GP_Rotate.h>
459 typedef enum GP_FilterSymmetries {
461 GP_ROTATE_CW = GP_ROTATE_90,
464 GP_ROTATE_CCW = GP_ROTATE_270,
467 } GP_FilterSymmetries;
469 GP_Context *GP_FilterSymmetry(const GP_Context *src,
470 GP_FilterSymmetries symmetry,
471 GP_ProgressCallback *callback);
473 int GP_FilterSymmetry(const GP_Context *src, GP_Context *dst,
474 GP_FilterSymmetries symmetry,
475 GP_ProgressCallback *callback);
476 -------------------------------------------------------------------------------
478 Catch all function for symmetry filters.
484 Linear filters family consists of filters based on discrete linear
485 convolution, that means that computed pixel value depends on linear
486 combination of the image pixels.
489 [latex, discrete_linear_convolution.png, 140]
490 -------------------------------------------------------------------------------
492 O(x,y)=\sum_{i=-\infty}^{\infty}\sum_{j=-\infty}^{\infty}I(x+i,y+j) \cdot K(i,j)
494 -------------------------------------------------------------------------------
496 The K denotes convolution kernel and in practice, due to computational
497 complexity i and j are bounded in relatively small intervals. For example i
498 and j are in (-1,1) and the kernel size is 3x3.
500 Note that pixel values outside the image are undefined. The linear convolution
501 in GFXprim simply uses the closest border pixel values for all pixels outside
504 Particular convolution kernel is called separable if it could be decomposed
505 into two one dimensional kernels (these when combined yields back the original
506 kernel). Such convolution then could be applied as two one dimensional
507 convolutions which is faster operation (especially for big kernels).
509 Generic Linear Convolution
510 ^^^^^^^^^^^^^^^^^^^^^^^^^^
512 Following paragraph describes linear convolution implementation as well as a
513 little of the math background skip it if you just need to use one of the
514 ready-to-use filters.
517 -------------------------------------------------------------------------------
518 #include <filters/GP_Linear.h>
522 int GP_FilterLinearConvolution_Raw(const GP_Context *src,
523 GP_Coord x_src, GP_Coord y_src,
524 GP_Size w_src, GP_Size h_src,
526 GP_Coord x_dst, GP_Coord y_dst,
527 float kernel[], uint32_t kw, uint32_t kh,
528 float kern_div, GP_ProgressCallback *callback);
529 -------------------------------------------------------------------------------
531 Internal generic convolution filter, this is a base for all linear convolution
532 filters with non-separable kernel.
534 The src coordinate and sizes denotes rectangle in the source context that the
537 The dst coordinates defines offset into the dst context.
539 The kernel is two-dimensional array of a size kw * kh indexed as
542 The kern_div is a coefficient that is used to divide the resulting values often
543 used to normalize the result.
545 This filter works 'in-place'.
547 The pixel value is computed as:
548 [latex, discrete_linear_convolution_alg1.png, 140]
549 -------------------------------------------------------------------------------
551 O(x,y)={1 \over kern\_div} \cdot \sum_{i=0}^{kw - 1}\sum_{j=0}^{kh - 1}
552 I(x + i - \lfloor kw/2 \rfloor, y + j - \lfloor kh/2 \rfloor)
555 -------------------------------------------------------------------------------
557 Which is the same as:
559 [latex, discrete_linear_convolution_alg2.png, 140]
560 -------------------------------------------------------------------------------
562 O(x,y)={1 \over kern\_div} \cdot
563 \sum_{i=-\lfloor kw/2 \rfloor}^{\lfloor kw/2 \rfloor}
564 \sum_{j=-\lfloor kh/2 \rfloor}^{\lfloor kh/2 \rfloor}
566 \cdot kernel(i + \lfloor kw/2 \rfloor, j + \lfloor kh/2 \rfloor)
568 -------------------------------------------------------------------------------
570 NOTE: The number of kernel rows and columns is expected to be odd number.
573 -------------------------------------------------------------------------------
574 #include <filters/GP_Linear.h>
578 int GP_FilterHLinearConvolution_Raw(const GP_Context *src,
579 GP_Coord x_src, GP_Coord y_src,
580 GP_Size w_src, GP_Size h_src,
582 GP_Coord x_dst, GP_Coord y_dst,
583 float kernel[], uint32_t kw, float kern_div,
584 GP_ProgressCallback *callback);
586 int GP_FilterVLinearConvolution_Raw(const GP_Context *src,
587 GP_Coord x_src, GP_Coord y_src,
588 GP_Size w_src, GP_Size h_src,
590 GP_Coord x_dst, GP_Coord y_dst,
591 float kernel[], uint32_t kh, float kern_div,
592 GP_ProgressCallback *callback);
594 int GP_FilterVHLinearConvolution_Raw(const GP_Context *src,
595 GP_Coord x_src, GP_Coord y_src,
596 GP_Size w_src, GP_Size h_src,
598 GP_Coord x_dst, GP_Coord y_dst,
599 float hkernel[], uint32_t kw, float hkern_div,
600 float vkernel[], uint32_t kh, float vkern_div,
601 GP_ProgressCallback *callback);
603 void GP_FilterKernelPrint_Raw(float kernel[], int kw, int kh, float kern_div);
604 -------------------------------------------------------------------------------
606 Internal special functions for one dimensional vertical and horizontal
607 convolution these two functions are base for all separable convolution filters.
609 The src coordinate and sizes denotes rectangle in the source context that the
612 The dst coordinates are offset into the dst.
614 The kernel is one-dimensional array of floats of size kw or kh.
616 The kern_div is a coefficient that is used to divide the resulting values.
618 The last function does both vertical and horizontal convolution and takes care
619 of correct progress callback.
621 These filters work 'in-place'.
623 The pixel value is computed as:
624 [latex, discrete_linear_1D_convolution_alg1.png, 140]
625 -------------------------------------------------------------------------------
627 O(x,y)={1 \over kern\_div} \cdot \sum_{i=0}^{kw - 1}
628 I(x + i - \lfloor kw/2 \rfloor, y)
633 O(x,y)={1 \over kern\_div} \cdot \sum_{j=0}^{kw - 1}
634 I(x, y + j - \lfloor kh/2 \rfloor)
637 -------------------------------------------------------------------------------
639 Which is the same as:
641 [latex, discrete_linear_1D_convolution_alg2.png, 140]
642 -------------------------------------------------------------------------------
644 O(x,y)={1 \over kern\_div} \cdot
645 \sum_{i=-\lfloor kw/2 \rfloor}^{\lfloor kw/2 \rfloor}
647 \cdot kernel(i + \lfloor kw/2 \rfloor)
651 O(x,y)={1 \over kern\_div} \cdot
652 \sum_{j=-\lfloor kh/2 \rfloor}^{\lfloor kh/2 \rfloor}
654 \cdot kernel(i, j + \lfloor kh/2 \rfloor)
656 -------------------------------------------------------------------------------
658 NOTE: The number of kernel rows and columns is expected to be odd number.
660 NOTE: The linear convolutions are internally implemented using integer
661 arithmetics, which works fine, but you need to take a care not to
662 overflow 32bit signed integer. If the pixel channel size is 8bit
663 long and 10bits are used for the fixed point part of the number
664 the rest must fit into about 10 bits to be safe.
667 -------------------------------------------------------------------------------
668 #include <filters/GP_Convolution.h>
672 typedef struct GP_FilterKernel2D {
679 int GP_FilterConvolutionEx(const GP_Context *src,
680 GP_Coord x_src, GP_Coord y_src,
681 GP_Size w_src, GP_Coord h_src,
683 GP_Coord x_dst, GP_Coord y_dst,
684 const GP_FilterKernel2D *kernel,
685 GP_ProgressCallback *callback);
687 GP_Context *GP_FilterConvolutionExAlloc(const GP_Context *src,
688 GP_Coord x_src, GP_Coord y_src,
689 GP_Size w_src, GP_Size h_src,
690 const GP_FilterKernel2D *kernel,
691 GP_ProgressCallback *callback);
693 int GP_FilterConvolution(const GP_Context *src, GP_Context *dst,
694 const GP_FilterKernel2D *kernel,
695 GP_ProgressCallback *callback);
697 GP_Context *GP_FilterConvolutionAlloc(const GP_Context *src,
698 const GP_FilterKernel2D *kernel,
699 GP_ProgressCallback *callback);
701 void GP_FilterKernel2DPrint(const GP_FilterKernel2D *kernel);
702 -------------------------------------------------------------------------------
704 Linear convolution filters, you should preferably use this API over the _Raw
707 The Ex variants takes a rectangle on which the filter should operate as well
708 as offset into the destination. The destination must be large enough so that
709 starting with offset there is at least w_dst and h_dst pixels.
711 The kernel is a pointer to a structure initialized with the kernel size, divider
712 and array of kernel values.
714 The last function prints convolution kernel in human-readable format into the
717 WARNING: If filter is executed in-place the work cannot be distributed between
718 threads (as some of the threads will overwrite values read by other
719 threads). In this case convolution filters runs in one thread
720 regardless of if threads are eanbled or not.
723 -------------------------------------------------------------------------------
727 * Example box smoothing filter.
729 static void box_smoothing(GP_Context *img)
731 float box_filter[] = {
737 GP_FilterKernel2D box_kernel = {
741 .kernel = box_filter,
744 GP_FilterConvolution(img, img, &box_kernel, NULL);
746 -------------------------------------------------------------------------------
748 Example function that implements simple 'in-place' smoothing filter.
754 -------------------------------------------------------------------------------
755 #include <GP_Filters.h>
759 int GP_FilterLaplace(const GP_Context *src, GP_Context *dst,
760 GP_ProgressCallback *callback);
762 GP_Context *GP_FilterLaplaceAlloc(const GP_Context *src,
763 GP_ProgressCallback *callback);
764 -------------------------------------------------------------------------------
766 Discrete Laplace filter that produces a second derivative of the original
769 The convolution kernel is defined as:
771 [latex, laplacian_kernel.png, 130]
772 -------------------------------------------------------------------------------
792 -------------------------------------------------------------------------------
794 NOTE: This filter is not separable but could be written as a sum of two one
795 dimensional filters as the kernel definition suggests.
797 Laplacian Edge Sharpening
798 ^^^^^^^^^^^^^^^^^^^^^^^^^
801 -------------------------------------------------------------------------------
802 #include <GP_Filters.h>
806 int GP_FilterEdgeSharpening(const GP_Context *src, GP_Context *dst,
807 float w, GP_ProgressCallback *callback);
809 GP_Context *GP_FilterEdgeSharpeningAlloc(const GP_Context *src, float w,
810 GP_ProgressCallback *callback);
811 -------------------------------------------------------------------------------
813 Laplace based edge sharpening filter, subtracts weighted second derivative
814 from the original image.
816 [latex, laplacian_edge_sharpening.png, 140]
817 -------------------------------------------------------------------------------
819 O(x,y) = I(x,y) - w * I''(x,y)
821 -------------------------------------------------------------------------------
823 .Original Image; Edge Sharpening w=0.1, w=0.3, w=0.5
824 image:images/dither/lenna_small.png[
826 link="images/dither/lenna.png"]
827 image:images/edge_sharpening/lenna_small_w_0_1.png[
828 "Edge Sharpening w=0.1",
829 link="images/edge_sharpening/lenna_w_0_1.png"]
830 image:images/edge_sharpening/lenna_small_w_0_3.png[
831 "Edge Sharpening w=0.5",
832 link="images/edge_sharpening/lenna_w_0_3.png"]
833 image:images/edge_sharpening/lenna_small_w_0_5.png[
834 "Edge Sharpening w=0.5",
835 link="images/edge_sharpening/lenna_w_0_5.png"]
841 -------------------------------------------------------------------------------
842 #include <filters/GP_Blur.h>
846 int GP_FilterGaussianBlurEx(const GP_Context *src,
847 GP_Coord x_src, GP_Coord y_src,
848 GP_Size w_src, GP_Size h_src,
850 GP_Coord x_dst, GP_Coord y_dst,
851 float x_sigma, float y_sigma,
852 GP_ProgressCallback *callback);
854 GP_Context *GP_FilterGaussianBlurExAlloc(const GP_Context *src,
855 GP_Coord x_src, GP_Coord y_src,
856 GP_Size w_src, GP_Size h_src,
857 float x_sigma, float y_sigma,
858 GP_ProgressCallback *callback);
860 int GP_FilterGaussianBlur(const GP_Context *src, GP_Context *dst,
861 float x_sigma, float y_sigma,
862 GP_ProgressCallback *callback)
864 GP_Context *GP_FilterGaussianBlurAlloc(const GP_Context *src,
865 float x_sigma, float y_sigma,
866 GP_ProgressCallback *callback)
867 -------------------------------------------------------------------------------
869 Gaussian blur (low pass) filters implemented as bilinear separable
872 The sigma denotes amount of the blur (the radius is computed accordingly
875 The sigma values can be set for vertical and horizontal direction
876 independently which may be useful when Gaussian blur is used as a low pass
877 filter before image is resampled non proportionally.
879 Interpolation filters
880 ~~~~~~~~~~~~~~~~~~~~~
882 Filters to link:filters_resize.html[resize image].
884 Nearest Neighbour Interpolation
885 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
887 Fast, but produces "pixelated" images. May however work better for images with
888 sharp edges mostly consisting of big one color regions (it doesn't blur the
889 result on upscaling).
891 Also is commonly used to show preview before you resample the image correctly.
893 Bilinear Interpolation
894 ^^^^^^^^^^^^^^^^^^^^^^
896 Bilinear is faster than bicubic interpolation and produces quite good results
897 especially the low pass variant doesn't need additional filter on down-sampling.
899 Bicubic Interpolation
900 ^^^^^^^^^^^^^^^^^^^^^
902 Works well as is on image upscaling. To get decent result on downscaling
903 low-pass filter (Gaussian blur) must be used on original image before actual
904 downscaling. To do this reasonably fast we could cheat a little: first resize
905 big images a little without the low-pass filter, then apply low-pass filter and
906 finally downscale it to desired size.
912 link:filters_dithering.html[Dithering filters] are filters for better loosy
913 (source pixel type has more bits to represent color or grayscale value) pixel
920 -------------------------------------------------------------------------------
921 #include <filters/GP_Median.h>
925 int GP_FilterMedianEx(const GP_Context *src,
926 GP_Coord x_src, GP_Coord y_src,
927 GP_Size w_src, GP_Size h_src,
929 GP_Coord x_dst, GP_Coord y_dst,
931 GP_ProgressCallback *callback);
933 GP_Context *GP_FilterMedianExAlloc(const GP_Context *src,
934 GP_Coord x_src, GP_Coord y_src,
935 GP_Size w_src, GP_Size h_src,
937 GP_ProgressCallback *callback);
939 int GP_FilterMedian(const GP_Context *src,
942 GP_ProgressCallback *callback);
944 GP_Context *GP_FilterMedianAlloc(const GP_Context *src,
946 GP_ProgressCallback *callback);
947 -------------------------------------------------------------------------------
949 Constant time median filters (the computational complexity is independent of
952 The xmed and ymed are radius values for x and y. The algorithm uses xmed
953 respectively ymed pixel neighbors from each side so the result is median of
954 rectangle of 2 * xmed + 1 x 2 * ymed + 1 pixels.
956 .Original Image; Median 3x3, 5x5, 7x7, 9x9
957 image:images/dither/lenna_small.png[
959 link="images/dither/lenna.png"]
960 image:images/median/lenna_small_med_3_3.png[
962 link="images/median/lenna_med_3_3.png"]
963 image:images/median/lenna_small_med_5_5.png[
965 link="images/median/lenna_med_5_5.png"]
966 image:images/median/lenna_small_med_7_7.png[
968 link="images/median/lenna_med_7_7.png"]
969 image:images/median/lenna_small_med_9_9.png[
971 link="images/median/lenna_med_9_9.png"]