Defines | |
| #define | assure(x) assert(x) |
| #define | mybool unsigned char |
| #define | mytrue 1 |
| #define | myfalse 0 |
| #define | OUT_TYPE IN_TYPE |
| #define | S_SWAP(SCA, i, j) |
| #define | BITS 64 |
| #define | sort3(p0, p1, p2, i0, i1, i2) |
| sort 3 elements | |
Functions | |
| static void | qsort_int (unsigned *SCA, unsigned n, const IN_TYPE *image) |
| quick sort | |
| static void | SCA_init (dheap *dh, unsigned x) |
| initialize sorted column array | |
| static void | SCA_replace (dheap *dh, unsigned x, unsigned yold, unsigned ynew) |
| Update sorted column array. | |
| static void | HEAP_SWAP (unsigned i, unsigned j, unsigned int *B, unsigned int *heaps) |
| Swap elements in double heap. | |
| static void | median (dheap *dh) |
| Partion double heaps array in median and upper/lower values. | |
| static unsigned | bubble_down_gt (const IN_TYPE *image, unsigned *B, unsigned *heaps, unsigned m, unsigned m1, unsigned root) |
| bubble down (towards leaves) in upper heap | |
| static unsigned | bubble_up_gt (const IN_TYPE *image, unsigned *B, unsigned *heaps, unsigned m1, unsigned child) |
| bubble up (towards root) in upper heap | |
| static void | heapify_gt (dheap *dh) |
| establish upper heap | |
| static unsigned | bubble_down_lt (const IN_TYPE *image, unsigned *B, unsigned *heaps, unsigned end, unsigned root) |
| bubble down in lower heap | |
| static unsigned | bubble_up_lt (const IN_TYPE *image, unsigned *B, unsigned *heaps, unsigned child) |
| bubble up in lower heap | |
| static void | heapify_lt (dheap *dh) |
| establish lower heap | |
| static void | dheap_establish (dheap *dh) |
| Initialize double heap. | |
| static dheap * | dheap_new (const IN_TYPE *image, unsigned Nx, unsigned Ny, unsigned rx, unsigned ry) |
| double heap constructor | |
| static void | dheap_delete (dheap *dh) |
| double heap destructor | |
| static IN_TYPE | dheap_median (const dheap *dh) |
| get current median | |
| static void | dheap_replace (const IN_TYPE *image, unsigned *B, unsigned *heaps, unsigned m, unsigned m1, unsigned anew, unsigned aold) |
| Insert and remove element in double heap. | |
| static IN_TYPE | get_kth (IN_TYPE *a, unsigned n, int k) |
| static IN_TYPE | max3 (IN_TYPE p0, IN_TYPE p1, IN_TYPE p2) |
| max of 3 elements | |
| static IN_TYPE | min3 (IN_TYPE p0, IN_TYPE p1, IN_TYPE p2) |
| min of 3 elements | |
| static IN_TYPE | median5 (IN_TYPE p0, IN_TYPE p1, IN_TYPE p2, IN_TYPE p3, IN_TYPE p4) |
| median of 5 | |
| static IN_TYPE | median9_2 (IN_TYPE p0, IN_TYPE p1, IN_TYPE p2, IN_TYPE p3, IN_TYPE p4, IN_TYPE p5, IN_TYPE p6, IN_TYPE p7, IN_TYPE p8) |
| median of 9 | |
| static IN_TYPE | median9_1 (IN_TYPE p0, IN_TYPE p1, IN_TYPE p2, IN_TYPE p3, IN_TYPE p4, IN_TYPE p5, IN_TYPE p6, IN_TYPE p7, IN_TYPE p8) |
| median of 9 | |
| static void | filter_median_1 (const IN_TYPE *in, OUT_TYPE *out, unsigned Nx, unsigned Ny, unsigned border_mode) |
| fast 3x3 image median filter | |
| static void | filter_median (const IN_TYPE *in, OUT_TYPE *out, unsigned Nx, unsigned Ny, unsigned rx, unsigned ry, unsigned border_mode) |
| Fast, any bit-depth, image median filter. | |
| static void | irplib_image_filter_double_double (double *, const double *, int, int, int, int, unsigned) |
| static void | irplib_image_filter_double_float (double *, const float *, int, int, int, int, unsigned) |
| static void | irplib_image_filter_double_int (double *, const int *, int, int, int, int, unsigned) |
| static void | irplib_image_filter_float_double (float *, const double *, int, int, int, int, unsigned) |
| static void | irplib_image_filter_float_float (float *, const float *, int, int, int, int, unsigned) |
| static void | irplib_image_filter_float_int (float *, const int *, int, int, int, int, unsigned) |
| static void | irplib_image_filter_int_double (int *, const double *, int, int, int, int, unsigned) |
| static void | irplib_image_filter_int_float (int *, const float *, int, int, int, int, unsigned) |
| static void | irplib_image_filter_int_int (int *, const int *, int, int, int, int, unsigned) |
| cpl_error_code | irplib_image_filter (cpl_image *self, const cpl_image *other, int hsizex, int hsizey, irplib_filter_mode mode) |
| Filter an image. | |
#include <irplib_filter.h>
| #define S_SWAP | ( | SCA, | |||
| i, | |||||
| j | ) |
Value:
do { \ const unsigned SCAi = SCA[i]; \ const unsigned SCAj = SCA[j]; \ SCA[i] = SCAj; \ SCA[j] = SCAi; \ } while(0)
Definition at line 75 of file filter_median.c.
Referenced by qsort_int(), and SCA_replace().
| #define sort3 | ( | p0, | |||
| p1, | |||||
| p2, | |||||
| i0, | |||||
| i1, | |||||
| i2 | ) |
Value:
do { \ if (i0 <= i1) { \ if (i1 <= i2) { \ p0 = i0; p1 = i1; p2 = i2; \ } else if (i0 <= i2) { \ /* i0, i2, i1 */ \ p0 = i0; p1 = i2; p2 = i1; \ } else { \ /* i2, i0, i1 */ \ p0 = i2; p1 = i0; p2 = i1; \ } \ } else { \ if (i0 <= i2) { \ /* i1, i0, i2 */ \ p0 = i1; p1 = i0; p2 = i2; \ } else if (i1 < i2) { \ /* i1, i2, i0 */ \ p0 = i1; p1 = i2; p2 = i0; \ } else { \ /* i2, i1, i0 */ \ p0 = i2; p1=i1; p2 = i0; \ } \ } \ } while(0)
| p0 | (out) rank 1 | |
| p1 | (out) rank 2 | |
| p2 | (out) rank 3 | |
| i0 | (in) element | |
| i1 | (in) element | |
| i2 | (in) element |
Definition at line 956 of file filter_median.c.
Referenced by filter_median_1().
| static void qsort_int | ( | unsigned * | SCA, | |
| unsigned | n, | |||
| const IN_TYPE * | image | |||
| ) | [static] |
quick sort
| SCA | sorted column array to be sorted | |
| n | length of SCA | |
| image | input image |
Definition at line 94 of file filter_median.c.
Referenced by SCA_init().
| static void SCA_init | ( | dheap * | dh, | |
| unsigned | x | |||
| ) | [static] |
initialize sorted column array
| dh | double heap | |
| x | current column |
Definition at line 179 of file filter_median.c.
References qsort_int().
Referenced by dheap_new(), and filter_median().
| static void SCA_replace | ( | dheap * | dh, | |
| unsigned | x, | |||
| unsigned | yold, | |||
| unsigned | ynew | |||
| ) | [static] |
Update sorted column array.
| dh | double heap | |
| x | current column | |
| yold | image row of previous element | |
| ynew | image row of new element |
Definition at line 203 of file filter_median.c.
References S_SWAP.
Referenced by filter_median().
| static void HEAP_SWAP | ( | unsigned | i, | |
| unsigned | j, | |||
| unsigned int * | B, | |||
| unsigned int * | heaps | |||
| ) | [static] |
Swap elements in double heap.
| i | index in heaps array | |
| j | index in heaps array | |
| B | image to heap map | |
| heaps | heaps array |
Definition at line 265 of file filter_median.c.
Referenced by bubble_down_gt(), bubble_down_lt(), bubble_up_gt(), bubble_up_lt(), dheap_replace(), and median().
| static void median | ( | dheap * | dh | ) | [static] |
Partion double heaps array in median and upper/lower values.
| dh | double heap with elements in no particular order |
Definition at line 286 of file filter_median.c.
References HEAP_SWAP().
Referenced by dheap_establish(), irplib_spectrum_find_brightest(), opt_measure_profile_order(), uves_average_reject(), and uves_get_blaze_ratio().
| static unsigned bubble_down_gt | ( | const IN_TYPE * | image, | |
| unsigned * | B, | |||
| unsigned * | heaps, | |||
| unsigned | m, | |||
| unsigned | m1, | |||
| unsigned | root | |||
| ) | [static] |
bubble down (towards leaves) in upper heap
| image | input image | |
| B | inverse map | |
| heaps | double heap array | |
| m | heap size | |
| m1 | m + 1 | |
| root | double heap position |
Definition at line 332 of file filter_median.c.
References HEAP_SWAP().
Referenced by dheap_replace(), and heapify_gt().
| static unsigned bubble_up_gt | ( | const IN_TYPE * | image, | |
| unsigned * | B, | |||
| unsigned * | heaps, | |||
| unsigned | m1, | |||
| unsigned | child | |||
| ) | [static] |
bubble up (towards root) in upper heap
| image | input image | |
| B | inverse map | |
| heaps | double heap array | |
| m1 | heap size + 1 | |
| child | double heap position |
Definition at line 372 of file filter_median.c.
References HEAP_SWAP().
Referenced by dheap_replace().
| static void heapify_gt | ( | dheap * | dh | ) | [static] |
establish upper heap
| dh | double heap |
Definition at line 398 of file filter_median.c.
References bubble_down_gt().
Referenced by dheap_establish().
| static unsigned bubble_down_lt | ( | const IN_TYPE * | image, | |
| unsigned * | B, | |||
| unsigned * | heaps, | |||
| unsigned | end, | |||
| unsigned | root | |||
| ) | [static] |
bubble down in lower heap
| image | input image | |
| B | inverse map | |
| heaps | double heap array | |
| end | double heap last position | |
| root | double heap position |
Definition at line 423 of file filter_median.c.
References HEAP_SWAP().
Referenced by dheap_replace(), and heapify_lt().
| static unsigned bubble_up_lt | ( | const IN_TYPE * | image, | |
| unsigned * | B, | |||
| unsigned * | heaps, | |||
| unsigned | child | |||
| ) | [static] |
bubble up in lower heap
| image | input image | |
| B | inverse map | |
| heaps | double heap array | |
| child | double heap position |
Definition at line 459 of file filter_median.c.
References HEAP_SWAP().
Referenced by dheap_replace().
| static void heapify_lt | ( | dheap * | dh | ) | [static] |
establish lower heap
| dh | double heap |
Definition at line 483 of file filter_median.c.
References bubble_down_lt().
Referenced by dheap_establish().
| static void dheap_establish | ( | dheap * | dh | ) | [static] |
Initialize double heap.
| dh | double heap with elements in no particular order |
Definition at line 502 of file filter_median.c.
References heapify_gt(), heapify_lt(), and median().
Referenced by dheap_new().
| static dheap* dheap_new | ( | const IN_TYPE * | image, | |
| unsigned | Nx, | |||
| unsigned | Ny, | |||
| unsigned | rx, | |||
| unsigned | ry | |||
| ) | [static] |
double heap constructor
| image | input image | |
| Nx | image width | |
| Ny | image height | |
| rx | filtering half-size in x | |
| ry | filtering half-size in y |
Definition at line 525 of file filter_median.c.
References assure, dheap_establish(), and SCA_init().
Referenced by filter_median().
| static void dheap_delete | ( | dheap * | dh | ) | [static] |
| static IN_TYPE dheap_median | ( | const dheap * | dh | ) | [static] |
get current median
| dh | double heap |
Definition at line 594 of file filter_median.c.
Referenced by filter_median().
| static void dheap_replace | ( | const IN_TYPE * | image, | |
| unsigned * | B, | |||
| unsigned * | heaps, | |||
| unsigned | m, | |||
| unsigned | m1, | |||
| unsigned | anew, | |||
| unsigned | aold | |||
| ) | [static] |
Insert and remove element in double heap.
| image | input image | |
| B | inverse map | |
| heaps | double heap array | |
| m | heap size | |
| m1 | m + 1 | |
| anew | image index of pixel to be inserted | |
| aold | image index of pixel to be removed |
Algorithm: The inverse map is used to quickly locate the old pixel, which is replaced, and the new element bubbled to a (non-unique) correct position until the double heap structure is re-established. The inverse map is maintained while swapping heap elements.
Definition at line 617 of file filter_median.c.
References bubble_down_gt(), bubble_down_lt(), bubble_up_gt(), bubble_up_lt(), HEAP_SWAP(), mybool, myfalse, and mytrue.
Referenced by filter_median().
| static IN_TYPE max3 | ( | IN_TYPE | p0, | |
| IN_TYPE | p1, | |||
| IN_TYPE | p2 | |||
| ) | [static] |
max of 3 elements
| p0 | element | |
| p1 | element | |
| p2 | element |
Definition at line 797 of file filter_median.c.
Referenced by median5().
| static IN_TYPE min3 | ( | IN_TYPE | p0, | |
| IN_TYPE | p1, | |||
| IN_TYPE | p2 | |||
| ) | [static] |
min of 3 elements
| p0 | element | |
| p1 | element | |
| p2 | element |
Definition at line 818 of file filter_median.c.
Referenced by median5().
| static IN_TYPE median5 | ( | IN_TYPE | p0, | |
| IN_TYPE | p1, | |||
| IN_TYPE | p2, | |||
| IN_TYPE | p3, | |||
| IN_TYPE | p4 | |||
| ) | [static] |
median of 5
| p0 | element | |
| p1 | element | |
| p2 | element | |
| p3 | element | |
| p4 | element |
Cost: 2 + 0 (probability 4/7) or 2 + 2 (probability 3/7) = 20/7 = 2.86 comparisons
Definition at line 846 of file filter_median.c.
References max3(), and min3().
Referenced by median9_2().
| static IN_TYPE median9_2 | ( | IN_TYPE | p0, | |
| IN_TYPE | p1, | |||
| IN_TYPE | p2, | |||
| IN_TYPE | p3, | |||
| IN_TYPE | p4, | |||
| IN_TYPE | p5, | |||
| IN_TYPE | p6, | |||
| IN_TYPE | p7, | |||
| IN_TYPE | p8 | |||
| ) | [static] |
median of 9
| p0 | element | |
| p1 | element | |
| p2 | element | |
| p3 | element | |
| p4 | element | |
| p5 | element | |
| p6 | element | |
| p7 | element | |
| p8 | element |
Cost: 1 + 2.86 (probability 1/3) or 2 + 2.86 (probability 2/3) = 95/21 = 4.52 comparisons
Definition at line 891 of file filter_median.c.
References median5().
Referenced by median9_1().
| static IN_TYPE median9_1 | ( | IN_TYPE | p0, | |
| IN_TYPE | p1, | |||
| IN_TYPE | p2, | |||
| IN_TYPE | p3, | |||
| IN_TYPE | p4, | |||
| IN_TYPE | p5, | |||
| IN_TYPE | p6, | |||
| IN_TYPE | p7, | |||
| IN_TYPE | p8 | |||
| ) | [static] |
median of 9
| p0 | element | |
| p1 | element | |
| p2 | element | |
| p3 | element | |
| p4 | element | |
| p5 | element | |
| p6 | element | |
| p7 | element | |
| p8 | element |
Cost: 1 + 4.52 = 116/21 = 5.52 comparisons
Definition at line 929 of file filter_median.c.
References median9_2().
Referenced by filter_median_1().
| static void filter_median_1 | ( | const IN_TYPE * | in, | |
| OUT_TYPE * | out, | |||
| unsigned | Nx, | |||
| unsigned | Ny, | |||
| unsigned | border_mode | |||
| ) | [static] |
fast 3x3 image median filter
| in | image to filter | |
| out | pre-allocated output image, must not overlap with the input image | |
| Nx | image width | |
| Ny | image height | |
| border_mode | periodic boundaries |
Definition at line 994 of file filter_median.c.
References assure, get_kth(), median9_1(), OUT_TYPE, and sort3.
Referenced by filter_median().
| static void filter_median | ( | const IN_TYPE * | in, | |
| OUT_TYPE * | out, | |||
| unsigned | Nx, | |||
| unsigned | Ny, | |||
| unsigned | rx, | |||
| unsigned | ry, | |||
| unsigned | border_mode | |||
| ) | [static] |
Fast, any bit-depth, image median filter.
| in | image to filter | |
| out | pre-allocated output image, may not overlap with the input image | |
| Nx | image width | |
| Ny | image height | |
| rx | filtering half-size in x, non-negative | |
| ry | filtering half-size in y, non-negative | |
| border_mode | Handling of the pixels near the border 0: the border is not processed 1: border copy 2: constant extrapolation 3: median of fewer values |
For each pixel in the image the median of a (2*Rx + 1)(2*Ry + 1) window is computed.
The straightforward approach is to loop over the image and build and sort the kernel array for every pixel. This leads to an O(RxRy log RxRy) algorithm, or O(RxRy) if the median is computed by repeated partitions.
The basic idea in this implementation is to maintain a double heap structure of the running window pixels:
_____ \ / <-- minimum heap of elements greater than the median \ / . <-- median
/ \ <-- maximum heap of elements less than the median / \ -----
With every 1 pixel shift of the running window (2Ry + 1) pixels have to be removed from the double heap, and another (2Ry + 1) pixels must be inserted. The worst case time for inserting/removing one element is two heap heights, O(log RxRy), so the overall time is O(Ry log RxRy).
Various tricks improve the performance
Rather than sorting every time the (2Ry + 1) new and old values (which would cost O(Ry log Ry), a sorted array of the current pixels is maintained for every column in the image. To update the sorted column arrays (SCA) only one pixel needs to be inserted/removed per iteration. When using simple linear search and insertion, the maintenance cost for the SCAs is O(Ry). A possible optimization not pursued here is to implement the SCAs as balanced binary search trees, which would reduce their maintenance cost to O(log Ry) (but the heap maintenance cost would still be O(Ry).
Performance: While the theoretical time complexity is O(Ry log RxRy), the empirical behaviour (for realistic size images with random, uncorrelated pixels from the same probability distribution) is O(Ry) with small constant coefficients.
Rx = Ry = 1 is handled as a separate case.
Definition at line 1311 of file filter_median.c.
References assure, dheap_median(), dheap_new(), dheap_replace(), filter_median_1(), OUT_TYPE, SCA_init(), and SCA_replace().
| cpl_error_code irplib_image_filter | ( | cpl_image * | self, | |
| const cpl_image * | other, | |||
| int | hsizex, | |||
| int | hsizey, | |||
| irplib_filter_mode | mode | |||
| ) |
Filter an image.
| self | Filtered image | |
| other | Image to filter | |
| hsizex | Filtering half-size in x, total size is 1 + 2 * hsizex | |
| hsizey | Filtering half-size in y, total size is 1 + 2 * hsizey | |
| mode | Filter mode binary or-ed with border handling mode |
Border modes: IRPLIB_FILTER_BORDER_NOP: Do not modify the border of the filtered image (This is the default mode). IRPLIB_FILTER_BORDER_CROP: Crop filtered image IRPLIB_FILTER_BORDER_FILTER: Filter the border using the reduced number of pixels. If in median filterring the number of pixels is even choose any one of the two central values. (For hsizex * hsizey == 1 the chosen value is always the lower one). IRPLIB_FILTER_BORDER_COPY: Copy the border of the raw image IRPLIB_FILTER_BORDER_EXTRAPOL_OUT: Extrapolate computed medians to border
irplib_image_filter(filtered, raw, 1, 1, IRPLIB_FILTER_MEDIAN | IRPLIB_FILTER_BORDER_FILTER);
Definition at line 166 of file irplib_filter.c.
1.5.1