package com.dronecontrol.perceptual.components.filters; import com.google.common.base.Function; import com.google.common.collect.Lists; import com.dronecontrol.perceptual.data.body.Coordinate; import java.util.List; public class BilateralFilter implements Filter { public static final int SIGMA_T = 5; public static final double SIGMA_U = 0.03; private static final int HISTORY_SIZE = 5 * SIGMA_T; private final List<Coordinate> previousCoordinates; public BilateralFilter() { previousCoordinates = Lists.newLinkedList(); } @Override public Coordinate getFilteredCoordinate(Coordinate coordinate) { if (coordinate == null) { return calculateSmoothedCoordinate(); } addCoordinateToActiveCoordinates(coordinate); return calculateSmoothedCoordinate(); } private Coordinate calculateSmoothedCoordinate() { if (previousCoordinates.size() == 0) { return null; } float x = (float) getValue(Lists.transform(previousCoordinates, new Function<Coordinate, Double>() { @Override public Double apply(Coordinate coordinate) { return (double) coordinate.getX(); } })); float y = (float) getValue(Lists.transform(previousCoordinates, new Function<Coordinate, Double>() { @Override public Double apply(Coordinate coordinate) { return (double) coordinate.getY(); } })); float z = (float) getValue(Lists.transform(previousCoordinates, new Function<Coordinate, Double>() { @Override public Double apply(Coordinate coordinate) { return (double) coordinate.getZ(); } })); return new Coordinate(x, y, z); } private double getValue(List<Double> values) { double numerator = 0; double denominator = 0; int n = values.size(); double currentValue = values.get(values.size() - 1); for (int i = 0; i < values.size(); i++) { double value = values.get(i); double exponent = (n - i) * (n - i) / (2.0 * SIGMA_T * SIGMA_T) + Math.pow(currentValue - value, 2.0) / (2 * SIGMA_U * SIGMA_U); double weight = Math.exp(-exponent); numerator += weight * value; denominator += weight; } return numerator / denominator; } private void addCoordinateToActiveCoordinates(Coordinate coordinate) { previousCoordinates.add(coordinate); while (previousCoordinates.size() > HISTORY_SIZE) { previousCoordinates.remove(0); } } }