View Javadoc
1   package com.github.celldynamics.quimp.plugin.randomwalk;
2   
3   import ij.IJ;
4   import ij.ImagePlus;
5   import ij.process.BinaryProcessor;
6   import ij.process.ImageProcessor;
7   
8   /**
9    * Provide sets of binary filters.
10   * 
11   * <p>Returned image is converted to BinaryProcessor and it is copy of input image.
12   * 
13   * @author p.baniukiewicz
14   *
15   */
16  public abstract class BinaryFilters {
17  
18    /**
19     * Filters available in this class.
20     * 
21     * @author p.baniukiewicz
22     *
23     */
24    public static enum Filters {
25      /**
26       * Do nothing.
27       */
28      NONE,
29      /**
30       * Simple filtering.
31       * 
32       * @see SimpleMorpho
33       */
34      SIMPLE,
35      /**
36       * Small median filter.
37       * 
38       * @see MedianMorpho
39       */
40      MEDIAN
41    }
42  
43    /**
44     * Available binary operations.
45     * 
46     * @author p.baniukiewicz
47     * @see BinaryFilters#iterateMorphological(ImageProcessor, MorphoOperations, double)
48     */
49    public static enum MorphoOperations {
50      /**
51       * Denote ERODE operation.
52       */
53      ERODE,
54      /**
55       * Denote DILATE operation.
56       */
57      DILATE,
58      /**
59       * Run IJ open macro.
60       */
61      IJOPEN
62    }
63  
64    /**
65     * Factory of filters supported by this class.
66     * 
67     * @param type type of demanded filter
68     * @return filter instance
69     * @see Filters
70     */
71    public static BinaryFilters getFilter(Filters type) {
72      switch (type) {
73        case NONE:
74          return new MedianMorpho.EmptyMorpho();
75        case SIMPLE:
76          return new MedianMorpho.SimpleMorpho();
77        case MEDIAN:
78          return new MedianMorpho.MedianMorpho();
79        default:
80          throw new IllegalArgumentException("Unknown filter type");
81      }
82    }
83  
84    /**
85     * Filter image using morphological operations.
86     * 
87     * <p>Input image is copied and converted to BinaryProcessor.
88     * 
89     * @param input image to process (not modified)
90     * @return processed image
91     */
92    abstract ImageProcessor filter(ImageProcessor input);
93  
94    /**
95     * Perform median filtering with radius 2 on image.
96     * 
97     * @author p.baniukiewicz
98     *
99     */
100   public static class MedianMorpho extends BinaryFilters {
101 
102     /*
103      * (non-Javadoc)
104      * 
105      * @see com.github.celldynamics.quimp.plugin.randomwalk.BinaryFilters#filter(ij.process.
106      * ImageProcessor)
107      */
108     @Override
109     ImageProcessor filter(ImageProcessor input) {
110       BinaryProcessor bp = getBinaryProcessor(input);
111       bp.medianFilter();
112       return bp;
113     }
114 
115   }
116 
117   /**
118    * Filter image using 1 iteration opening.
119    * 
120    * @author p.baniukiewicz
121    *
122    */
123   public static class SimpleMorpho extends BinaryFilters {
124 
125     /*
126      * (non-Javadoc)
127      * 
128      * @see BinaryFilters#filter(ij.process.ImageProcessor)
129      */
130     @Override
131     ImageProcessor filter(ImageProcessor input) {
132       return iterateMorphological(getBinaryProcessor(input), MorphoOperations.IJOPEN, 1);
133     }
134 
135   }
136 
137   /**
138    * Dummy filter that does nothing.
139    * 
140    * @author p.baniukiewicz
141    *
142    */
143   public static class EmptyMorpho extends BinaryFilters {
144 
145     /*
146      * (non-Javadoc)
147      * 
148      * @see
149      * com.github.celldynamics.quimp.plugin.randomwalk.BinaryFilters#filter(ij.process.
150      * ImageProcessor)
151      */
152     @Override
153     ImageProcessor filter(ImageProcessor input) {
154       BinaryProcessor ret = getBinaryProcessor(input);
155       return ret;
156     }
157 
158   }
159 
160   /**
161    * Converts input image to BinaryProcessor duplicating it.
162    * 
163    * @param input image to convert
164    * @return Image converted to BinaryProcessor
165    */
166   public static BinaryProcessor getBinaryProcessor(ImageProcessor input) {
167     return new BinaryProcessor(input.duplicate().convertToByteProcessor());
168   }
169 
170   /**
171    * Run morphological operation on input image.
172    * 
173    * @param ip Image to process, must be IJ binary (8-bit-image with only 0 and 255)
174    * @param oper Operator
175    * @param iter number of iterations
176    * @return Modified image (copy)
177    */
178   public static ImageProcessor iterateMorphological(ImageProcessor ip, MorphoOperations oper,
179           double iter) {
180     BinaryProcessor result;
181     switch (oper) {
182       case ERODE:
183         result = getBinaryProcessor(ip);
184         for (int i = 0; i < iter; i++) {
185           result.erode(1, 0); // first param influence precision
186         }
187         break;
188       case DILATE:
189         result = getBinaryProcessor(ip);
190         for (int i = 0; i < iter; i++) {
191           result.dilate(1, 0);
192         }
193         break;
194       case IJOPEN:
195         // this approach duplicate image internally
196         IJ.run("Options...", "iterations=" + iter + " count=1 black do=Nothing");
197         IJ.run(new ImagePlus("before", ip), "Open", "");
198         result = (BinaryProcessor) ip;
199         break;
200       default:
201         throw new IllegalArgumentException("Binary operation not supported");
202     }
203     return result;
204   }
205 
206 }