filter_median.c

00001 #include <assert.h>
00002 #include <stdlib.h>
00003 /* Needed for memcpy() */
00004 #include <string.h>
00005 
00010 #define assure(x) assert(x)
00011 
00012 #ifdef bool
00013 #define mybool bool
00014 #else
00015 #define mybool unsigned char
00016 #endif
00017 
00018 #ifdef true
00019 #define mytrue true
00020 #else
00021 #define mytrue 1
00022 #endif
00023 
00024 #ifdef false
00025 #define myfalse false
00026 #else
00027 #define myfalse 0
00028 #endif
00029 
00030 #ifndef OUT_TYPE
00031 #define OUT_TYPE IN_TYPE
00032 #endif
00033 
00035 typedef struct dheap {
00036     unsigned *heaps;
00037     /* Double binary heap and median element. Values are pixel buffer indices in the
00038        current filtering window.
00039        heaps[0] ... heaps[m-1]    : a maximum heap of pixels with values less than
00040                                     median
00041        heaps[m]                   : median
00042        heaps[m+1] ... heaps[2m]   : a minimum heap of pixels with values greater 
00043                                     than median
00044     */
00045     unsigned *B; /* Size Nx x Ny map from image positions to double heap positions.
00046                     This is the inverse map of the heaps[] array, 
00047                        B[heaps[i]] = i.
00048                     It allows constant time look-up of any pixel in the double heap
00049                     array.
00050 
00051                     Notice that only the pixels in the current window need to be
00052                     simultansously stored in B, therefore B could be compressed to
00053                     size (2rx+1)(2ry+1)^2. However, in that case the overall execution time
00054                     would be dominated by mapping pixels to positions in B.
00055                  */
00056     unsigned *SCA; /* Array Nx*(2Ry+1) of sorted column arrays. Values are image pixel
00057                       buffer indices. Each column array is sorted according to image
00058                       buffer pixel values. This buffer is laid out in column major
00059                       order to allow fast iteration within each column array (i.e.
00060                       the x'th column array is at
00061                       {S[x*(2Ry+1)], ..., S[x*(2Ry+1) + 2Ry]}) 
00062                    */
00063     const IN_TYPE *image;
00064     unsigned rx; //kernel radius
00065     unsigned ry; //kernel radius
00066     unsigned Nx; //image width
00067     unsigned Ny; //image height
00068     unsigned m;  //kernel window half size, must be positive
00069     unsigned Rx;  //2rx + 1
00070     unsigned Ry;  //2ry + 1
00071 } dheap;
00075 #define S_SWAP(SCA, i, j) \
00076 do { \
00077     const unsigned SCAi = SCA[i]; \
00078     const unsigned SCAj = SCA[j]; \
00079     SCA[i] = SCAj; \
00080     SCA[j] = SCAi; \
00081 } while(0)
00082 
00083 
00084 #define BITS 64
00085 
00093 static void
00094 qsort_int(unsigned *SCA, 
00095           unsigned n, const IN_TYPE *image)
00096 {
00097     int i, ir, j, k, l;
00098     int i_stack[BITS];
00099     int j_stack ;
00100     int a;
00101 
00102     IN_TYPE ia;
00103 
00104     //assure( n <= 1 << BITS );  /* generates warnings */
00105     /* true because no-one ever wants to filter with a radius larger than 2^BITS */
00106 
00107     ir = n ;
00108     l = 1 ;
00109     j_stack = 0 ;
00110     while (1) {
00111         if (ir-l < 7) {
00112             for (j=l+1 ; j<=ir ; j++) {
00113                 a = SCA[j-1];
00114                 ia = image[a];
00115                 for (i=j-1 ; i>=1 ; i--) {
00116                     if (image[SCA[i-1]] <= ia) break;
00117                     SCA[i] = SCA[i-1];
00118                 }
00119                 SCA[i] = a;
00120             }
00121             if (j_stack == 0) break;
00122             ir = i_stack[j_stack-- -1];
00123             l  = i_stack[j_stack-- -1];
00124         } else {
00125             /* The following is buggy and has O(n^2) behaviour if the
00126                input array is sorted in reverse order.
00127                For maximum performance we should select the pivot randomly,
00128                (however this step is used only in the initialization of 
00129                the sorted column arrays, so be it) */
00130             k = (l+ir) >> 1;
00131             S_SWAP(SCA, k-1, l);
00132             if (image[SCA[l]] > image[SCA[ir-1]]) {
00133                 S_SWAP(SCA, l, ir-1);
00134             }
00135             if (image[SCA[l-1]] > image[SCA[ir-1]]) {
00136                 S_SWAP(SCA, l-1, ir-1);
00137             }
00138             if (image[SCA[l]] > image[SCA[l-1]]) {
00139                 S_SWAP(SCA, l, l-1);
00140             }
00141 
00142             i = l+1;
00143             j = ir;
00144             a = SCA[l-1];
00145             ia = image[a];
00146             for (;;) {
00147                 do i++; while (image[SCA[i-1]] < ia);
00148                 do j--; while (image[SCA[j-1]] > ia);
00149                 if (j < i) break;
00150                 S_SWAP(SCA, i-1, j-1);
00151             }
00152             SCA[l-1] = SCA[j-1];
00153             SCA[j-1] = a;
00154             j_stack += 2;
00155 
00156             assert( j_stack <= BITS );
00157 
00158             if (ir-i+1 >= j-l) {
00159                 i_stack[j_stack-1] = ir;
00160                 i_stack[j_stack-2] = i;
00161                 ir = j-1;
00162             } else {
00163                 i_stack[j_stack-1] = j-1;
00164                 i_stack[j_stack-2] = l;
00165                 l = i;
00166             }
00167         }
00168     }
00169 
00170     return;
00171 }
00172 
00178 static void
00179 SCA_init(dheap *dh, unsigned x)
00180 {
00181     unsigned y;
00182     unsigned *SCAx = dh->SCA + (dh->Ry)*x;
00183 
00184     for (y = 0; y < dh->Ry; y++) {
00185         SCAx[y] = x + y*dh->Nx;
00186     }
00187 
00188     qsort_int(SCAx,
00189               dh->Ry,
00190               dh->image);
00191     
00192     return;
00193 }
00194 
00202 static void
00203 SCA_replace(dheap *dh, unsigned x, 
00204             unsigned yold, unsigned ynew)
00205 {
00206     unsigned n = dh->Ry;
00207     unsigned *SCAx = dh->SCA + n*x; //start of current column array
00208     const IN_TYPE *im = dh->image;
00209 
00210     unsigned i;
00211     unsigned aold = x + yold*dh->Nx;
00212     unsigned anew = x + ynew*dh->Nx;
00213 
00214     /* Do a linear search for the old pixel and replace it with
00215        the new.
00216 
00217        (Since SCAx is sorted according
00218        to pixel value, we could do a binary search here.
00219        This turns out to be no faster in practice,
00220        up to at least r = 64)
00221     */
00222     for (i = 0; i < n; i++) {
00223         if (SCAx[i] == aold) break;
00224     }
00225     SCAx[i] = anew;
00226 
00227     /* The new pixel is not necessarily in it the right place.
00228        Bubble until SCAx is again sorted.
00229     */
00230     if (i+1 < n && 
00231         im[SCAx[i  ]] >
00232         im[SCAx[i+1]]) {
00233         
00234         S_SWAP(SCAx, i  , i+1);
00235         i++;
00236         
00237         while (i+1 < n && 
00238                im[SCAx[i  ]] >
00239                im[SCAx[i+1]]) {
00240             S_SWAP(SCAx, i  , i+1);
00241             i++;
00242         }
00243     }
00244     else {
00245         while (i >= 1 && 
00246                im[SCAx[i  ]] <
00247                im[SCAx[i-1]]) {
00248             S_SWAP(SCAx, i  , i-1);
00249             i--;
00250         }
00251     }
00252     
00253     return;
00254 }
00255 
00256 
00264 static void
00265 HEAP_SWAP(unsigned i, 
00266           unsigned j,
00267           unsigned int *B,
00268           unsigned int *heaps)
00269 {
00270     unsigned ai = heaps[i];
00271     unsigned aj = heaps[j];
00272     heaps[i] = aj;
00273     heaps[j] = ai;
00274 
00275     B[aj] = i;
00276     B[ai] = j;
00277 
00278   return;
00279 }
00280 
00285 static void
00286 median(dheap *dh)
00287 {
00288     unsigned n = 2 * dh->m + 1;
00289     
00290     const unsigned k = (n-1)/2;
00291     IN_TYPE pivot;
00292     unsigned i, j, lo, hi;
00293 
00294     lo = 0;
00295     hi = n - 1;
00296     
00297     while (lo < hi) {
00298         /* Buggy. We should select the pivot randomly,
00299            or there is O(n^2) behaviour for certain inputs */
00300         pivot = dh->image[dh->heaps[k]];
00301         i = lo;
00302         j = hi;
00303         do {
00304             while (dh->image[dh->heaps[i]] < pivot) i++;
00305             while (dh->image[dh->heaps[j]] > pivot) j--;
00306             if (i <= j) {
00307                 if (i != j) HEAP_SWAP(i, j, dh->B, dh->heaps);
00308                 i++;
00309                 j--;
00310             }
00311         } while (i <= j);
00312         
00313         if (j < k) lo = i;
00314         if (k < i) hi = j;
00315     }
00316     
00317     return;
00318 }
00319 
00320 
00331 static unsigned
00332 bubble_down_gt(const IN_TYPE *image,
00333                unsigned *B,
00334                unsigned *heaps,
00335                unsigned m,
00336                unsigned m1,
00337                unsigned root)
00338 {
00339     unsigned child;
00340     unsigned end = m-1;
00341 
00342     while (root * 2 + 1 <= end) {
00343         child = root*2 + 1;
00344 
00345         if (child < end && 
00346             image[heaps[m1 + child]] > 
00347             image[heaps[m1 + child + 1]]) {
00348             child = child + 1;
00349         }
00350         if (image[heaps[m1 + root]] > 
00351             image[heaps[m1 + child]]) {
00352             HEAP_SWAP(m1 + root, m1 + child, B, heaps);
00353             root = child;
00354         }
00355         else {
00356             return root;
00357         }
00358     }
00359     return root;
00360 }
00361 
00371 static unsigned
00372 bubble_up_gt(const IN_TYPE *image,
00373              unsigned *B,
00374              unsigned *heaps, 
00375              unsigned m1,
00376              unsigned child)
00377 {
00378     unsigned parent;
00379 
00380     while (child > 0) {
00381         parent = (child - 1) / 2;
00382 
00383         if (image[heaps[m1 + parent]] >
00384             image[heaps[m1 + child]]) {
00385             HEAP_SWAP(m1 + parent, m1 + child, B, heaps);
00386             child = parent;
00387         }
00388         else return child;
00389     }
00390     return child;
00391 }
00392 
00397 static void
00398 heapify_gt(dheap *dh)
00399 {
00400     int start = dh->m/2-1;
00401 
00402     while (start >= 0) {
00403         bubble_down_gt(dh->image,
00404                        dh->B,
00405                        dh->heaps,
00406                        dh->m,
00407                        dh->m+1, start);
00408         start = start - 1;
00409     }
00410     return;
00411 }
00412 
00422 static unsigned
00423 bubble_down_lt(const IN_TYPE *image,
00424                unsigned *B,
00425                unsigned *heaps,
00426                unsigned end, unsigned root)
00427 {
00428     unsigned child;
00429 
00430     while (root * 2 + 1 <= end) {
00431         child = root*2 + 1;
00432         
00433         if (child < end &&
00434             image[heaps[child]] <
00435             image[heaps[child + 1]]) {
00436             child = child + 1;
00437         }
00438         if (image[heaps[root]] <
00439             image[heaps[child]]) {
00440             HEAP_SWAP(root, child, B, heaps);
00441             root = child;
00442         }
00443         else {
00444             return root;
00445         }
00446     }
00447     return root;
00448 }
00449 
00458 static unsigned
00459 bubble_up_lt(const IN_TYPE *image,
00460              unsigned *B,
00461              unsigned *heaps, unsigned child)
00462 {
00463     unsigned parent;
00464 
00465     while (child > 0) {
00466         parent = (child - 1) / 2;
00467 
00468         if (image[heaps[parent]] <
00469             image[heaps[child]]) {
00470             HEAP_SWAP(parent, child, B, heaps);
00471             child = parent;
00472         }
00473         else return child;
00474     }
00475     return child;
00476 }
00477 
00482 static void
00483 heapify_lt(dheap *dh)
00484 {
00485     int start = dh->m/2-1;
00486 
00487     while (start >= 0) {
00488         bubble_down_lt(dh->image,
00489                        dh->B,
00490                        dh->heaps,
00491                        dh->m-1, start);
00492         start = start - 1;
00493     }
00494     return;
00495 } 
00496 
00501 static void
00502 dheap_establish(dheap *dh)
00503 {
00504     median(dh);
00505     
00506     heapify_lt(dh);
00507     heapify_gt(dh);
00508     
00509     return;
00510 }
00511 
00524 static dheap *
00525 dheap_new(const IN_TYPE *image, unsigned Nx, unsigned Ny, unsigned rx, unsigned ry)
00526 {
00527     dheap *dh = malloc(sizeof(*dh));
00528     assure( dh != NULL );
00529     assure( rx > 0 || ry > 0 );
00530 
00531     dh->heaps = malloc( (2*rx+1)*(2*ry+1) * sizeof(*dh->heaps));
00532     dh->B     = malloc( Nx*Ny             * sizeof(*dh->B));
00533     dh->SCA   = malloc( Nx*(2*ry+1)       * sizeof(*dh->SCA));
00534     assure( dh->heaps != NULL );
00535     assure( dh->B != NULL );
00536     assure( dh->SCA != NULL );
00537     
00538     dh->image = image;
00539     dh->m     = ((2*rx+1)*(2*ry+1))/2;
00540     dh->Nx    = Nx;
00541     dh->Ny    = Ny;
00542     dh->rx    = rx;
00543     dh->ry    = ry;
00544     dh->Rx    = 2*rx+1;
00545     dh->Ry    = 2*ry+1;
00546 
00547     {
00548         unsigned k = 0;
00549         unsigned x, y;
00550         
00551         for (y = 0; y < dh->Ry; y++) {
00552             for (x = 0; x < dh->Rx; x++) {
00553                 unsigned ai = x + y * dh->Nx;
00554                 dh->heaps[k]  = ai;
00555                 dh->B[ai] = k;
00556                 k++;
00557             }
00558         }
00559     }
00560     dheap_establish(dh);
00561 
00562     {
00563         unsigned x;
00564         for (x = 0; x < 2*dh->rx; x++)
00565         {
00566             SCA_init(dh, x);
00567         }
00568     }
00569 
00570     return dh;
00571 }
00572 
00577 static void
00578 dheap_delete(dheap *dh)
00579 {
00580     free(dh->SCA);
00581     free(dh->B);
00582     free(dh->heaps);
00583     free(dh);
00584 
00585     return;
00586 }
00587 
00593 static IN_TYPE
00594 dheap_median(const dheap *dh)
00595 {
00596     return dh->image[dh->heaps[dh->m]];
00597 }
00598 
00616 static void
00617 dheap_replace(const IN_TYPE *image,
00618               unsigned *B,
00619               unsigned *heaps,
00620               unsigned m,
00621               unsigned m1,
00622               unsigned anew,
00623               unsigned aold)
00624 {
00625     static mybool prev_was_larger  = myfalse;
00626     static mybool prev_was_smaller = myfalse;
00627     /* These flags remember if the previously inserted element was larger/smaller
00628        than the one it replaced. Both flags may be false, which means nothing is known.
00629 
00630        If the previous element was larger (smaller), then the current element
00631        we are inserting now is likely to be also larger (smaller). This information is
00632        used to decrease the number of comparisons needed to bubble the current
00633        element in place.
00634 
00635        To make things thread-safe, these flags could be made in/out parameters
00636        (type mybool*) of this function.
00637     */
00638 
00639     unsigned pos;
00640 
00641     /* Lookup position of old pixel in heaps structure, overwrite with
00642        new pixel */
00643     unsigned ci = B[aold]; 
00644     heaps[ci] = anew;
00645     B[anew] = ci;
00646 
00647     /* Move new element to a correct place. 
00648        Swap heaps priority element with median as needed */
00649     if (ci < m) {
00650         /* Lower heap */
00651         if (prev_was_smaller) {
00652             pos = bubble_down_lt(image, B, heaps, m-1,
00653                                  ci);
00654             if (pos == ci) pos = bubble_up_lt(image, B, heaps, ci);
00655         }
00656         else 
00657             /* previous was larger or nothing is known */
00658         {
00659             /* Optimistic guess optimization here: bubble_up requires only one comparison
00660                and is faster than bubble_down. Therefore, in the case where nothing is known
00661                about the previous element, we try to bubble_up before bubble_down.
00662             */
00663             pos = bubble_up_lt(image, B, heaps, ci);
00664             if (pos == ci) pos = bubble_down_lt(image, B, heaps, m-1, ci);
00665         }
00666         
00667         if (pos == 0 &&
00668             image[heaps[0]] > image[heaps[m]]) {
00669             HEAP_SWAP(0, m, B, heaps);
00670             
00671             if (image[heaps[m1]] < 
00672                 image[heaps[m]]) {
00673                 HEAP_SWAP(m1, m, B, heaps);
00674                 bubble_down_gt(image, B, heaps, m, m1, 0);
00675             }
00676         }
00677 
00678         /* Finally prepare flags for the next call of this function.
00679            If final position and initial postions are the same,
00680            we cannot tell if this element was larger/smaller than the
00681            one it replaced (at least not without the cost of a comparison with
00682            the previous element, which may or may not pay off).
00683         */
00684         prev_was_larger  = (pos < ci);
00685         prev_was_smaller = (pos > ci);
00686         return;
00687     }
00688     else if (ci >= m1) {
00689         /* Upper heap */
00690         if (prev_was_larger) {
00691             pos = bubble_down_gt(image, B, heaps, m, m1, ci-(m1));
00692             if (pos == ci-(m1)) 
00693                 pos = bubble_up_gt(image, B, heaps, m1, ci-(m1));
00694         }
00695         else {
00696             pos = bubble_up_gt(image, B, heaps, m1, ci-(m1));
00697             if (pos == ci-(m1)) 
00698                 pos = bubble_down_gt(image, B, heaps, m, m1, ci-(m1));
00699         }
00700 
00701         if (pos == 0 &&
00702             image[heaps[m1]] < image[heaps[m]]) {
00703             HEAP_SWAP(m1, m, B, heaps);
00704             
00705             if (image[heaps[0]] > image[heaps[m]]) {
00706                 HEAP_SWAP(0, m, B, heaps);
00707                 bubble_down_lt(image, B, heaps, m-1, 0);
00708             }
00709         }
00710 
00711         prev_was_smaller = (pos < ci-(m1));
00712         prev_was_larger  = (pos > ci-(m1));
00713         return;
00714     }
00715     else {
00716         /* The median element was replaced */
00717         if (prev_was_smaller) {
00718             if (image[heaps[0]] > image[heaps[m]]) {
00719                 HEAP_SWAP(0, m, B, heaps);
00720                 bubble_down_lt(image, B, heaps, m-1, 0);
00721                 prev_was_smaller = mytrue;
00722                 prev_was_larger = myfalse;
00723                 return;
00724             } 
00725             else if (image[heaps[m1]] < 
00726                      image[heaps[m]]) {
00727                 HEAP_SWAP(m1, m, B, heaps);
00728                 bubble_down_gt(image, B, heaps, m, m1, 0);
00729                 prev_was_smaller = myfalse;
00730                 prev_was_larger = mytrue;
00731                 return;
00732             } else {
00733                 prev_was_smaller = myfalse;
00734                 prev_was_larger  = myfalse;
00735                 return;
00736             }
00737         } else {
00738             if (image[heaps[m1]] < 
00739                 image[heaps[m]]) {
00740                 HEAP_SWAP(m1, m, B, heaps);
00741                 bubble_down_gt(image, B, heaps, m, m1, 0);
00742                 prev_was_smaller = myfalse;
00743                 prev_was_larger = mytrue;
00744                 return;
00745             } else if (image[heaps[0]] > image[heaps[m]]) {
00746                 HEAP_SWAP(0, m, B, heaps);
00747                 bubble_down_lt(image, B, heaps, m-1, 0);
00748                 prev_was_smaller = mytrue;
00749                 prev_was_larger = myfalse;
00750                 return;
00751             } else {
00752                 prev_was_smaller = myfalse;
00753                 prev_was_larger  = myfalse;
00754                 return;
00755             }
00756         }
00757     }
00758 }
00759 
00760 static
00761 IN_TYPE get_kth(IN_TYPE * a, unsigned n, int k)
00762 {
00763     IN_TYPE x;
00764     int     i, j, l, m;
00765 
00766     l=0; m=n-1;
00767     while (l<m) {
00768         x=a[k];
00769         i=l;
00770         j=m;
00771         do {
00772             while (a[i]<x) i++;
00773             while (x<a[j]) j--;
00774             if (i<=j) {
00775                 const IN_TYPE temp = a[i];
00776                 a[i] = a[j];
00777                 a[j] = temp;
00778                 i++; j--;
00779             }
00780         } while (i<=j);
00781         if (j<k) l=i;
00782         if (k<i) m=j;
00783     }
00784     return a[k];
00785 }
00786 
00796 static inline IN_TYPE
00797 max3(IN_TYPE p0,
00798      IN_TYPE p1,
00799      IN_TYPE p2)
00800 {
00801     return (p0 > p1) 
00802         ?
00803         ((p0 > p2) ? p0 : p2)
00804         :
00805         ((p1 > p2) ? p1 : p2);
00806 }
00807 
00817 static inline IN_TYPE
00818 min3(IN_TYPE p0,
00819      IN_TYPE p1,
00820      IN_TYPE p2)
00821 {
00822     return (p0 < p1)
00823         ?
00824         ((p0 < p2) ? p0 : p2)
00825         :
00826         ((p1 < p2) ? p1 : p2);
00827 }
00828 
00845 static inline IN_TYPE
00846 median5(IN_TYPE p0,
00847         IN_TYPE p1,
00848         IN_TYPE p2,
00849         IN_TYPE p3,
00850         IN_TYPE p4)
00851 {
00852     /*
00853       This would be a one-off median filter (i.e. rank 4th, 5th
00854       or 6th of 9). Saves some 35% execution time.
00855 
00856       return p1;
00857     */
00858     
00859     return (p3 < p1)
00860         ?
00861         ((p4 >= p1) ? p1 : max3(p3, p4, p0))
00862         :
00863         ((p4 <= p1) ? p1 : min3(p3, p4, p2));
00864 }
00865 
00890 static inline IN_TYPE
00891 median9_2(IN_TYPE p0,
00892           IN_TYPE p1,
00893           IN_TYPE p2,
00894           IN_TYPE p3,
00895           IN_TYPE p4,
00896           IN_TYPE p5,
00897           IN_TYPE p6,
00898           IN_TYPE p7,
00899           IN_TYPE p8)
00900 {
00901     return (p4 <= p7) 
00902         ? 
00903         median5(p3, p4, p5, p2, p6)
00904         :
00905         ((p1 < p7) ? median5(p6, p7, p8, p2, p3)
00906          : median5(p0, p1, p2, p8, p3));
00907 }
00928 static inline IN_TYPE
00929 median9_1(IN_TYPE p0,
00930           IN_TYPE p1,
00931           IN_TYPE p2,
00932           IN_TYPE p3,
00933           IN_TYPE p4,
00934           IN_TYPE p5,
00935           IN_TYPE p6,
00936           IN_TYPE p7,
00937           IN_TYPE p8)
00938 {
00939     return (p1 < p4) ? median9_2(p0, p1, p2, p3, p4, p5, p6, p7, p8)
00940              : median9_2(p3, p4, p5, p0, p1, p2, p6, p7, p8);
00941 }
00942 
00956 #define sort3(p0, p1, p2, i0, i1, i2)                         \
00957 do {                                                          \
00958     if (i0 <= i1) {                                           \
00959         if (i1 <= i2) {                                       \
00960              p0 = i0; p1 = i1; p2 = i2;                       \
00961         } else if (i0 <= i2) {                                \
00962             /* i0, i2, i1 */                                  \
00963             p0 = i0; p1 = i2; p2 = i1;                        \
00964         } else {                                              \
00965             /*  i2, i0, i1 */                                 \
00966             p0 = i2; p1 = i0; p2 = i1;                        \
00967         }                                                     \
00968     } else {                                                  \
00969         if (i0 <= i2) {                                       \
00970             /* i1, i0, i2 */                                  \
00971             p0 = i1; p1 = i0; p2 = i2;                        \
00972         } else if (i1 < i2) {                                 \
00973             /* i1, i2, i0 */                                  \
00974             p0 = i1; p1 = i2; p2 = i0;                        \
00975         } else {                                              \
00976             /* i2, i1, i0 */                                  \
00977             p0 = i2; p1=i1; p2 = i0;                          \
00978         }                                                     \
00979     }                                                         \
00980 } while(0)
00981 
00993 static void
00994 filter_median_1(const IN_TYPE *in, OUT_TYPE *out,
00995                 unsigned Nx, unsigned Ny, unsigned border_mode)
00996 {
00997     register IN_TYPE p0, p1, p2, p3, p4, p5;
00998     register IN_TYPE p6 = (IN_TYPE)0; /* Fix (false) uninit warning */
00999     register IN_TYPE p7 = (IN_TYPE)0; /* Fix (false) uninit warning */
01000     register IN_TYPE p8 = (IN_TYPE)0; /* Fix (false) uninit warning */
01001     const IN_TYPE * i0 = in;
01002     const IN_TYPE * i1 = i0 + Nx;
01003     const IN_TYPE * i2 = i1 + Nx;
01004     const IN_TYPE * istop = in + Nx*Ny; /* First pixel not to be accessed */
01005 
01006 
01007     assure( Nx >= 3 );
01008     assure( Ny >= 3 );
01009 
01010     switch (border_mode) {
01011         case IRPLIB_FILTER_BORDER_FILTER: {
01012             IN_TYPE buf6[6];
01013             unsigned j = 0;
01014 
01015             buf6[0] = i0[0];
01016             buf6[1] = i0[1];
01017             buf6[2] = i1[0];
01018             buf6[3] = i1[1];
01019             out[j++] = get_kth(buf6, 4, 1);
01020 
01021             for (; j < Nx-1; j++) {
01022                 memcpy(buf6,   i0+j-1, 3*sizeof(*buf6));
01023                 memcpy(buf6+3, i1+j-1, 3*sizeof(*buf6));
01024                 out[j] = get_kth(buf6, 6, 2);
01025             }
01026             buf6[0] = i0[Nx-2];
01027             buf6[1] = i0[Nx-1];
01028             buf6[2] = i1[Nx-2];
01029             buf6[3] = i1[Nx-1];
01030             out[j] = get_kth(buf6, 4, 1);
01031             out += Nx;
01032 
01033             break;
01034         }
01035         case IRPLIB_FILTER_BORDER_COPY: {
01036             /* From the first row copy all but the last pixel */
01037             if (sizeof(IN_TYPE) == sizeof(OUT_TYPE)) {
01038                 (void)memcpy(out, in, (Nx-1)*sizeof(*out));
01039             } else {
01040                 unsigned i;
01041                 for (i=0; i < Nx-1; i++) out[i] = (OUT_TYPE)in[i];
01042             }
01043         }
01044         case IRPLIB_FILTER_BORDER_EXTRAPOL_OUT:
01045         case IRPLIB_FILTER_BORDER_NOP:
01046             out += Nx-1;
01047             break;
01048         default:
01049         case IRPLIB_FILTER_BORDER_CROP:
01050             break;
01051     }
01052 
01053     for (;i2 < istop; i0 += Nx, i1 += Nx, i2 += Nx, out += Nx) {
01054 
01055         unsigned char k = 2;
01056         unsigned j = 0;
01057 
01058         /* Start a new row */
01059 
01060         switch (border_mode) {
01061             case IRPLIB_FILTER_BORDER_FILTER: {
01062                 IN_TYPE buf6[6];
01063 
01064                 buf6[0] = i0[0];
01065                 buf6[1] = i1[0];
01066                 buf6[2] = i2[0];
01067                 buf6[3] = i0[1];
01068                 buf6[4] = i1[1];
01069                 buf6[5] = i2[1];
01070                 out[0] = get_kth(buf6, 6, 2);
01071 
01072                 /* j must be incremented twice, but out[j] should
01073                    only be incremented once */
01074                 out--;
01075 
01076                 break;
01077             }
01078             case IRPLIB_FILTER_BORDER_CROP:
01079                 out -= 2; /* Nx - 2 medians in each row */
01080                 break;
01081             case IRPLIB_FILTER_BORDER_COPY: {
01082                 /* Copy last pixel from previous row and
01083                    first pixel from current row */
01084                 out[0] = (IN_TYPE)i0[Nx-1];
01085                 out[1] = (IN_TYPE)i0[Nx];
01086                 break;
01087             }
01088             default:
01089                 break;
01090         }
01091 
01092         sort3(p0, p1, p2, i0[j], i1[j], i2[j]);
01093         j++;
01094         
01095         sort3(p3, p4, p5, i0[j], i1[j], i2[j]);
01096         j++;
01097 
01098         for (; j < Nx; j++) {
01099 
01100             if (k == 0) {
01101                 k = 1;
01102                 sort3(p0, p1, p2, i0[j], i1[j], i2[j]);
01103             }
01104             else if (k == 1) {
01105                 k = 2;
01106                 sort3(p3, p4, p5, i0[j], i1[j], i2[j]);
01107             }
01108             else {
01109                 k = 0;
01110                 sort3(p6, p7, p8, i0[j], i1[j], i2[j]);
01111             }
01112         
01113             out[j]
01114                 = (OUT_TYPE)median9_1(p0, p1, p2, p3, p4, p5, p6, p7, p8);
01115 
01116             /* The cost per pixel was determined by considering the 9! possible
01117                permutations of 9 different numbers and subsequently confirmed by
01118                experiment:
01119 
01120                2.66 + 5.52 = 172/21 = 8.19 comparisons per pixel
01121                3 + 3 + 4 = 10  (worst case)
01122                
01123                In the case of two or more equal elements the cost is always the
01124                same or less (down to 6 for all equal elements) due to the way the
01125                comparisons are made.
01126 
01127                If sorted column arrays were used the cost would be one less
01128                1.66 + 5.52 = 151/21 = 7.19
01129                (worst case 9)
01130                
01131                A rank 4th-6th filter would cost 2.86 comparisons less
01132                
01133                2.66 + 2.66 = 16/3 = 5.33
01134                
01135                or only 4.33 comparisons per pixel if SCAs are used.
01136             */
01137         }
01138 
01139         if (border_mode == IRPLIB_FILTER_BORDER_FILTER) {
01140             IN_TYPE buf6[6];
01141 
01142             buf6[0] = i0[j-2];
01143             buf6[1] = i1[j-2];
01144             buf6[2] = i2[j-2];
01145             buf6[3] = i0[j-1];
01146             buf6[4] = i1[j-1];
01147             buf6[5] = i2[j-1];
01148 
01149             out[j] = get_kth(buf6, 6, 2);
01150 
01151             /* out was decremented, increment it back */
01152             out++;
01153         } else if (border_mode == IRPLIB_FILTER_BORDER_EXTRAPOL_OUT) {
01154             /* Extrapolate last and first computed medians of row */
01155             out[1]  = out[2];
01156             out[Nx] = out[Nx-1];
01157 
01158             if (i0 == in) {
01159                 /* Finished first row of medians */
01160                 (void)memcpy(out-(Nx-1), out+1, Nx*sizeof(*out));
01161             }
01162         }
01163     }
01164 
01165     switch (border_mode) {
01166         case IRPLIB_FILTER_BORDER_FILTER: {
01167             IN_TYPE buf6[6];
01168             unsigned j = 0;
01169 
01170             buf6[0] = i0[0];
01171             buf6[1] = i0[1];
01172             buf6[2] = i1[0];
01173             buf6[3] = i1[1];
01174             out[j++] = get_kth(buf6, 4, 1);
01175 
01176             for (; j < Nx-1; j++) {
01177                 memcpy(buf6,   i0+j-1, 3*sizeof(*buf6));
01178                 memcpy(buf6+3, i1+j-1, 3*sizeof(*buf6));
01179                 out[j] = get_kth(buf6, 6, 2);
01180             }
01181             buf6[0] = i0[Nx-2];
01182             buf6[1] = i0[Nx-1];
01183             buf6[2] = i1[Nx-2];
01184             buf6[3] = i1[Nx-1];
01185             out[j] = get_kth(buf6, 4, 1);
01186 
01187             break;
01188         }
01189         default:
01190         case IRPLIB_FILTER_BORDER_CROP:
01191             break;
01192         case IRPLIB_FILTER_BORDER_COPY: {
01193             /* From the 2nd last row copy last pixel */
01194             /* From the last row copy all pixels */
01195             if (sizeof(IN_TYPE) == sizeof(OUT_TYPE)) {
01196                 (void)memcpy(out, istop-(Nx+1), (Nx+1)*sizeof(*out));
01197             } else {
01198                 unsigned i;
01199                 istop -= (Nx+1);
01200                 for (i=0; i < Nx+1; i++) out[i] = (OUT_TYPE)istop[i];
01201             }
01202             break;
01203         }
01204         case IRPLIB_FILTER_BORDER_EXTRAPOL_OUT: {
01205             /* Extrapolate last row of computed medians */
01206 
01207             (void)memcpy(out+1, out-(Nx-1), Nx*sizeof(*out));
01208             break;
01209         }
01210     }
01211 
01212     return;
01213 }
01214 
01215 
01310 static void
01311 filter_median(const IN_TYPE *in, OUT_TYPE *out,
01312               unsigned Nx, unsigned Ny,
01313               unsigned rx, unsigned ry,
01314               unsigned border_mode)
01315 {
01316     dheap *dh;
01317     unsigned y;
01318     unsigned x;
01319     int dx;
01320 
01321     assure( 2*rx + 1 <= Nx ); //ignore border for now
01322     assure( 2*ry + 1 <= Ny ); //ignore border for now
01323 
01324     border_mode &= IRPLIB_FILTER_BORDER_MODE;
01325 
01326     if (rx == 1 && ry == 1) {
01327         filter_median_1(in, out, Nx, Ny, border_mode);
01328 
01329         return;
01330     }
01331 
01332     assure( border_mode == 0 ); //ignore border for now
01333 
01334     if (rx == 0 && ry == 0) {
01335         /* The double heap structure must have non-empty heaps,
01336            so handle this (trivial) case explicitly.
01337            
01338            Works for all border modes (because there is no border).
01339         */
01340         unsigned i;
01341         for (i = 0; i < Nx * Ny; i++) out[i] = (OUT_TYPE)in[i];
01342         return;
01343     }
01344 
01345     dh = dheap_new(in, Nx, Ny, rx, ry);
01346     
01347     /* Loop over image like this
01348        -->->->-
01349        -<-<-<--
01350        -->->->-  
01351        so that the current window always moves by 1 pixel per iteration
01352     */
01353     for (y = 0 + dh->ry, dx = 1;
01354          y < dh->Ny - dh->ry; 
01355          y++, dx = -dx) {
01356 
01357         unsigned xfirst = (dx ==  1) ? dh->rx : dh->Nx-1 - dh->rx;
01358         unsigned xlast  = (dx == -1) ? dh->rx : dh->Nx-1 - dh->rx;
01359 
01360         for (x = xfirst; x != xlast + dx; x += dx) {
01361 
01362             if (y == dh->ry) {
01363                 SCA_init(dh, x + dx * dh->rx);
01364             }
01365             else {
01366                 /* Most frequent case. Update just 1 pixel in 1 sorted column array */
01367                 SCA_replace(dh, x + dx * dh->rx,
01368                             y - dh->ry - 1,
01369                             y + dh->ry);
01370             }
01371             
01372             if (x == xfirst) {
01373                 if (y != dh->ry) {
01374                     /* Window just moved to next row,
01375                        update pixels at window bottom row */
01376                     unsigned i;
01377                     for (i  = x - dx*dh->rx; 
01378                          i != x + dx*dh->rx; i += dx) {
01379                         SCA_replace(dh, i,
01380                                     y - dh->ry - 1,
01381                                     y + dh->ry);
01382                         
01383                         dheap_replace(dh->image,
01384                                       dh->B,
01385                                       dh->heaps,
01386                                       dh->m,
01387                                       dh->m+1,
01388                                       i + ((y + dh->ry    ) * dh->Nx),
01389                                       i + ((y - dh->ry - 1) * dh->Nx));
01390                     }
01391                     
01392                     dheap_replace(dh->image,
01393                                   dh->B,
01394                                   dh->heaps,
01395                                   dh->m,
01396                                   dh->m+1,
01397                                   i + ((y + dh->ry    ) * dh->Nx),
01398                                   i + ((y - dh->ry - 1) * dh->Nx));
01399                 }
01400             }
01401             else {
01402                 /* Most frequent case. Replace pixels in xold column
01403                    with pixels from xnew column */
01404                 unsigned xnew = x + dx * dh->rx;
01405                 unsigned xold = x - dx * (dh->rx+1);
01406                 unsigned *SCAxnew = dh->SCA + dh->Ry*xnew;
01407                 unsigned *SCAxold = dh->SCA + dh->Ry*xold;
01408                 
01409                 const IN_TYPE *image = dh->image;
01410                 unsigned *B = dh->B;
01411                 unsigned *heaps = dh->heaps;
01412                 unsigned m = dh->m;
01413                 unsigned m1 = m+1;
01414                 unsigned anew, aold;
01415                 unsigned i;
01416                 
01417                 /* Loop through old/new sorted column arrays and replace
01418                    old pixels by new pixels of the same rank (i.e. position in
01419                    sorted column array). 
01420                    
01421                    This heuristic increases the chance that the new pixel is close
01422                    to its final position when inserted into the double heap structure.
01423                 */
01424                 for (i = 0; i < dh->Ry; i++) {
01425                     anew = SCAxnew[i];
01426                     aold = SCAxold[i];
01427                     
01428                     dheap_replace(image, B, heaps, m, m1, 
01429                                   anew, aold);
01430                 }
01431             }
01432             out[x + y*Nx] = (OUT_TYPE)dheap_median(dh);
01433         }
01434     }
01435 
01436     dheap_delete(dh);
01437     return;
01438 }
01439 

Generated on Thu Nov 15 14:32:24 2007 for UVES Pipeline Reference Manual by  doxygen 1.5.1