Marsyas  0.6.0-alpha
/usr/src/RPM/BUILD/marsyas-0.6.0/src/marsyas/marsystems/MedianFilter.cpp
Go to the documentation of this file.
00001 #include "MedianFilter.h"
00002 #include <map>
00003 #include <algorithm>
00004 
00005 using std::ostringstream;
00006 using std::map;
00007 using std::multimap;
00008 using std::less;
00009 using std::pair;
00010 using std::min;
00011 using std::max;
00012 
00013 using namespace Marsyas;
00014 
00015 MedianFilter::MedianFilter(mrs_string inName)
00016   :MarSystem("MedianFilter",inName)
00017 {
00018   addControls();
00019 }
00020 
00021 MedianFilter::MedianFilter(const MedianFilter& inToCopy)
00022   :MarSystem(inToCopy)
00023 {
00024   ctrl_WindowSize_ = getctrl("mrs_natural/WindowSize");
00025   WindowSize_ = inToCopy.WindowSize_;
00026 }
00027 
00028 MedianFilter::~MedianFilter() {}
00029 
00030 MarSystem* MedianFilter::clone() const
00031 {
00032   return new MedianFilter(*this);
00033 }
00034 
00035 void MedianFilter::addControls()
00036 {
00037   addctrl("mrs_natural/WindowSize",10,ctrl_WindowSize_);
00038   ctrl_WindowSize_->setState(true);
00039   WindowSize_ = 10;
00040 }
00041 
00042 void MedianFilter::myUpdate(MarControlPtr inSender)
00043 {
00044   WindowSize_ = ctrl_WindowSize_->to<mrs_natural>();
00045   MarSystem::myUpdate(inSender);
00046 }
00047 
00048 void MedianFilter::myProcess(realvec& inVec, realvec& outVec)
00049 {
00050   // Each element in the input vector is replaced by the median of
00051   // the elements that fall in a window surrounding the element, defined as:
00052   // element index + [0,1.. N-1] - floor(N/2) with N, the size of the window.
00053 
00054   // Define moving window: once inserted,
00055   // the elements in the moving window are automatically sorted
00056   mrs_natural N = WindowSize_;
00057   multimap<mrs_real,mrs_natural,less<mrs_real> > theWindow;
00058   typedef multimap<mrs_real,mrs_natural,less<mrs_real> >::iterator iter;
00059   typedef pair<mrs_real,mrs_natural> element;
00060 
00061   // M = floor(N/2)
00062   mrs_natural M = (mrs_natural)floor((mrs_real)N/2.);
00063 
00064   // Initialize the moving window
00065   // For i=0, the window = [v(0), v(0),.. v(0),v(1),.. v(N-M)]
00066   for (int p=-M; p<=0; p++)
00067     theWindow.insert(element(inVec(0),p));
00068   for (int p=1; p<=N-M-1; p++)
00069     theWindow.insert(element(inVec(p),p));
00070 
00071   mrs_natural I = inVec.getSize();
00072   for (int i=0; i<I; ++i)
00073   {
00074     // Define to-be-inserted element
00075     element theNewOne(inVec(min(i+N-M,I-1)),i+N-M);
00076 
00077     // Search for median, insert and delete position
00078     int theOffset = -M;
00079 
00080     iter theMedian, theToDelete, theToInsert = theWindow.begin();
00081     for (iter theIter=theWindow.begin(); theIter!=theWindow.end(); theIter++)
00082     {
00083       if (theOffset == 0)
00084         theMedian = theIter;
00085       if (theIter->second == i-M)
00086         // Index i-M = first inserted element (oldest)
00087         theToDelete = theIter;
00088       if (theNewOne.first > theIter->first)
00089       {
00090         // Update theToInsert as long as theIter
00091         // is smaller than the to-be-inserted element
00092         theToInsert = theIter;
00093         theToInsert++;
00094       }
00095       theOffset++;
00096     }
00097 
00098     if (theToInsert == theToDelete)
00099       theToInsert++;
00100 
00101     outVec(i) = theMedian->first;
00102     theWindow.erase(theToDelete);
00103     theWindow.insert(theToInsert,theNewOne);
00104   }
00105 }