Home  · Classes  · Annotated Classes  · Modules  · Members  · Namespaces  · Related Pages

MorphologicalFilter.h

Go to the documentation of this file.
00001 // --------------------------------------------------------------------------
00002 //                   OpenMS -- Open-Source Mass Spectrometry
00003 // --------------------------------------------------------------------------
00004 // Copyright The OpenMS Team -- Eberhard Karls University Tuebingen,
00005 // ETH Zurich, and Freie Universitaet Berlin 2002-2012.
00006 //
00007 // This software is released under a three-clause BSD license:
00008 //  * Redistributions of source code must retain the above copyright
00009 //    notice, this list of conditions and the following disclaimer.
00010 //  * Redistributions in binary form must reproduce the above copyright
00011 //    notice, this list of conditions and the following disclaimer in the
00012 //    documentation and/or other materials provided with the distribution.
00013 //  * Neither the name of any author or any participating institution
00014 //    may be used to endorse or promote products derived from this software
00015 //    without specific prior written permission.
00016 // For a full list of authors, refer to the file AUTHORS.
00017 // --------------------------------------------------------------------------
00018 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021 // ARE DISCLAIMED. IN NO EVENT SHALL ANY OF THE AUTHORS OR THE CONTRIBUTING
00022 // INSTITUTIONS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00023 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00024 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
00025 // OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
00026 // WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
00027 // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
00028 // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029 //
00030 // --------------------------------------------------------------------------
00031 // $Maintainer: Clemens Groepl $
00032 // $Authors: $
00033 // --------------------------------------------------------------------------
00034 
00035 #ifndef OPENMS_FILTERING_BASELINE_MORPHOLOGICALFILTER_H
00036 #define OPENMS_FILTERING_BASELINE_MORPHOLOGICALFILTER_H
00037 
00038 #include <OpenMS/CONCEPT/ProgressLogger.h>
00039 #include <OpenMS/DATASTRUCTURES/DefaultParamHandler.h>
00040 #include <OpenMS/KERNEL/MSExperiment.h>
00041 #include <OpenMS/MATH/MISC/MathFunctions.h>
00042 
00043 #include <algorithm>
00044 #include <iterator>
00045 
00046 namespace OpenMS
00047 {
00048 
00049   namespace Internal
00050   {
00057     template <typename IteratorT>
00058     class /* OPENMS_DLLAPI */ IntensityIteratorWrapper :
00059       public std::iterator<std::forward_iterator_tag, typename IteratorT::value_type::IntensityType>
00060     {
00061 public:
00062       typedef typename IteratorT::value_type::IntensityType value_type;
00063       typedef typename IteratorT::value_type::IntensityType & reference;
00064       typedef typename IteratorT::value_type::IntensityType * pointer;
00065       typedef typename IteratorT::difference_type difference_type;
00066 
00067       IntensityIteratorWrapper(const IteratorT & rhs) :
00068         base(rhs)
00069       {
00070       }
00071 
00072       value_type operator*()
00073       {
00074         return base->getIntensity();
00075       }
00076 
00077       template <typename IndexT>
00078       value_type operator[](const IndexT & index)
00079       {
00080         return base[index].getIntensity();
00081       }
00082 
00083       difference_type operator-(IntensityIteratorWrapper & rhs) const
00084       {
00085         return base - rhs.base;
00086       }
00087 
00088       IntensityIteratorWrapper & operator++()
00089       {
00090         ++base;
00091         return *this;
00092       }
00093 
00094       IntensityIteratorWrapper operator++(int)
00095       {
00096         IteratorT tmp = *this;
00097         ++(*this);
00098         return tmp;
00099       }
00100 
00101       bool operator==(const IntensityIteratorWrapper & rhs) const
00102       {
00103         return base == rhs.base;
00104       }
00105 
00106       bool operator!=(const IntensityIteratorWrapper & rhs) const
00107       {
00108         return base != rhs.base;
00109       }
00110 
00111 protected:
00112       IteratorT base;
00113     };
00114 
00116     template <typename IteratorT>
00117     IntensityIteratorWrapper<IteratorT> intensityIteratorWrapper(const IteratorT & rhs)
00118     {
00119       return IntensityIteratorWrapper<IteratorT>(rhs);
00120     }
00121 
00122   }
00123 
00159   class OPENMS_DLLAPI MorphologicalFilter :
00160     public ProgressLogger,
00161     public DefaultParamHandler
00162   {
00163 public:
00164 
00166     MorphologicalFilter() :
00167       ProgressLogger(),
00168       DefaultParamHandler("MorphologicalFilter"),
00169       struct_size_in_datapoints_(0)
00170     {
00171       //structuring element
00172       defaults_.setValue("struc_elem_length", 3.0, "Length of the structuring element. This should be wider than the expected peak width.");
00173       defaults_.setValue("struc_elem_unit", "Thomson", "The unit of the 'struct_elem_length'.");
00174       defaults_.setValidStrings("struc_elem_unit", StringList::create("Thomson,DataPoints"));
00175       //methods
00176       defaults_.setValue("method", "tophat", "Method to use, the default is 'tophat'.  Do not change this unless you know what you are doing.  The other methods may be useful for tuning the parameters, see the class documentation of MorpthologicalFilter.");
00177       defaults_.setValidStrings("method", StringList::create("identity,erosion,dilation,opening,closing,gradient,tophat,bothat,erosion_simple,dilation_simple"));
00178 
00179       defaultsToParam_();
00180     }
00181 
00183     virtual ~MorphologicalFilter()
00184     {
00185     }
00186 
00198     template <typename InputIterator, typename OutputIterator>
00199     void filterRange(InputIterator input_begin, InputIterator input_end, OutputIterator output_begin)
00200     {
00201       // the buffer is static only to avoid reallocation
00202       static std::vector<typename InputIterator::value_type> buffer;
00203       const UInt size = input_end - input_begin;
00204 
00205       //determine the struct size in data points if not already set
00206       if (struct_size_in_datapoints_ == 0)
00207       {
00208         struct_size_in_datapoints_ = (UInt)(DoubleReal)param_.getValue("struc_elem_length");
00209       }
00210 
00211       //apply the filtering
00212       String method = param_.getValue("method");
00213       if (method == "identity")
00214       {
00215         std::copy(input_begin, input_end, output_begin);
00216       }
00217       else if (method == "erosion")
00218       {
00219         applyErosion_(struct_size_in_datapoints_, input_begin, input_end, output_begin);
00220       }
00221       else if (method == "dilation")
00222       {
00223         applyDilation_(struct_size_in_datapoints_, input_begin, input_end, output_begin);
00224       }
00225       else if (method == "opening")
00226       {
00227         if (buffer.size() < size) buffer.resize(size);
00228         applyErosion_(struct_size_in_datapoints_, input_begin, input_end, buffer.begin());
00229         applyDilation_(struct_size_in_datapoints_, buffer.begin(), buffer.begin() + size, output_begin);
00230       }
00231       else if (method == "closing")
00232       {
00233         if (buffer.size() < size) buffer.resize(size);
00234         applyDilation_(struct_size_in_datapoints_, input_begin, input_end, buffer.begin());
00235         applyErosion_(struct_size_in_datapoints_, buffer.begin(), buffer.begin() + size, output_begin);
00236       }
00237       else if (method == "gradient")
00238       {
00239         if (buffer.size() < size) buffer.resize(size);
00240         applyErosion_(struct_size_in_datapoints_, input_begin, input_end, buffer.begin());
00241         applyDilation_(struct_size_in_datapoints_, input_begin, input_end, output_begin);
00242         for (UInt i = 0; i < size; ++i) output_begin[i] -= buffer[i];
00243       }
00244       else if (method == "tophat")
00245       {
00246         if (buffer.size() < size) buffer.resize(size);
00247         applyErosion_(struct_size_in_datapoints_, input_begin, input_end, buffer.begin());
00248         applyDilation_(struct_size_in_datapoints_, buffer.begin(), buffer.begin() + size, output_begin);
00249         for (UInt i = 0; i < size; ++i) output_begin[i] = input_begin[i] - output_begin[i];
00250       }
00251       else if (method == "bothat")
00252       {
00253         if (buffer.size() < size) buffer.resize(size);
00254         applyDilation_(struct_size_in_datapoints_, input_begin, input_end, buffer.begin());
00255         applyErosion_(struct_size_in_datapoints_, buffer.begin(), buffer.begin() + size, output_begin);
00256         for (UInt i = 0; i < size; ++i) output_begin[i] = input_begin[i] - output_begin[i];
00257       }
00258       else if (method == "erosion_simple")
00259       {
00260         applyErosionSimple_(struct_size_in_datapoints_, input_begin, input_end, output_begin);
00261       }
00262       else if (method == "dilation_simple")
00263       {
00264         applyDilationSimple_(struct_size_in_datapoints_, input_begin, input_end, output_begin);
00265       }
00266 
00267       struct_size_in_datapoints_ = 0;
00268     }
00269 
00284     template <typename PeakType>
00285     void filter(MSSpectrum<PeakType> & spectrum)
00286     {
00287       //make sure the right peak type is set
00288       spectrum.setType(SpectrumSettings::RAWDATA);
00289 
00290       //Abort if there is nothing to do
00291       if (spectrum.size() <= 1) return;
00292 
00293       //Determine structuring element size in datapoints (depending on the unit)
00294       if ((String)(param_.getValue("struc_elem_unit")) == "Thomson")
00295       {
00296         struct_size_in_datapoints_ =
00297           UInt(
00298             ceil(
00299               (DoubleReal)(param_.getValue("struc_elem_length"))
00300               *
00301               DoubleReal(spectrum.size() - 1)
00302               /
00303               (spectrum.back().getMZ() - spectrum.begin()->getMZ())
00304               )
00305             );
00306       }
00307       else
00308       {
00309         struct_size_in_datapoints_ = (UInt)(DoubleReal)param_.getValue("struc_elem_length");
00310       }
00311       //make it odd (needed for the algorithm)
00312       if (!Math::isOdd(struct_size_in_datapoints_)) ++struct_size_in_datapoints_;
00313 
00314       //apply the filtering and overwrite the input data
00315       std::vector<typename PeakType::IntensityType> output(spectrum.size());
00316       filterRange(Internal::intensityIteratorWrapper(spectrum.begin()),
00317                   Internal::intensityIteratorWrapper(spectrum.end()),
00318                   output.begin()
00319                   );
00320 
00321       //overwrite output with data
00322       for (Size i = 0; i < spectrum.size(); ++i)
00323       {
00324         spectrum[i].setIntensity(output[i]);
00325       }
00326     }
00327 
00334     template <typename PeakType>
00335     void filterExperiment(MSExperiment<PeakType> & exp)
00336     {
00337       startProgress(0, exp.size(), "filtering baseline");
00338       for (UInt i = 0; i < exp.size(); ++i)
00339       {
00340         filter(exp[i]);
00341         setProgress(i);
00342       }
00343       endProgress();
00344     }
00345 
00346 protected:
00347 
00349     UInt struct_size_in_datapoints_;
00350 
00355     template <typename InputIterator, typename OutputIterator>
00356     void applyErosion_(Int struc_size, InputIterator input, InputIterator input_end, OutputIterator output)
00357     {
00358       typedef typename InputIterator::value_type ValueType;
00359       const Int size = input_end - input;
00360       const Int struc_size_half = struc_size / 2;           // yes, integer division
00361 
00362       static std::vector<ValueType> buffer;
00363       if (Int(buffer.size()) < struc_size) buffer.resize(struc_size);
00364 
00365       Int anchor;           // anchoring position of the current block
00366       Int i;                // index relative to anchor, used for 'for' loops
00367       Int ii = 0;           // input index
00368       Int oi = 0;           // output index
00369       ValueType current;           // current value
00370 
00371       // we just can't get the case distinctions right in these cases, resorting to simple method.
00372       if (size <= struc_size || size <= 5)
00373       {
00374         applyErosionSimple_(struc_size, input, input_end, output);
00375         return;
00376       }
00377       {
00378         // lower margin area
00379         current = input[0];
00380         for (++ii; ii < struc_size_half; ++ii) if (current > input[ii]) current = input[ii];
00381         for (; ii < std::min(Int(struc_size), size); ++ii, ++oi)
00382         {
00383           if (current > input[ii]) current = input[ii];
00384           output[oi] = current;
00385         }
00386       }
00387       {
00388         // middle (main) area
00389         for (anchor = struc_size;
00390              anchor <= size - struc_size;
00391              anchor += struc_size
00392              )
00393         {
00394           ii = anchor;
00395           current = input[ii];
00396           buffer[0] = current;
00397           for (i = 1; i < struc_size; ++i, ++ii)
00398           {
00399             if (current > input[ii]) current = input[ii];
00400             buffer[i] = current;
00401           }
00402           ii = anchor - 1;
00403           oi = ii + struc_size_half;
00404           current = input[ii];
00405           for (i = 1; i < struc_size; ++i, --ii, --oi)
00406           {
00407             if (current > input[ii]) current = input[ii];
00408             output[oi] = std::min(buffer[struc_size - i], current);
00409           }
00410           if (current > input[ii]) current = input[ii];
00411           output[oi] = current;
00412         }
00413       }
00414       {
00415         // higher margin area
00416         ii = size - 1;
00417         oi = ii;
00418         current = input[ii];
00419         for (--ii; ii >= size - struc_size_half; --ii) if (current > input[ii]) current = input[ii];
00420         for (; ii >= std::max(size - Int(struc_size), 0); --ii, --oi)
00421         {
00422           if (current > input[ii]) current = input[ii];
00423           output[oi] = current;
00424         }
00425         anchor = size - struc_size;
00426         ii = anchor;
00427         current = input[ii];
00428         buffer[0] = current;
00429         for (i = 1; i < struc_size; ++i, ++ii)
00430         {
00431           if (current > input[ii]) current = input[ii];
00432           buffer[i] = current;
00433         }
00434         ii = anchor - 1;
00435         oi = ii + struc_size_half;
00436         current = input[ii];
00437         for (i = 1; (ii >= 0) && (i < struc_size); ++i, --ii, --oi)
00438         {
00439           if (current > input[ii]) current = input[ii];
00440           output[oi] = std::min(buffer[struc_size - i], current);
00441         }
00442         if (ii >= 0)
00443         {
00444           if (current > input[ii]) current = input[ii];
00445           output[oi] = current;
00446         }
00447       }
00448       return;
00449     }
00450 
00455     template <typename InputIterator, typename OutputIterator>
00456     void applyDilation_(Int struc_size, InputIterator input, InputIterator input_end, OutputIterator output)
00457     {
00458       typedef typename InputIterator::value_type ValueType;
00459       const Int size = input_end - input;
00460       const Int struc_size_half = struc_size / 2;           // yes, integer division
00461 
00462       static std::vector<ValueType> buffer;
00463       if (Int(buffer.size()) < struc_size) buffer.resize(struc_size);
00464 
00465       Int anchor;           // anchoring position of the current block
00466       Int i;                // index relative to anchor, used for 'for' loops
00467       Int ii = 0;           // input index
00468       Int oi = 0;           // output index
00469       ValueType current;           // current value
00470 
00471       // we just can't get the case distinctions right in these cases, resorting to simple method.
00472       if (size <= struc_size || size <= 5)
00473       {
00474         applyDilationSimple_(struc_size, input, input_end, output);
00475         return;
00476       }
00477       {
00478         // lower margin area
00479         current = input[0];
00480         for (++ii; ii < struc_size_half; ++ii) if (current < input[ii]) current = input[ii];
00481         for (; ii < std::min(Int(struc_size), size); ++ii, ++oi)
00482         {
00483           if (current < input[ii]) current = input[ii];
00484           output[oi] = current;
00485         }
00486       }
00487       {
00488         // middle (main) area
00489         for (anchor = struc_size;
00490              anchor <= size - struc_size;
00491              anchor += struc_size
00492              )
00493         {
00494           ii = anchor;
00495           current = input[ii];
00496           buffer[0] = current;
00497           for (i = 1; i < struc_size; ++i, ++ii)
00498           {
00499             if (current < input[ii]) current = input[ii];
00500             buffer[i] = current;
00501           }
00502           ii = anchor - 1;
00503           oi = ii + struc_size_half;
00504           current = input[ii];
00505           for (i = 1; i < struc_size; ++i, --ii, --oi)
00506           {
00507             if (current < input[ii]) current = input[ii];
00508             output[oi] = std::max(buffer[struc_size - i], current);
00509           }
00510           if (current < input[ii]) current = input[ii];
00511           output[oi] = current;
00512         }
00513       }
00514       {
00515         // higher margin area
00516         ii = size - 1;
00517         oi = ii;
00518         current = input[ii];
00519         for (--ii; ii >= size - struc_size_half; --ii) if (current < input[ii]) current = input[ii];
00520         for (; ii >= std::max(size - Int(struc_size), 0); --ii, --oi)
00521         {
00522           if (current < input[ii]) current = input[ii];
00523           output[oi] = current;
00524         }
00525         anchor = size - struc_size;
00526         ii = anchor;
00527         current = input[ii];
00528         buffer[0] = current;
00529         for (i = 1; i < struc_size; ++i, ++ii)
00530         {
00531           if (current < input[ii]) current = input[ii];
00532           buffer[i] = current;
00533         }
00534         ii = anchor - 1;
00535         oi = ii + struc_size_half;
00536         current = input[ii];
00537         for (i = 1; (ii >= 0) && (i < struc_size); ++i, --ii, --oi)
00538         {
00539           if (current < input[ii]) current = input[ii];
00540           output[oi] = std::max(buffer[struc_size - i], current);
00541         }
00542         if (ii >= 0)
00543         {
00544           if (current < input[ii]) current = input[ii];
00545           output[oi] = current;
00546         }
00547       }
00548       return;
00549     }
00550 
00552     template <typename InputIterator, typename OutputIterator>
00553     void applyErosionSimple_(Int struc_size, InputIterator input_begin, InputIterator input_end, OutputIterator output_begin)
00554     {
00555       typedef typename InputIterator::value_type ValueType;
00556       const int size = input_end - input_begin;
00557       const Int struc_size_half = struc_size / 2;           // yes integer division
00558       for (Int index = 0; index < size; ++index)
00559       {
00560         Int start = std::max(0, index - struc_size_half);
00561         Int stop  = std::min(size - 1, index + struc_size_half);
00562         ValueType value = input_begin[start];
00563         for (Int i = start + 1; i <= stop; ++i) if (value > input_begin[i]) value = input_begin[i];
00564         output_begin[index] = value;
00565       }
00566       return;
00567     }
00568 
00570     template <typename InputIterator, typename OutputIterator>
00571     void applyDilationSimple_(Int struc_size, InputIterator input_begin, InputIterator input_end, OutputIterator output_begin)
00572     {
00573       typedef typename InputIterator::value_type ValueType;
00574       const int size = input_end - input_begin;
00575       const Int struc_size_half = struc_size / 2;           // yes integer division
00576       for (Int index = 0; index < size; ++index)
00577       {
00578         Int start = std::max(0, index - struc_size_half);
00579         Int stop   = std::min(size - 1, index + struc_size_half);
00580         ValueType value = input_begin[start];
00581         for (Int i = start + 1; i <= stop; ++i) if (value < input_begin[i]) value = input_begin[i];
00582         output_begin[index] = value;
00583       }
00584       return;
00585     }
00586 
00587 private:
00588 
00590     MorphologicalFilter(const MorphologicalFilter & source);
00591 
00592   };
00593 
00594 } // namespace OpenMS
00595 
00596 #endif

OpenMS / TOPP release 1.10.0 Documentation generated on Thu Mar 7 2013 09:42:42 using doxygen 1.7.1