PlugIn Algorithm Median

From MIPAV
Jump to navigation Jump to 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)