View Javadoc
1   package com.github.celldynamics.quimp.geom.filters;
2   
3   import java.awt.geom.Point2D;
4   import java.util.Arrays;
5   import java.util.Collection;
6   import java.util.List;
7   
8   import org.scijava.vecmath.Point2d;
9   import org.scijava.vecmath.Tuple2d;
10  
11  import com.github.celldynamics.quimp.plugin.utils.IPadArray;
12  import com.github.celldynamics.quimp.plugin.utils.QuimpDataConverter;
13  
14  /**
15   * Perform filtering on basic list of coordinates.
16   * 
17   * @author p.baniukiewicz
18   * @see OutlineProcessor
19   */
20  public class PointListProcessor {
21  
22    private QuimpDataConverter dt;
23  
24    /**
25     * Initialize object with list of points.
26     * 
27     * @param list to process
28     */
29    public PointListProcessor(List<? extends Tuple2d> list) {
30      dt = new QuimpDataConverter(list);
31    }
32  
33    /**
34     * Initialize object with list of points.
35     * 
36     * @param list to process
37     */
38    public PointListProcessor(Collection<? extends Point2D> list) {
39      dt = new QuimpDataConverter(list);
40    }
41  
42    /**
43     * Apply mean filter to list.
44     * 
45     * @param window size of mean window
46     * @param iters number of iterations
47     * @return Reference to this object
48     */
49    public PointListProcessor smoothMean(int window, int iters) {
50      double[] x = dt.getX();
51      double[] y = dt.getY();
52  
53      for (int i = 0; i < iters; i++) {
54        y = runningMean(y, window);
55        x = runningMean(x, window);
56      }
57      dt = new QuimpDataConverter(x, y);
58      return this;
59    }
60  
61    /**
62     * Apply median filter to list.
63     * 
64     * @param window size of median window
65     * @param iters number of iterations
66     * @return Reference to this object
67     */
68    public PointListProcessor smoothMedian(int window, int iters) {
69      double[] x = dt.getX();
70      double[] y = dt.getY();
71  
72      for (int i = 0; i < iters; i++) {
73        y = runningMedian(y, window);
74        x = runningMedian(x, window);
75      }
76      dt = new QuimpDataConverter(x, y);
77      return this;
78    }
79  
80    /**
81     * Return modified list.
82     * 
83     * @return list after processing
84     */
85    public List<Point2d> getList() {
86      return dt.getList();
87    }
88  
89    /**
90     * Return modified awt double list.
91     * 
92     * @return list after processing (doubles)
93     */
94    public List<Point2D> getListAwtDouble() {
95      return dt.getListofDoublePoints();
96    }
97  
98    /**
99     * Return modified awt int list.
100    * 
101    * @return list after processing (integers)
102    */
103   public List<Point2D> getListAwtInt() {
104     return dt.getListofIntPoints();
105   }
106 
107   /**
108    * Return underlying DataConverter instance.
109    * 
110    * @return DataConverter
111    */
112   public QuimpDataConverter getDataConverterInstance() {
113     return dt;
114   }
115 
116   /**
117    * Running mean on input array.
118    * 
119    * @param data data to filter, can be empty
120    * @param windowSize odd window size
121    * @return Filtered array
122    */
123   public static double[] runningMean(double[] data, int windowSize) {
124     if (windowSize % 2 == 0) {
125       throw new IllegalArgumentException("Window must be odd");
126     }
127     double[] ret = new double[data.length];
128     int cp = windowSize / 2; // left and right range of window
129 
130     for (int c = 0; c < data.length; c++) { // for every point in data
131       double mean = 0;
132       for (int cc = c - cp; cc <= c + cp; cc++) { // points in range c-2 - c+2 (for window=5)
133         int indexTmp = IPadArray.getIndex(data.length, cc, IPadArray.CIRCULARPAD);
134         mean += data[indexTmp];
135       }
136       mean = mean / windowSize;
137       ret[c] = mean; // remember result
138     }
139     return ret;
140   }
141 
142   /**
143    * Running median on input array.
144    * 
145    * @param data data to filter, can be empty
146    * @param windowSize odd window size
147    * @return Filtered array
148    */
149   public static double[] runningMedian(double[] data, int windowSize) {
150     if (windowSize % 2 == 0) {
151       throw new IllegalArgumentException("Window must be odd");
152     }
153     double[] ret = new double[data.length];
154     int cp = windowSize / 2; // left and right range of window
155     double[] xs = new double[windowSize]; // window point
156     int l = 0;
157 
158     for (int c = 0; c < data.length; c++) { // for every point in data
159       l = 0;
160       for (int cc = c - cp; cc <= c + cp; cc++) { // collect points in range c-2 c-1 c-0 c+1 c+2
161         int indexTmp = IPadArray.getIndex(data.length, cc, IPadArray.CIRCULARPAD);
162         xs[l] = data[indexTmp];
163         l++;
164       }
165       // get median
166       Arrays.sort(xs);
167       ret[c] = xs[cp];
168     }
169     return ret;
170   }
171 }