Program Listing for File median.hpp

Return to documentation for file (/tmp/ws/src/filters/include/filters/median.hpp)

/*
 * Copyright (c) 2009, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef FILTERS__MEDIAN_HPP_
#define FILTERS__MEDIAN_HPP_

#include <memory>
#include <utility>
#include <vector>

#include "filters/filter_base.hpp"

#include "filters/realtime_circular_buffer.hpp"


/*********************************************************************/
/*
 * Algorithm from N. Wirth's book, implementation by N. Devillard.
 * This code in public domain.
 */

namespace filters
{

/*---------------------------------------------------------------------------
  Function : kth_smallest()
  In : array of elements, # of elements in the array, rank k
  Out : one element
  Job : find the kth smallest element in the array
  Notice : use the median() macro defined below to get the median.
  Reference:
  Author: Wirth, Niklaus
  Title: Algorithms + data structures = programs
  Publisher: Englewood Cliffs: Prentice-Hall, 1976
  Physical description: 366 p.
  Series: Prentice-Hall Series in Automatic Computation
  ---------------------------------------------------------------------------*/
template<typename elem_type>
elem_type kth_smallest(elem_type * a, int n, int k)
{
  int i, j, l, m;
  elem_type x;
  l = 0; m = n - 1;
  while (l < m) {
    x = a[k];
    i = l;
    j = m;
    do {
      while (a[i] < x) {i++;}
      while (x < a[j]) {j--;}
      if (i <= j) {
        std::swap(a[i], a[j]);
        i++; j--;
      }
    } while (i <= j);
    if (j < k) {l = i;}
    if (k < i) {m = j;}
  }
  return a[k];
}

template<typename elem_type>
elem_type median(elem_type * a, int n)
{
  return kth_smallest(a, n, (((n) & 1) ? ((n) / 2) : (((n) / 2) - 1)));
}

template<typename T>
class MedianFilter : public filters::FilterBase<T>
{
public:
  MedianFilter();

  ~MedianFilter() override;

  bool configure() override;

  bool update(const T & data_in, T & data_out) override;

protected:
  std::vector<T> temp_storage_;
  std::unique_ptr<RealtimeCircularBuffer<T>> data_storage_;

  T temp;  // used for preallocation and copying from non vector source

  size_t number_of_observations_;
};

template<typename T>
MedianFilter<T>::MedianFilter()
: number_of_observations_(0)
{
}

template<typename T>
MedianFilter<T>::~MedianFilter()
{
}


template<typename T>
bool MedianFilter<T>::configure()
{
  if (!FilterBase<T>::getParam("number_of_observations", number_of_observations_)) {
    RCLCPP_ERROR(this->logging_interface_->get_logger(), "MedianFilter was not given params.\n");
    return false;
  }

  data_storage_.reset(new RealtimeCircularBuffer<T>(number_of_observations_, temp));
  temp_storage_.resize(number_of_observations_);

  return true;
}

template<typename T>
bool MedianFilter<T>::update(const T & data_in, T & data_out)
{
  if (!FilterBase<T>::configured_) {
    return false;
  }

  data_storage_->push_back(data_in);

  size_t length = data_storage_->size();
  for (size_t row = 0; row < length; ++row) {
    temp_storage_[row] = (*data_storage_)[row];
  }
  data_out = median(&temp_storage_[0], length);

  return true;
}

template<typename T>
class MultiChannelMedianFilter : public filters::MultiChannelFilterBase<T>
{
public:
  MultiChannelMedianFilter();

  ~MultiChannelMedianFilter() override;

  bool configure() override;

  bool update(const std::vector<T> & data_in, std::vector<T> & data_out) override;

protected:
  std::vector<T> temp_storage_;
  std::unique_ptr<RealtimeCircularBuffer<std::vector<T>>> data_storage_;

  std::vector<T> temp;  // used for preallocation and copying from non vector source

  size_t number_of_observations_;
};

template<typename T>
MultiChannelMedianFilter<T>::MultiChannelMedianFilter()
: number_of_observations_(0)
{
}

template<typename T>
MultiChannelMedianFilter<T>::~MultiChannelMedianFilter()
{
}

template<typename T>
bool MultiChannelMedianFilter<T>::configure()
{
  if (!FilterBase<T>::getParam("number_of_observations", number_of_observations_)) {
    RCLCPP_ERROR(
      this->logging_interface_->get_logger(), "MultiChannelMedianFilter was not given params.\n");
    return false;
  }

  temp.resize(this->number_of_channels_);
  data_storage_.reset(new RealtimeCircularBuffer<std::vector<T>>(number_of_observations_, temp));
  temp_storage_.resize(number_of_observations_);

  return true;
}

template<typename T>
bool MultiChannelMedianFilter<T>::update(const std::vector<T> & data_in, std::vector<T> & data_out)
{
  if (data_in.size() != this->number_of_channels_ || data_out.size() != this->number_of_channels_) {
    return false;
  }
  if (!FilterBase<T>::configured_) {
    return false;
  }

  data_storage_->push_back(data_in);

  size_t length = data_storage_->size();
  for (size_t i = 0; i < this->number_of_channels_; ++i) {
    for (size_t row = 0; row < length; ++row) {
      temp_storage_[row] = (*data_storage_)[row][i];
    }
    data_out[i] = median(&temp_storage_[0], length);
  }

  return true;
}

}  // namespace filters

#endif  // FILTERS__MEDIAN_HPP_