doc: filters_python: Add rotation and symmetry filters.
[gfxprim/pasky.git] / doc / filters.txt
blob93a28886eb9bd3680fe971dd2d723f1c0406db77
1 Context filters
2 ---------------
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.
11 Common filter API
12 ~~~~~~~~~~~~~~~~~
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
40 as arguments.
42 [source,c]
43 -------------------------------------------------------------------------------
45  * Filter common API.
46  */
47 int GP_FilterFoo(const GP_Context *src, GP_Context *dst,
48                  foo params ...,
49                  GP_ProgressCallback *callback);
51 GP_Context *GP_FilterFooAlloc(const GP_Context *src,
52                               foo params ...,
53                               GP_ProgressCallback *callback);
54 -------------------------------------------------------------------------------
57 Point Filters
58 ~~~~~~~~~~~~~
60 Point operations are filters that works with pixels as with independent values
61 (the value of destination pixel depends only on the pixel on the same
62 coordinates in source image). All of these filters works 'in-place' and the
63 result has always the same size as the source.
65 Invert
66 ^^^^^^
68 [source,c]
69 -------------------------------------------------------------------------------
70 #include <GP.h>
71 /* or */
72 #include <filters/GP_Point.h>
74 int GP_FilterInvert(const GP_Context *src, GP_Context *dst,
75                     GP_ProgressCallback *callback);
77 GP_Context *GP_FilterInvertAlloc(const GP_Context *src,
78                                  GP_ProgressCallback *callback);
79 -------------------------------------------------------------------------------
81 The pixel channel values are counted as +chann_max - val+.
83 include::images/invert/images.txt[]
85 Brightness
86 ^^^^^^^^^^
88 [source,c]
89 -------------------------------------------------------------------------------
90 #include <GP.h>
91 /* or */
92 #include <filters/GP_Point.h>
94 int GP_FilterBrightness(const GP_Context *src, GP_Context *dst,
95                         float p, GP_ProgressCallback *callback);
97 GP_Context *GP_FilterBrightnessAlloc(const GP_Context *src, float p,
98                                      GP_ProgressCallback *callback);
99 -------------------------------------------------------------------------------
101 The pixel channel values are counted as +val + chann_max * p+.
103 include::images/brightness/images.txt[]
105 Contrast
106 ^^^^^^^^
108 [source,c]
109 -------------------------------------------------------------------------------
110 #include <GP.h>
111 /* or */
112 #include <filters/GP_Point.h>
114 int GP_FilterContrast(const GP_Context *src, GP_Context *dst,
115                       float p, GP_ProgressCallback *callback);
117 GP_Context *GP_FilterContrastAlloc(const GP_Context *src, float p,
118                                    GP_ProgressCallback *callback);
119 -------------------------------------------------------------------------------
121 The pixel channel values are counted as +val * p+.
123 include::images/contrast/images.txt[]
125 BrightnessContrast
126 ^^^^^^^^^^^^^^^^^^
128 [source,c]
129 -------------------------------------------------------------------------------
130 #include <GP.h>
131 /* or */
132 #include <filters/GP_Point.h>
134 int GP_FilterBrightnessContrast(const GP_Context *src, GP_Context *dst,
135                                 float b, float c,
136                                 GP_ProgressCallback *callback);
138 GP_Context *GP_FilterBrightnessContrastAlloc(const GP_Context *src,
139                                              float b, float c,
140                                              GP_ProgressCallback *callback);
141 -------------------------------------------------------------------------------
143 The pixel channel values are counted as +val * c + chann_max * b+.
145 include::images/brightness_contrast/images.txt[]
147 Posterize
148 ^^^^^^^^^
150 [source,c]
151 -------------------------------------------------------------------------------
152 #include <GP.h>
153 /* or */
154 #include <filters/GP_Point.h>
156 int GP_FilterPosterize(const GP_Context *src, GP_Context *dst,
157                        unsigned int levels, GP_ProgressCallback *callback);
159 GP_Context *GP_FilterPosterizeAlloc(const GP_Context *src, unsigned int levels,
160                                     GP_ProgressCallback *callback);
161 -------------------------------------------------------------------------------
163 The pixel channel values are quantized into number of levels.
165 include::images/posterize/images.txt[]
168 Gaussian additive noise filter
169 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
171 [source,c]
172 -------------------------------------------------------------------------------
173 #include <GP_Filters.h>
174 /* or */
175 #include <filters/GP_GaussianNoise.h>
177 int GP_FilterGaussianNoiseAddEx(const GP_Context *src,
178                                 GP_Coord x_src, GP_Coord y_src,
179                                 GP_Size w_src, GP_Size h_src,
180                                 GP_Context *dst,
181                                 GP_Coord x_dst, GP_Coord y_dst,
182                                 float sigma, float mu,
183                                 GP_ProgressCallback *callback);
185 GP_Context *GP_FilterGaussianNoiseAddExAlloc(const GP_Context *src,
186                                              GP_Coord x_src, GP_Coord y_src,
187                                              GP_Size w_src, GP_Size h_src,
188                                              float sigma, float mu,
189                                              GP_ProgressCallback *callback);
191 static inline int GP_FilterGaussianNoiseAdd(const GP_Context *src,
192                                             GP_Context *dst,
193                                             float sigma, float mu,
194                                             GP_ProgressCallback *callback);
196 static inline GP_Context *
197 GP_FilterGaussianNoiseAddAlloc(const GP_Context *src,
198                                float sigma, float mu,
199                                GP_ProgressCallback *callback);
200 -------------------------------------------------------------------------------
202 Gaussian additive noise filter adds gaussian distributed noise to an image
203 with a defined sigma and mu. Both sigma and mu weights mapped to [0,1]
204 interval.
206 TIP: See the link:example_gaussian_noise.html[gaussian noise example].
208 include::images/gaussian_noise/images.txt[]
210 Arithmetic filters
211 ~~~~~~~~~~~~~~~~~~
213 Arithmetic filters do take two contexts as an input and combines them into one
214 output context.
216 The pixel type of both input contexts must match.
218 If size of the input contexts differs, minimum is used.
220 [source,c]
221 -------------------------------------------------------------------------------
222 #include <filters/GP_Arithmetic.h>
223 /* or */
224 #include <GP.h>
226 int GP_FilterAddition(const GP_Context *src_a,
227                       const GP_Context *src_b,
228                       GP_Context *dst,
229                       GP_ProgressCallback *callback);
231 GP_Context *GP_FilterAdditionAlloc(const GP_Context *src_a,
232                                    const GP_Context *src_b,
233                                    GP_ProgressCallback *callback);
234 -------------------------------------------------------------------------------
236 Produces saturated (clamped) addition of two contexts.
238 [source,c]
239 -------------------------------------------------------------------------------
240 #include <filters/GP_Arithmetic.h>
241 /* or */
242 #include <GP.h>
244 int GP_FilterMultiply(const GP_Context *src_a,
245                       const GP_Context *src_b,
246                       GP_Context *dst,
247                       GP_ProgressCallback *callback);
249 GP_Context *GP_FilterMultiplyAlloc(const GP_Context *src_a,
250                                    const GP_Context *src_b,
251                                    GP_ProgressCallback *callback);
252 -------------------------------------------------------------------------------
254 Produces saturated (clamped) multiplication of two contexts.
256 [source,c]
257 -------------------------------------------------------------------------------
258 #include <filters/GP_Arigthmetic.h>
259 /* or */
260 #include <GP.h>
262 int GP_FilterDifference(const GP_Context *src_a,
263                         const GP_Context *src_b,
264                         GP_Context *dst,
265                         GP_ProgressCallback *callback);
267 GP_Context *GP_FilterDifferenceAlloc(const GP_Context *src_a,
268                                      const GP_Context *src_b,
269                                      GP_ProgressCallback *callback);
271 -------------------------------------------------------------------------------
273 Produces symmetric difference (i.e. abs(a - b)).
275 [source,c]
276 -------------------------------------------------------------------------------
277 #include <filters/GP_Arigthmetic.h>
278 /* or */
279 #include <GP.h>
281 int GP_FilterMax(const GP_Context *src_a,
282                  const GP_Context *src_b,
283                  GP_Context *dst,
284                  GP_ProgressCallback *callback);
286 GP_Context *GP_FilterMaxAlloc(const GP_Context *src_a,
287                               const GP_Context *src_b,
288                               GP_ProgressCallback *callback);
290 int GP_FilterMin(const GP_Context *src_a,
291                  const GP_Context *src_b,
292                  GP_Context *dst,
293                  GP_ProgressCallback *callback);
295 GP_Context *GP_FilterMinAlloc(const GP_Context *src_a,
296                               const GP_Context *src_b,
297                               GP_ProgressCallback *callback);
298 -------------------------------------------------------------------------------
300 Maximum and minimum filter.
302 Rotation and Symmetry filters
303 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
305 [source,c]
306 -------------------------------------------------------------------------------
307 #include <filters/GP_Rotate.h>
308 /* or */
309 #include <GP.h>
311 int GP_FilterMirrorH(const GP_Context *src, GP_Context *dst,
312                      GP_ProgressCallback *callback);
314 GP_Context *GP_FilterMirrorHAlloc(const GP_Context *src,
315                                    GP_ProgressCallback *callback);
316 -------------------------------------------------------------------------------
318 Mirrors context horizontally.
320 Works 'in-place'.
322 The destination has to have the same pixel type and the size must be at least
323 as large as source.
325 [source,c]
326 -------------------------------------------------------------------------------
327 #include <filters/GP_Rotate.h>
328 /* or */
329 #include <GP.h>
331 int GP_FilterMirrorV(const GP_Context *src, GP_Context *dst,
332                      GP_ProgressCallback *callback);
334 GP_Context *GP_FilterMirrorVAlloc(const GP_Context *src,
335                                    GP_ProgressCallback *callback);
336 -------------------------------------------------------------------------------
338 Mirrors context vertically.
340 Works 'in-place'.
342 The destination has to have the same pixel type and the size must be at least
343 as large as source.
345 [source,c]
346 -------------------------------------------------------------------------------
347 #include <filters/GP_Rotate.h>
348 /* or */
349 #include <GP.h>
351 int GP_FilterRotate90(const GP_Context *src, GP_Context *dst,
352                       GP_ProgressCallback *callback);
354 GP_Context *GP_FilterRotate90Alloc(const GP_Context *src,
355                                     GP_ProgressCallback *callback);
356 -------------------------------------------------------------------------------
358 Rotate context by 90 degrees.
360 Doesn't work 'in-place' (yet).
362 The destination has to have the same pixel type and size must be large enough to
363 fit rotated context (i.e. W and H are swapped).
365 [source,c]
366 -------------------------------------------------------------------------------
367 #include <filters/GP_Rotate.h>
368 /* or */
369 #include <GP.h>
371 int GP_FilterRotate180(const GP_Context *src, GP_Context *dst,
372                        GP_ProgressCallback *callback);
374 GP_Context *GP_FilterRotate180Alloc(const GP_Context *src,
375                                      GP_ProgressCallback *callback);
376 -------------------------------------------------------------------------------
378 Rotate context by 180 degrees.
380 Doesn't work 'in-place' (yet).
382 The destination has to have the same pixel type and the size must be at least
383 as large as source.
385 [source,c]
386 -------------------------------------------------------------------------------
387 #include <filters/GP_Rotate.h>
388 /* or */
389 #include <GP.h>
391 int GP_FilterRotate270(const GP_Context *src, GP_Context *dst,
392                        GP_ProgressCallback *callback);
394 GP_Context *GP_FilterRotate270Alloc(const GP_Context *src,
395                                      GP_ProgressCallback *callback);
396 -------------------------------------------------------------------------------
398 Rotate context by 270 degrees.
400 Doesn't work 'in-place' (yet).
402 The destination has to have the same pixel type and destination size must be
403 large enough to fit rotated context (i.e. W and H are swapped).
405 [source,c]
406 -------------------------------------------------------------------------------
407 #include <filters/GP_Rotate.h>
408 /* or */
409 #include <GP.h>
411 typedef enum GP_FilterSymmetries {
412         GP_ROTATE_90,
413         GP_ROTATE_CW = GP_ROTATE_90,
414         GP_ROTATE_180,
415         GP_ROTATE_270,
416         GP_ROTATE_CCW = GP_ROTATE_270,
417         GP_MIRROR_H,
418         GP_MIRROR_V,
419 } GP_FilterSymmetries;
421 GP_Context *GP_FilterSymmetry(const GP_Context *src,
422                               GP_FilterSymmetries symmetry,
423                               GP_ProgressCallback *callback);
425 int GP_FilterSymmetry(const GP_Context *src, GP_Context *dst,
426                       GP_FilterSymmetries symmetry,
427                       GP_ProgressCallback *callback);
428 -------------------------------------------------------------------------------
430 Catch all function for symmetry filters.
433 Linear filters
434 ~~~~~~~~~~~~~~
436 Linear filters family consists of filters based on discrete linear
437 convolution, that means that computed pixel value depends on linear
438 combination of the image pixels.
440 It's defined as:
441 [latex, discrete_linear_convolution.png, 140]
442 -------------------------------------------------------------------------------
444 O(x,y)=\sum_{i=-\infty}^{\infty}\sum_{j=-\infty}^{\infty}I(x+i,y+j) \cdot K(i,j)
446 -------------------------------------------------------------------------------
448 The K denotes convolution kernel and in practice, due to computational
449 complexity i and j are bounded in relatively small intervals. For example i
450 and j are in (-1,1) and the kernel size is 3x3.
452 Note that pixel values outside the image are undefined. The linear convolution
453 in GFXprim simply uses the closest border pixel values for all pixels outside
454 the image.
456 Particular convolution kernel is called separable if it could be decomposed
457 into two one dimensional kernels (these when combined yields back the original
458 kernel). Such convolution then could be applied as two one dimensional
459 convolutions which is faster operation (especially for big kernels).
461 Generic Linear Convolution
462 ^^^^^^^^^^^^^^^^^^^^^^^^^^
464 Following paragraph describes linear convolution implementation as well as a
465 little of the math background skip it if you just need to use one of the
466 ready-to-use filters.
468 [source,c]
469 -------------------------------------------------------------------------------
470 #include <filters/GP_Linear.h>
471 /* or */
472 #include <GP.h>
474 int GP_FilterLinearConvolution_Raw(const GP_Context *src,
475                                    GP_Coord x_src, GP_Coord y_src,
476                                    GP_Size w_src, GP_Size h_src,
477                                    GP_Context *dst,
478                                    GP_Coord x_dst, GP_Coord y_dst,
479                                    float kernel[], uint32_t kw, uint32_t kh,
480                                    float kern_div, GP_ProgressCallback *callback);
481 -------------------------------------------------------------------------------
483 Internal generic convolution filter, this is a base for all linear convolution
484 filters with non-separable kernel.
486 The src coordinate and sizes denotes rectangle in the source context that the
487 filter operates on.
489 The dst coordinates defines offset into the dst context.
491 The kernel is two-dimensional array of a size kw * kh indexed as
492 kernel[x + y*kw].
494 The kern_div is a coefficient that is used to divide the resulting values often
495 used to normalize the result.
497 This filter works 'in-place'.
499 The pixel value is computed as:
500 [latex, discrete_linear_convolution_alg1.png, 140]
501 -------------------------------------------------------------------------------
503 O(x,y)={1 \over kern\_div} \cdot \sum_{i=0}^{kw - 1}\sum_{j=0}^{kh - 1}
504        I(x + i - \lfloor kw/2 \rfloor, y + j - \lfloor kh/2 \rfloor)
505        \cdot kernel(i,j)
507 -------------------------------------------------------------------------------
509 Which is the same as:
511 [latex, discrete_linear_convolution_alg2.png, 140]
512 -------------------------------------------------------------------------------
514 O(x,y)={1 \over kern\_div} \cdot
515        \sum_{i=-\lfloor kw/2 \rfloor}^{\lfloor kw/2 \rfloor}
516        \sum_{j=-\lfloor kh/2 \rfloor}^{\lfloor kh/2 \rfloor}
517        I(x + i, y + j)
518        \cdot kernel(i + \lfloor kw/2 \rfloor, j + \lfloor kh/2 \rfloor)
520 -------------------------------------------------------------------------------
522 NOTE: The number of kernel rows and columns is expected to be odd number.
524 [source,c]
525 -------------------------------------------------------------------------------
526 #include <filters/GP_Linear.h>
527 /* or */
528 #include <GP.h>
530 int GP_FilterHLinearConvolution_Raw(const GP_Context *src,
531                                     GP_Coord x_src, GP_Coord y_src,
532                                     GP_Size w_src, GP_Size h_src,
533                                     GP_Context *dst,
534                                     GP_Coord x_dst, GP_Coord y_dst,
535                                     float kernel[], uint32_t kw, float kern_div,
536                                     GP_ProgressCallback *callback);
538 int GP_FilterVLinearConvolution_Raw(const GP_Context *src,
539                                     GP_Coord x_src, GP_Coord y_src,
540                                     GP_Size w_src, GP_Size h_src,
541                                     GP_Context *dst,
542                                     GP_Coord x_dst, GP_Coord y_dst,
543                                     float kernel[], uint32_t kh, float kern_div,
544                                     GP_ProgressCallback *callback);
546 int GP_FilterVHLinearConvolution_Raw(const GP_Context *src,
547                                      GP_Coord x_src, GP_Coord y_src,
548                                      GP_Size w_src, GP_Size h_src,
549                                      GP_Context *dst,
550                                      GP_Coord x_dst, GP_Coord y_dst,
551                                      float hkernel[], uint32_t kw, float hkern_div,
552                                      float vkernel[], uint32_t kh, float vkern_div,
553                                      GP_ProgressCallback *callback);
555 void GP_FilterKernelPrint_Raw(float kernel[], int kw, int kh, float kern_div);
556 -------------------------------------------------------------------------------
558 Internal special functions for one dimensional vertical and horizontal
559 convolution these two functions are base for all separable convolution filters.
561 The src coordinate and sizes denotes rectangle in the source context that the
562 filter operates on.
564 The dst coordinates are offset into the dst.
566 The kernel is one-dimensional array of floats of size kw or kh.
568 The kern_div is a coefficient that is used to divide the resulting values.
570 The last function does both vertical and horizontal convolution and takes care
571 of correct progress callback.
573 These filters work 'in-place'.
575 The pixel value is computed as:
576 [latex, discrete_linear_1D_convolution_alg1.png, 140]
577 -------------------------------------------------------------------------------
579 O(x,y)={1 \over kern\_div} \cdot \sum_{i=0}^{kw - 1}
580        I(x + i - \lfloor kw/2 \rfloor, y)
581        \cdot kernel(i)
585 O(x,y)={1 \over kern\_div} \cdot \sum_{j=0}^{kw - 1}
586        I(x, y + j - \lfloor kh/2 \rfloor)
587        \cdot kernel(j)
589 -------------------------------------------------------------------------------
591 Which is the same as:
593 [latex, discrete_linear_1D_convolution_alg2.png, 140]
594 -------------------------------------------------------------------------------
596 O(x,y)={1 \over kern\_div} \cdot
597        \sum_{i=-\lfloor kw/2 \rfloor}^{\lfloor kw/2 \rfloor}
598        I(x + i, y)
599        \cdot kernel(i + \lfloor kw/2 \rfloor)
603 O(x,y)={1 \over kern\_div} \cdot
604        \sum_{j=-\lfloor kh/2 \rfloor}^{\lfloor kh/2 \rfloor}
605        I(x, y + j)
606        \cdot kernel(i, j + \lfloor kh/2 \rfloor)
608 -------------------------------------------------------------------------------
610 NOTE: The number of kernel rows and columns is expected to be odd number.
612 NOTE: The linear convolutions are internally implemented using integer
613       arithmetics, which works fine, but you need to take a care not to
614       overflow 32bit signed integer. If the pixel channel size is 8bit
615       long and 10bits are used for the fixed point part of the number
616       the rest must fit into about 10 bits to be safe.
618 [source,c]
619 -------------------------------------------------------------------------------
620 #include <filters/GP_Convolution.h>
621 /* or */
622 #include <GP.h>
624 typedef struct GP_FilterKernel2D {
625         unsigned int w;
626         unsigned int h;
627         float div;
628         float *kernel;
629 } GP_FilterKernel2D;
631 int GP_FilterConvolutionEx(const GP_Context *src,
632                            GP_Coord x_src, GP_Coord y_src,
633                            GP_Size w_src, GP_Coord h_src,
634                            GP_Context *dst,
635                            GP_Coord x_dst, GP_Coord y_dst,
636                            const GP_FilterKernel2D *kernel,
637                            GP_ProgressCallback *callback);
639 GP_Context *GP_FilterConvolutionExAlloc(const GP_Context *src,
640                                         GP_Coord x_src, GP_Coord y_src,
641                                         GP_Size w_src, GP_Size h_src,
642                                         const GP_FilterKernel2D *kernel,
643                                         GP_ProgressCallback *callback);
645 int GP_FilterConvolution(const GP_Context *src, GP_Context *dst,
646                          const GP_FilterKernel2D *kernel,
647                          GP_ProgressCallback *callback);
649 GP_Context *GP_FilterConvolutionAlloc(const GP_Context *src,
650                                       const GP_FilterKernel2D *kernel,
651                                       GP_ProgressCallback *callback);
653 void GP_FilterKernel2DPrint(const GP_FilterKernel2D *kernel);
654 -------------------------------------------------------------------------------
656 Linear convolution filters, you should preferably use this API over the _Raw
657 variants.
659 The Ex variants takes a rectangle on which the filter should operate as well
660 as offset into the destination. The destination must be large enough so that
661 starting with offset there is at least w_dst and h_dst pixels.
663 The kernel is a pointer to a structure initialized with the kernel size, divider
664 and array of kernel values.
666 The last function prints convolution kernel in human-readable format into the
667 stdout.
669 WARNING: If filter is executed in-place the work cannot be distributed between
670          threads (as some of the threads will overwrite values read by other
671          threads). In this case convolution filters runs in one thread
672          regardless of if threads are eanbled or not.
674 [source,c]
675 -------------------------------------------------------------------------------
676 #include <GP.h>
679  * Example box smoothing filter.
680  */
681 static void box_smoothing(GP_Context *img)
683         float box_filter[] = {
684                 1, 1, 1,
685                 1, 1, 1,
686                 1, 1, 1,
687         };
689         GP_FilterKernel2D box_kernel = {
690                 .w = 3,
691                 .h = 3,
692                 .div = 9,
693                 .kernel = box_filter,
694         };
696         GP_FilterConvolution(img, img, &box_kernel, NULL);
698 -------------------------------------------------------------------------------
700 Example function that implements simple 'in-place' smoothing filter.
702 Laplace Filter
703 ^^^^^^^^^^^^^^
705 [source,c]
706 -------------------------------------------------------------------------------
707 #include <GP_Filters.h>
708 /* or */
709 #include <GP.h>
711 int GP_FilterLaplace(const GP_Context *src, GP_Context *dst,
712                      GP_ProgressCallback *callback);
714 GP_Context *GP_FilterLaplaceAlloc(const GP_Context *src,
715                                   GP_ProgressCallback *callback);
716 -------------------------------------------------------------------------------
718 Discrete Laplace filter that produces a second derivative of the original
719 image.
721 The convolution kernel is defined as:
723 [latex, laplacian_kernel.png, 130]
724 -------------------------------------------------------------------------------
726 \begin{bmatrix}
727 0  &  1  &  0 \\
728 0  & -2  &  0 \\
729 0  &  1  &  0
730 \end{bmatrix}
732 \begin{bmatrix}
733 0  &  0  &  0 \\
734 1  & -2  &  1 \\
735 0  &  0  &  0
736 \end{bmatrix}
738 \begin{bmatrix}
739 0  &  1  &  0 \\
740 1  & -4  &  1 \\
741 0  &  1  &  0
742 \end{bmatrix}
744 -------------------------------------------------------------------------------
746 NOTE: This filter is not separable but could be written as a sum of two one
747       dimensional filters as the kernel definition suggests.
749 Laplacian Edge Sharpening
750 ^^^^^^^^^^^^^^^^^^^^^^^^^
752 [source,c]
753 -------------------------------------------------------------------------------
754 #include <GP_Filters.h>
755 /* or */
756 #include <GP.h>
758 int GP_FilterEdgeSharpening(const GP_Context *src, GP_Context *dst,
759                             float w, GP_ProgressCallback *callback);
761 GP_Context *GP_FilterEdgeSharpeningAlloc(const GP_Context *src, float w,
762                                          GP_ProgressCallback *callback);
763 -------------------------------------------------------------------------------
765 Laplace based edge sharpening filter, subtracts weighted second derivative
766 from the original image.
768 The w paramerter is multiplicative weight applied on the second derivative.
769 Reasonable results are when the parameter is between '0.1' and '1'.
771 [latex, laplacian_edge_sharpening.png, 140]
772 -------------------------------------------------------------------------------
774 O(x,y) = I(x,y) - w * I''(x,y)
776 -------------------------------------------------------------------------------
778 include::images/edge_sharpening/images.txt[]
780 Gaussian Blur
781 ^^^^^^^^^^^^^
783 [source,c]
784 -------------------------------------------------------------------------------
785 #include <filters/GP_Blur.h>
786 /* or */
787 #include <GP.h>
789 int GP_FilterGaussianBlurEx(const GP_Context *src,
790                             GP_Coord x_src, GP_Coord y_src,
791                             GP_Size w_src, GP_Size h_src,
792                             GP_Context *dst,
793                             GP_Coord x_dst, GP_Coord y_dst,
794                             float x_sigma, float y_sigma,
795                             GP_ProgressCallback *callback);
797 GP_Context *GP_FilterGaussianBlurExAlloc(const GP_Context *src,
798                                          GP_Coord x_src, GP_Coord y_src,
799                                          GP_Size w_src, GP_Size h_src,
800                                          float x_sigma, float y_sigma,
801                                          GP_ProgressCallback *callback);
803 int GP_FilterGaussianBlur(const GP_Context *src, GP_Context *dst,
804                           float x_sigma, float y_sigma,
805                           GP_ProgressCallback *callback)
807 GP_Context *GP_FilterGaussianBlurAlloc(const GP_Context *src,
808                                        float x_sigma, float y_sigma,
809                                        GP_ProgressCallback *callback)
810 -------------------------------------------------------------------------------
812 Gaussian blur (low pass) filters implemented as bilinear separable
813 convolution.
815 The sigma denotes amount of the blur (the radius is computed accordingly
816 automatically).
818 The sigma values can be set for vertical and horizontal direction
819 independently which may be useful when Gaussian blur is used as a low pass
820 filter before image is resampled non proportionally.
822 include::images/blur/images.txt[]
824 Interpolation filters
825 ~~~~~~~~~~~~~~~~~~~~~
827 Filters to link:filters_resize.html[resize image].
829 Nearest Neighbour Interpolation
830 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
832 Fast, but produces "pixelated" images. May however work better for images with
833 sharp edges mostly consisting of big one color regions (it doesn't blur the
834 result on upscaling).
836 Also is commonly used to show preview before you resample the image correctly.
838 Bilinear Interpolation
839 ^^^^^^^^^^^^^^^^^^^^^^
841 Bilinear is faster than bicubic interpolation and produces quite good results
842 especially the low pass variant doesn't need additional filter on down-sampling.
844 Bicubic Interpolation
845 ^^^^^^^^^^^^^^^^^^^^^
847 Works well as is on image upscaling. To get decent result on downscaling
848 low-pass filter (Gaussian blur) must be used on original image before actual
849 downscaling. To do this reasonably fast we could cheat a little: first resize
850 big images a little without the low-pass filter, then apply low-pass filter and
851 finally downscale it to desired size.
853 [[Dithering]]
854 Dithering
855 ~~~~~~~~~
857 link:filters_dithering.html[Dithering filters] are filters for better loosy
858 (source pixel type has more bits to represent color or grayscale value) pixel
859 type conversions.
861 Median
862 ~~~~~~
864 [source,c]
865 -------------------------------------------------------------------------------
866 #include <filters/GP_Median.h>
867 /* or */
868 #include <GP.h>
870 int GP_FilterMedianEx(const GP_Context *src,
871                       GP_Coord x_src, GP_Coord y_src,
872                       GP_Size w_src, GP_Size h_src,
873                       GP_Context *dst,
874                       GP_Coord x_dst, GP_Coord y_dst,
875                       int xmed, int ymed,
876                       GP_ProgressCallback *callback);
878 GP_Context *GP_FilterMedianExAlloc(const GP_Context *src,
879                                    GP_Coord x_src, GP_Coord y_src,
880                                    GP_Size w_src, GP_Size h_src,
881                                    int xmed, int ymed,
882                                    GP_ProgressCallback *callback);
884 int GP_FilterMedian(const GP_Context *src,
885                     GP_Context *dst,
886                     int xmed, int ymed,
887                     GP_ProgressCallback *callback);
889 GP_Context *GP_FilterMedianAlloc(const GP_Context *src,
890                                  int xmed, int ymed,
891                                  GP_ProgressCallback *callback);
892 -------------------------------------------------------------------------------
894 Constant time median filter (the computational complexity is independent of
895 radius size).
897 The xmed and ymed are radius values for x and y. The algorithm uses xmed
898 respectively ymed pixel neighbors from each side so the result is median of
899 rectangle of 2 * xmed + 1 x 2 * ymed + 1 pixels.
901 include::images/median/images.txt[]