Defines | |
| #define | inline |
| #define | OUT_TYPE IN_TYPE |
| #define | assure(x) assert(x) |
| #define | mybool unsigned char |
| #define | mytrue 1 |
| #define | myfalse 0 |
| #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 | fill_row (IN_TYPE *in, unsigned nx, unsigned y, unsigned xmin, unsigned xmax, IN_TYPE val1, IN_TYPE val2) |
| Write values to image row. | |
| static void | fill_chess (IN_TYPE *in_larger, const IN_TYPE *in, unsigned Nx_larger, unsigned Ny_larger, unsigned Nx, unsigned Ny, unsigned rx, unsigned ry) |
| Fill image border with +- infinity. | |
| 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. | |
#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 117 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 998 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 136 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 221 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 245 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 307 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 328 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 374 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 414 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 440 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 465 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 501 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 525 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 544 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 567 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 636 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 659 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 839 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 860 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 888 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 933 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 971 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 1036 of file filter_median.c.
References assure, get_kth(), median9_1(), OUT_TYPE, and sort3.
Referenced by filter_median().
| static void fill_row | ( | IN_TYPE * | in, | |
| unsigned | nx, | |||
| unsigned | y, | |||
| unsigned | xmin, | |||
| unsigned | xmax, | |||
| IN_TYPE | val1, | |||
| IN_TYPE | val2 | |||
| ) | [static] |
Write values to image row.
| in | image to fill | |
| nx | image width | |
| y | row (?) to fill | |
| xmin | first column to fill (inclusive) | |
| xmax | last column to fill (exclusive) | |
| val1 | value to write first position (xmin, y) | |
| val2 | other value |
Definition at line 1276 of file filter_median.c.
Referenced by fill_chess().
| static void fill_chess | ( | IN_TYPE * | in_larger, | |
| const IN_TYPE * | in, | |||
| unsigned | Nx_larger, | |||
| unsigned | Ny_larger, | |||
| unsigned | Nx, | |||
| unsigned | Ny, | |||
| unsigned | rx, | |||
| unsigned | ry | |||
| ) | [static] |
Fill image border with +- infinity.
| in_larger | image to fill | |
| in | input image | |
| Nx_larger | in_larger width | |
| Ny_larger | in_larger height | |
| Nx | in width | |
| Ny | in height | |
| rx | filter x-radius | |
| ry | filter y-radius |
Definition at line 1305 of file filter_median.c.
References fill_row().
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, same size as 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 (the region where part of the kernel would be outside the image) |
Unsupported filter modes: In-place: Possible using a pixel buffer of dimension (Nx + 2Rx) * (1 + 2Ry) Unsupported border modes: Input extrapolation: The input image is extended to (Nx+2Rx) * (Ny+2Ry) and the halo is filled using extrapolation of the input border. Mean: As any, except the arithmetic mean of the two central values is used.
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 1440 of file filter_median.c.
References assure, dheap_median(), dheap_new(), dheap_replace(), fill_chess(), filter_median(), filter_median_1(), OUT_TYPE, SCA_init(), and SCA_replace().
1.5.1