contrib/tbl/vipl/vipl_median.txx
Go to the documentation of this file.
00001 #ifndef vipl_median_txx_
00002 #define vipl_median_txx_
00003 
00004 #include "vipl_median.h"
00005 
00006 template <class ImgIn,class ImgOut,class DataIn,class DataOut,class PixelItr>
00007 bool vipl_median <ImgIn,ImgOut,DataIn,DataOut,PixelItr> :: section_applyop()
00008 {
00009   const ImgIn &in = this->in_data(0);
00010   ImgOut &out = *this->out_data_ptr();
00011   int size = (radius() < 0) ? 0 : int(radius());
00012 
00013   // circular mask was generated in preop(), we just use it here
00014 
00015   // apply filter:
00016   DataIn* v = new DataIn[(2*size+1)*(2*size+1)];
00017   int startx = vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::start(this->X_Axis());
00018   int starty = vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::start(this->Y_Axis());
00019   int stopx  = vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::stop(this->X_Axis());
00020   int stopy  = vipl_filter<ImgIn,ImgOut,DataIn,DataOut,2,PixelItr>::stop(this->Y_Axis());
00021   for (int j = starty; j < stopy; ++j)
00022     for (int i = startx; i < stopx; ++i) {
00023       register unsigned int count = 0;
00024       v[count++] = fgetpixel(in, i, j, DataIn(0));
00025       for (int x=0; x<=size; ++x) for (int y=0; y<=size; ++y) if (mask()[x][y]) {
00026         v[count++] = getpixel(in, i+x, j+y, DataIn(0));
00027         v[count++] = getpixel(in, i-x, j+y, DataIn(0));
00028         v[count++] = getpixel(in, i+x, j-y, DataIn(0));
00029         v[count++] = getpixel(in, i-x, j-y, DataIn(0));
00030       }
00031       // qsort:
00032       for (unsigned int d=count/2; d>0; d/=2)
00033         for (unsigned int ii=d; ii<count; ++ii)
00034           for (int jj=ii-d; jj>=0 && v[jj]>v[jj+d]; jj-=d) {
00035             DataIn t = v[jj]; v[jj] = v[jj+d]; v[jj+d] = t;
00036           }
00037 
00038       fsetpixel(out, i, j, DataOut(v[count/2]));
00039     }
00040   delete[] v;
00041   return true;
00042 }
00043 
00044 // it is important that the mask be computed in preop, if it was done in
00045 // section_applyop then on a large image it would be computed many times.
00046 template <class ImgIn,class ImgOut,class DataIn,class DataOut,class PixelItr>
00047 bool vipl_median <ImgIn,ImgOut,DataIn,DataOut,PixelItr> :: preop()
00048 {
00049   // create circular mask:
00050   int size = (radius() < 0) ? 0 : int(radius());
00051   float rs = (radius() < 0) ? 0 : radius() * radius();
00052   typedef bool* boolptr;
00053   if (mask() == 0)
00054     ref_mask() = new boolptr[1+size];
00055   else {
00056     for (int x=0; x<=size; ++x)
00057       if (mask()[x]) delete[] ref_mask()[x];
00058     delete[] ref_mask();
00059     ref_mask() = new boolptr[1+size];
00060   }
00061   for (int x=0; x<=size; ++x) {
00062     ref_mask()[x] = new bool[size+1];
00063     for (int y=0; y<=size; ++y)
00064       ref_mask()[x][y] = (x*x + y*y <= rs);
00065   }
00066   return true;
00067 }
00068 
00069 // Since we will know if radius changes between calls to filter, we
00070 // destroy the mask in postop, after we are all done filtering
00071 template <class ImgIn,class ImgOut,class DataIn,class DataOut,class PixelItr>
00072 bool vipl_median <ImgIn,ImgOut,DataIn,DataOut,PixelItr> :: postop()
00073 {
00074   int size = (radius() < 0) ? 0 : int(radius());
00075   if (mask()) {
00076     for (int x=0; x<=size; ++x)
00077       if (mask()[x]) delete[] ref_mask()[x];
00078     delete[] ref_mask();
00079     ref_mask()=0;
00080   }
00081   return true;
00082 }
00083 
00084 #endif // vipl_median_txx_