00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
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 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
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
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
00202 static std::vector<typename InputIterator::value_type> buffer;
00203 const UInt size = input_end - input_begin;
00204
00205
00206 if (struct_size_in_datapoints_ == 0)
00207 {
00208 struct_size_in_datapoints_ = (UInt)(DoubleReal)param_.getValue("struc_elem_length");
00209 }
00210
00211
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
00288 spectrum.setType(SpectrumSettings::RAWDATA);
00289
00290
00291 if (spectrum.size() <= 1) return;
00292
00293
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
00312 if (!Math::isOdd(struct_size_in_datapoints_)) ++struct_size_in_datapoints_;
00313
00314
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
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;
00361
00362 static std::vector<ValueType> buffer;
00363 if (Int(buffer.size()) < struc_size) buffer.resize(struc_size);
00364
00365 Int anchor;
00366 Int i;
00367 Int ii = 0;
00368 Int oi = 0;
00369 ValueType current;
00370
00371
00372 if (size <= struc_size || size <= 5)
00373 {
00374 applyErosionSimple_(struc_size, input, input_end, output);
00375 return;
00376 }
00377 {
00378
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
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
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;
00461
00462 static std::vector<ValueType> buffer;
00463 if (Int(buffer.size()) < struc_size) buffer.resize(struc_size);
00464
00465 Int anchor;
00466 Int i;
00467 Int ii = 0;
00468 Int oi = 0;
00469 ValueType current;
00470
00471
00472 if (size <= struc_size || size <= 5)
00473 {
00474 applyDilationSimple_(struc_size, input, input_end, output);
00475 return;
00476 }
00477 {
00478
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
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
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;
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;
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 }
00595
00596 #endif