View Javadoc
1   package com.github.celldynamics.quimp.plugin.protanalysis;
2   
3   import java.awt.Polygon;
4   import java.awt.geom.Point2D;
5   import java.util.Collection;
6   
7   import org.apache.commons.lang3.NotImplementedException;
8   import org.scijava.vecmath.Point2d;
9   import org.slf4j.Logger;
10  import org.slf4j.LoggerFactory;
11  
12  import com.github.celldynamics.quimp.plugin.qanalysis.STmap;
13  
14  import ij.plugin.filter.MaximumFinder;
15  import ij.process.ByteProcessor;
16  import ij.process.ImageProcessor;
17  
18  /**
19   * Calculate maxima for image.
20   * 
21   * <p>Support various methods of finding maxima in ImageJ image.
22   * 
23   * @author p.baniukiewicz
24   *
25   */
26  public class MaximaFinder {
27  
28    /**
29     * The Constant LOGGER.
30     */
31    static final Logger LOGGER = LoggerFactory.getLogger(MaximaFinder.class.getName());
32    private ImageProcessor ip;
33    private Polygon maxima; // found maxima as polygon
34  
35    // /**
36    // * Indicate that image processor has been rotated. By default x coordinate should be frame, y
37    // * index. But For visualisation is better to rotate image to have longer axis on bottom.
38    // * By default TrackVisualisation.Map.Map(String, float[][]) rotates image.
39    // */
40    // public boolean ROTATED = true;
41  
42    /**
43     * Construct MaximaFinder object.
44     * 
45     * @param ip Image processor with image to analyse.
46     */
47    public MaximaFinder(ImageProcessor ip) {
48      this.ip = ip;
49      maxima = null;
50    }
51  
52    /**
53     * Compute maxima using ImageJ procedure.
54     * 
55     * @param tolerance tolerance
56     * @see <a href=
57     *      "link">https://rsb.info.nih.gov/ij/developer/api/ij/plugin/filter/MaximumFinder.html</a>
58     */
59    public void computeMaximaIJ(double tolerance) {
60      MaximumFinder mf = new MaximumFinder();
61      // maxima = mf.getMaxima(ip, tolerance, false); // stopped working for 1.52n
62      ByteProcessor ret = mf.findMaxima(ip, tolerance, MaximumFinder.SINGLE_POINTS, false);
63      maxima = new Polygon();
64      for (int x = 0; x < ret.getWidth(); ++x) {
65        for (int y = 0; y < ret.getHeight(); ++y) {
66          if (ret.get(x, y) > 0) {
67            maxima.addPoint(x, y);
68          }
69        }
70      }
71      LOGGER.debug("Found maxima: " + maxima.npoints);
72    }
73  
74    /**
75     * Compute maxima from image where points different from background stand for location of maxima
76     * in <tt>ip</tt>.
77     * 
78     * <p>This method can be used for restoring maxima in compatible format supported by this class
79     * from other image created outside.
80     * 
81     * @param mximaMap map of maxima in image used for constructing this object
82     */
83    public void computeMaximaImage(ImageProcessor mximaMap) {
84      // TODO finish computeMaximaImage method
85      throw new NotImplementedException("Not implemented");
86    }
87  
88    /**
89     * Set maxima for this object.
90     * 
91     * <p>This can be used for setting maxima explicitly. Any use of {@link #computeMaximaIJ(double)}
92     * or
93     * {@link #computeMaximaImage(ImageProcessor)} will override these values.
94     * 
95     * @param maxi list of maxima coordinates.
96     */
97    public void setMaximad(Collection<Point2d> maxi) {
98      maxima = new Polygon();
99      for (Point2d p : maxi) {
100       maxima.addPoint((int) p.getX(), (int) p.getY());
101     }
102 
103   }
104 
105   /**
106    * Set maxima for this object.
107    * 
108    * <p>This can be used for setting maxima explicitly. Any use of {@link #computeMaximaIJ(double)}
109    * or
110    * {@link #computeMaximaImage(ImageProcessor)} will override these values.
111    * 
112    * @param maxi list of maxima coordinates. Note that these values should relate to image
113    *        coordinates (integer row and column) even if axis labels are different. Both coordinates
114    *        are used for indexing {@link STmap}.
115    */
116   public void setMaxima(Collection<? extends Point2D> maxi) {
117     maxima = new Polygon();
118     for (Point2D p : maxi) {
119       maxima.addPoint((int) p.getX(), (int) p.getY());
120     }
121   }
122 
123   /**
124    * Return values corresponding to indexes returned by getMaxima.
125    * 
126    * <p>Must be called after getMaxima.
127    * 
128    * @return Maxima in order of indexes returned by getMaxima.
129    */
130   public double[] getMaxValues() {
131     if (maxima == null) {
132       return new double[0];
133     }
134     double[] ret = new double[maxima.npoints];
135     for (int i = 0; i < maxima.npoints; i++) {
136       ret[i] = ip.getf(maxima.xpoints[i], maxima.ypoints[i]);
137     }
138     return ret;
139   }
140 
141   /**
142    * getMaxima.
143    * 
144    * @return Return maxima found by {@link #computeMaximaIJ(double)}. The coordinates depend on
145    *         orientation of input image. For typical application like analysis of motility map, x
146    *         axis stands for frames and y-axis for outline indexes.
147    */
148   public Polygon getMaxima() {
149     if (maxima == null) {
150       return new Polygon();
151     }
152     return maxima;
153   }
154 
155   /**
156    * Number of points found.
157    * 
158    * @return Number of points found.
159    */
160   public int getMaximaNumber() {
161     if (maxima == null) {
162       return 0;
163     }
164     return maxima.npoints;
165   }
166 }