PlugIn Algorithm Median

From MIPAV
Jump to: navigation, search

PlugIn Algorithm median


PlugInAlgorithmMedian
The source code for the plugin program, PlugInAlgorithmMedian.java (Figure 1), is an example of an algorithm type of plugin. This plugin program runs a median filter on an image, using its own dialog box and implementation of the median filter.
Note: For ease of reading, comment lines in the source file appear in green type, and keywords appear in bold type.
{| border="1" cellpadding="5" |+
Figure 1. PlugInAlgorithmMedian.javaÂ
|- |
1 // By leaving out the package keyword in this class, it is therefore in the default java package
2 // for the application.
3
4 import gov.nih.mipav.model.algorithms.*;
5 import gov.nih.mipav.model.structures.*;
6 import gov.nih.mipav.view.*;
7
8 import java.io.*;
9 import java.util.*;
10 import java.awt.*;
11
12
13 /**
14 * Example of a plugin implementation of the median filter.
15 * This class creates the algorithm that runs on the image.
16 * This shows how to extend the AlgorithmBase class.
17 *
18 * Note: The median algorithm is already implemented in
19 * the MIPAV/IASO software.
20 *
21 * @version July 12, 2002
22 * @see Algorithms
23 * @see AlgorithmMedian
24 *
25 * $Logfile: /mipav/src/plugins/PlugInAlgorithmMedian.java $
26 * $Revision: 7 $
27 * $Date: 3/16/05 3:36p $
28 *
29 */
30 public class PlugInAlgorithmMedian extends AlgorithmBase {
31
32 private static final int SQUARE_KERNEL = 0; //square kernel
33 private static final int CUBE_KERNEL = 0;
34 private static final int CROSS_KERNEL = 1; // cross
35 private static final int AXIAL_KERNEL = 1; //
36 private static final int X_KERNEL = 2; // X-shaped kernel, from 1
37 // corner to opposite corner
38 private static final int HORZ_KERNEL = 3; // horizontal (2D only)
39 private static final int VERT_KERNEL = 4; // vertical (2D only)
40
41
42 private BitSet mask = null;
43
44 private int iterations; // number of times to filter
45 // the image.
46 private int kernelSize; // dimension of the kernel
47 // (i.e., 5 = 5x5, 7 = 7x7,
48 // 9 = 9x9, etc.)
49 private int kernelShape; // user-selectable shape of
50 // the region for neighbor-
51 // selection
52 private boolean entireImage; // true means apply to
// entire

53 // image, false only region
54 private byte[] kernel; // mask to determine the
|- |
55 // region of pixels used in a
56 // median filter
57 private float stdDevLimit; // compute median value of
58 // pixel if pixel magnitude is
59 // outside this fraction of
60 // the standard deviation
61 private boolean sliceFiltering; // do all filtering slice-by-
62 // slice, rather than as a
63 // volume (applies only to
64 // 3D/volume images)
65 private int currentSlice = 0;//
66 private int numberOfSlices;
67 private int halfK;
68 private int kernelCenter;
69 private float[] kernelMask;
70 private int maskCenter;
71
72
73
74 private boolean isColorImage = false; // indicates the image being
75 // messed with is a color
76 // image
77 private int valuesPerPixel=1; // number of elements in a
78 // pixel. Monochrome = 1,
79 // Color = 4. (a, R, G, B)
80 private boolean rChannel = true; // if T, filter the red
81 // channel
82 private boolean gChannel = true; // the green channel
83 private boolean bChannel = true; // the blue channel
84
85 /**
86 * Constructor for 3D images in which changes are placed in a predetermined
87 * destination image.
88 * @param destImg Image model where result image is to stored.
89 * @param srcImg Source image model.
90 * @param iters Number of iterations of the median filter.
91 * @param kSize Kernel size: dimension of the kernel (i.e., 5 = 5x5,
92 * 7 = 7x7, 9 = 9x9, etc.).
93 * @param kShape Kernel shape: element neighbors to include when finding
94 * the median.
95 * @param stdDev Inner-bounds by which to process pixels (pixel values
96 * outside this bound will be median filtered).
97 * @param sliceBySlice Each slice in a volume image is to be filtered separately
98 * (when true), else the volume will use a kernel with 3
99 * dimensions.
100 * @param maskFlag Flag that indicates that the median filtering will be
101 * performed for the whole image if equal to true.
102 */
103 public PlugInAlgorithmMedian(ModelImage destImg, ModelImage srcImg, int iters,
104 int kSize, int kShape, float stdDev, boolean sliceBySlice,
105 boolean maskFlag) {
106
107 super(destImg, srcImg);
Â
|- |
108 if ( srcImg.isColorImage() ) {
109 isColorImage = true;
110 valuesPerPixel = 4;
111 }
112 // else, already false
113 entireImage = maskFlag;
114 iterations = iters;
115 kernelSize = kSize; // dimension of the kernel
116 kernelShape = kShape; // set up the mask (kernel) used to
117 // filter
118
119 stdDevLimit = stdDev; // inside magnitude bounds of pixel
120 // value to adjust
121 sliceFiltering = sliceBySlice;
122 numberOfSlices = srcImage.getExtents()[2];
123 makeKernel();
124 }
125
126 /**
127 * Constructor for 2D images in which changes are placed in a predetermined
128 * destination image.
129 * @param destImg Image model where result image is to stored.
130 * @param srcImg Source image model.
131 * @param iters Number of iterations of the median filter.
132 * @param kSize Kernel size: dimension of the kernel (i.e., 5 = 5x5, 7 = 7x7,
133 * 9 = 9x9, etc.).
134 * @param kShape Kernel shape: element neighbors to include when finding the
135 * median.
136 * @param stdDe Inner-bounds by which to process pixels (pixel values outside
137 * this bound will be median filtered).
138 * @param maskFlag Flag that indicates that the median filtering will be
139 * performed for the whole image if equal to true.
140 */
141 public PlugInAlgorithmMedian(ModelImage destImg, ModelImage srcImg, int iters,
142 int kSize, int kShape, float stdDev, boolean maskFlag) {
143
144 super(destImg, srcImg);
145 if ( srcImg.isColorImage() ) {
146 isColorImage = true;
147 valuesPerPixel = 4;
148 }
149 // else, already false
150 entireImage = maskFlag;
151 iterations = iters;
152 kernelSize = kSize; // dimension of the kernel
153 kernelShape = kShape; // set up the mask (kernel) used to filter
154 stdDevLimit = stdDev; // inside magnitude bounds of pixel value to adjust
155 sliceFiltering = true; // as a default--this doesn't make much sense in a 2D
156 // application.
157 numberOfSlices = 1; // 2D images may only have 1 slice.
158 makeKernel();
159 }
160 /**
161 * Constructor for 3D images in which changes are returned to the source image.
162 * @param srcImg Source image model.
163 * @param iters Number of iterations of the median filter.
Â
|- |
164 * @param kSize Kernel size: dimension of the kernel (i.e., 5 = 5x5, 7 = 7x7,
165 * 9 = 9x9, etc.).
166 * @param kShape Kernel shape: element neighbors to include when finding the
167 * median.
168 * @param stdDev Inner-bounds by which to process pixels (pixel values outside
169 * this bound will be median filtered).
170 * @param sliceBySlice Each slice in a volume image is to be filtered separately
* (when

171 * true), else the volume will use a kernel with 3 dimensions.
172 * @param maskFlag Flag that indicates that the median filtering will be
173 * performed for the whole image if equal to true.
174 */
175 public PlugInAlgorithmMedian(ModelImage srcImg, int iters, int kSize, int kShape,
176 float stdDev, boolean sliceBySlice, boolean maskFlag) {
177 super(null, srcImg);
178 if ( srcImg.isColorImage() ) {
179 isColorImage = true;
180 valuesPerPixel = 4;
181 }
182 // else, already false
183 entireImage = maskFlag;
184 iterations = iters;
185 kernelSize = kSize; // dimension of the kernel
186 kernelShape = kShape; // set up the mask (kernel) used to filter
187 stdDevLimit = stdDev; // inside magnitude bounds of pixel value to adjust
188 sliceFiltering = sliceBySlice;
189 numberOfSlices = srcImage.getExtents()[2];
190 makeKernel();
191 }
192
193 /**
194 * Constructor for 2D images in which changes are returned to the source image.
195 * @param srcImg Source image model.
196 * @param iters Number of iterations of the median filter.
197 * @param kSize Kernel size: dimension of the kernel (i.e., 5 = 5x5, 7 = 7x7,
198 * 9 = 9x9, etc.).
199 * @param kShape Kernel shape: element neighbors to include when finding the
* median.

200 * @param stdDev Inner-bounds by which to process pixels (pixel values outside
201 * this bound will be median filtered).
202 * @param maskFlag Flag that indicates that the median filtering will be
203 * performed for the whole image if equal to true.
204 */
205 public PlugInAlgorithmMedian(ModelImage srcImg, int iters, int kSize, int kShape,
206 float stdDev, boolean maskFlag) {
207 super(null, srcImg);
208 if ( srcImg.isColorImage() ) {
209 isColorImage = true;
210 valuesPerPixel = 4;
211 }
212 // else, already false
213 entireImage = maskFlag;
214 iterations = iters;
215 kernelSize = kSize; // dimension of the kernel
216 kernelShape = kShape; // set up the mask (kernel) used to filter
217 stdDevLimit = stdDev; // inside magnitude bounds of pixel value to adjust
Â
|- |
218 sliceFiltering = true; // as a default--though a different value doesn't
219 // make much sense in a 2D application.
220 // (calculates makeKernel() )
221 numberOfSlices = 1; // 2D images may only have 1 slice.
222 makeKernel();
223 }
224
225 /**
226 * RGB images are median filtered by "channel." That is, each color,
227 * red, blue and green, is filtered independently of the other two colors.
228 * This median filter permits selectively filtering any combination of the
229 * three channels instead of simply filtering all three. True for any of
230 * the arguments enforces filtering that channel.
231 * @param r Filter red channel.
232 * @param g Filter green channel.
233 * @param b Filter blue channel.
234 */
235 public void setRGBChannelFilter(boolean r, boolean g, boolean b) {
236 if (isColorImage) { // just in case somebody called for a mono image
237 rChannel = r;
238 gChannel = g;
239 bChannel = b;
240 }
241 }
242
243 /**
244 * Prepares this class for destruction.
245 */
246 public void finalize(){
247 destImage = null;
248 srcImage = null;
249 super.finalize();
250 }
251
252 /**
253 * Constructs a string of the construction parameters and outputs the string to the
254 * message frame if the logging procedure is turned on.
255 */
256 private void constructLog() {
257 historyString = new String( "Median("
258 String.valueOf(kernelShape) ", "
259 String.valueOf(kernelSize) ", "
260 String.valueOf(iterations) ", "
261 String.valueOf(entireImage) ")\n");
262 }
263
264 /**
265 * Starts the algorithm.
266 */
267 public void runAlgorithm() {
268
269 if (srcImage == null) {
270 displayError("Source Image is null");
271 return;
272 }
273
Â
|- |
274 constructLog();
275 if (destImage != null){ // if there exists a destination image
276 if (srcImage.getNDims() == 2){
277 calcStoreInDest2D();
278 }
279 else if (srcImage.getNDims() > 2) {
280 calcStoreInDest3D();
281 }
282 }
283 else { // there is no image but the original source.
284 if (srcImage.getNDims() == 2){
285 calcInPlace2D();
286 }
287 else if (srcImage.getNDims() > 2) {
288 calcInPlace3D();
289 }
290 }
291 } // end runAlgorithm()
292
293 /**
294 * Median filters the source image. Replaces the original image with the filtered
295 * image.
296 */
297 private void calcInPlace2D(){
298
299 int length; // total number of data-elements (pixels) in image
300 float buffer[]; // data-buffer (for pixel data) which is the "heart"
301 // of the image
302 float resultBuffer[]; // copy-to buffer (for pixel data) for image-data
303 // after filtering
304
305 try {
306 if (!isColorImage) {
307 // image length is length in 2 dims
308 length = srcImage.getExtents()[0]
309 *srcImage.getExtents()[1];
310 }
311 else { // if (isColorImage) {
312 // image length is length in 2 dims
313 // by 4 color elements per pixel
314 length = srcImage.getExtents()[0]
315 *srcImage.getExtents()[1]
316 *4; // 1 each for ARGB
317 }
318 buffer = new float[length];
319 resultBuffer = new float[length];
320 srcImage.exportData(0,length, buffer); // locks and releases lock
321 }
322 catch (IOException error) {
323 buffer = null;
324 resultBuffer = null;
325 errorCleanUp("Algorithm Median: source image locked", true);
326 return;
327 }
328 catch (OutOfMemoryError e){
329 buffer = null;
Â
|- |
330 resultBuffer = null;
331 errorCleanUp("Algorithm Median reports: Out of memory when creating image
332 buffer", true);
333 return;
334 }
335
336 this.buildProgressBar(); // let user know what is going on
337 this.sliceFilter(buffer, resultBuffer, 0, "image"); // filter this slice
338 disposeProgressBar(); // filtering work should be done.
339
340 if (threadStopped) {
341 finalize();
342 return;
343 }
344
345 try { // place buffer data into the image
346 srcImage.importData(0, resultBuffer, true);
347 }
348 catch (IOException error) {
349 buffer = null;
350 resultBuffer = null;
351 errorCleanUp("Algorithm Median: Source image locked", true);
352 return;
353 }
354
355 setCompleted(true);
356 }
357
358 /**
359 * Median filters the source image and replaces the source image with the median
360 * filtered image.
361 */
362 private void calcInPlace3D(){
363
364 int imageSliceLength = srcImage.getExtents()[0]*srcImage.getExtents()[1];
365 int length;
366 float buffer[];
367 float resultBuffer[];
368 try {
369 if (!isColorImage) {
370 // image length is length in 3 dims
371 length = srcImage.getExtents()[0]
372 *srcImage.getExtents()[1]
373 *srcImage.getExtents()[2];
374 }
375 else { // if (isColorImage) {
376 // image length is length in 3 dims
377 // by 4 color elements per pixel
378 length = srcImage.getExtents()[0]
379 *srcImage.getExtents()[1]
380 *srcImage.getExtents()[2]
381 *4; // 1 each for ARGB
382 }
383 buffer = new float[length];
384 resultBuffer = new float[length];
385 srcImage.exportData(0,length, buffer); // locks and releases lock
386 this.buildProgressBar();
387 }
Â
|- |
388 catch (IOException error) {
389 buffer = null;
390 resultBuffer = null;
391 errorCleanUp("Algorithm Median: Source image locked", true);
392 return;
393 }
394 catch (OutOfMemoryError e){
395 buffer = null;
396 resultBuffer = null;
397 errorCleanUp("Algorithm Median: Out of memory", true);
398 return;
399 }
|}


PlugIn Algorithm Median (con't)