Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
Convolver.java
1 package ij.plugin.filter;
2 import ij.*;
3 import ij.process.*;
4 import ij.gui.*;
5 import ij.io.*;
6 import java.awt.*;
7 import java.util.*;
8 import java.awt.event.*;
9 import java.io.*;
10 
13 public class Convolver implements PlugInFilter {
14 
15  static final int BYTE=0, SHORT=1, FLOAT=2, RGB=3;
16 
17  ImagePlus imp;
18  int kw, kh;
19  boolean canceled;
20  float[] kernel;
21  boolean isLineRoi;
22  Button open, save;
23  GenericDialog gd;
24 
25  static String kernelText = "-1 -1 -1 -1 -1\n-1 -1 -1 -1 -1\n-1 -1 24 -1 -1\n-1 -1 -1 -1 -1\n-1 -1 -1 -1 -1\n";
26  static boolean normalize = true;
27 
28  public int setup(String arg, ImagePlus imp) {
29  IJ.register(Convolver.class);
30  this.imp = imp;
31  canceled = false;
32  if (imp==null)
33  {IJ.noImage(); return DONE;}
34  Roi roi = imp.getRoi();
35  isLineRoi= roi!=null && roi.getType()>=Roi.LINE;
36  kernel = getKernel();
37  if (kernel==null)
38  return DONE;
39  if ((kw&1)==0) {
40  IJ.showMessage("Convolver","The kernel must be square and have an\n"
41  +"odd width. This kernel is "+kw+"x"+kh+".");
42  return DONE;
43  }
44  int flags = IJ.setupDialog(imp, DOES_ALL);
45  if ((flags&DONE)!=0)
46  return DONE;
47  IJ.showStatus("Convolve: "+kw+"x"+kh+" kernel");
48  imp.startTiming();
49  return flags;
50  }
51 
52  public void run(ImageProcessor ip) {
53  if (canceled)
54  return;
55  if (isLineRoi)
56  ip.resetRoi();
57  convolve(ip, kernel, kw, kh);
58  IJ.showStatus("Convolve");
59  ip.resetMinAndMax();
60  }
61 
62  float[] getKernel() {
63  gd = new GenericDialog("Convolver...", IJ.getInstance());
64  gd.addTextAreas(kernelText, null, 10, 30);
65  gd.addCheckbox("Normalize Kernel", normalize);
66  gd.showDialog();
67  if (gd.wasCanceled()) {
68  canceled = true;
69  return null;
70  }
71  kernelText = gd.getNextText();
72  normalize = gd.getNextBoolean();
73  StringTokenizer st = new StringTokenizer(kernelText);
74  int n = st.countTokens();
75  kw = (int)Math.sqrt(n);
76  kh = kw;
77  n = kw*kh;
78  float[] k = new float[n];
79  for (int i=0; i<n; i++)
80  k[i] = (float)getNum(st);
81  //IJ.write("kw: "+kw);
82  return k;
83  }
84 
85 
86 
87  double getNum(StringTokenizer st) {
88  Double d;
89  String token = st.nextToken();
90  try {d = new Double(token);}
91  catch (NumberFormatException e){d = null;}
92  if (d!=null)
93  return(d.doubleValue());
94  else
95  return 0.0;
96  }
97 
98  public void convolve(ImageProcessor ip, float[] kernel, int kw, int kh) {
99  if ((kw&1)!=1 || (kh&1)!=1)
100  throw new IllegalArgumentException("Kernel width or height not odd");
101  int type;
102  if (ip instanceof ByteProcessor)
103  type = BYTE;
104  else if (ip instanceof ShortProcessor)
105  type = SHORT;
106  else if (ip instanceof FloatProcessor)
107  type = FLOAT;
108  else
109  type = RGB;
110 
111  ip.setCalibrationTable(null);
112  ImageProcessor ip2 = ip.convertToFloat();
113  ip2.setRoi(ip.getRoi());
114  ip2.setMask(ip.getMask());
115  convolveFloat(ip2, kernel, kw, kh);
116  switch (type) {
117  case BYTE:
118  ip2 = ip2.convertToByte(false);
119  byte[] pixels = (byte[])ip.getPixels();
120  byte[] pixels2 = (byte[])ip2.getPixels();
121  System.arraycopy(pixels2, 0, pixels, 0, pixels.length);
122  break;
123  case SHORT:
124  ip2 = ip2.convertToShort(false);
125  short[] pixels16 = (short[])ip.getPixels();
126  short[] pixels16b = (short[])ip2.getPixels();
127  System.arraycopy(pixels16b, 0, pixels16, 0, pixels16.length);
128  break;
129  case FLOAT:
130  break;
131  }
132  }
133 
134  public void setNormalize(boolean normalizeKernel) {
135  normalize = normalizeKernel;
136  }
137 
138  public void convolveFloat(ImageProcessor ip, float[] kernel, int kw, int kh) {
139  int width = ip.getWidth();
140  int height = ip.getHeight();
141  Rectangle r = ip.getRoi();
142  boolean isRoi = r.width!=width||r.height!=height;
143  boolean nonRectRoi = isRoi && ip.getMask()!=null;
144  if (nonRectRoi)
145  ip.snapshot();
146  int x1 = r.x;
147  int y1 = r.y;
148  int x2 = x1 + r.width;
149  int y2 = y1 + r.height;
150  int uc = kw/2;
151  int vc = kh/2;
152  float[] pixels = (float[])ip.getPixels();
153  float[] pixels2 = (float[])ip.getPixelsCopy();
154  //for (int i=0; i<width*height; i++)
155  // pixels[i] = 0f;
156 
157  double scale = 1.0;
158  if (normalize) {
159  double sum = 0.0;
160  for (int i=0; i<kernel.length; i++)
161  sum += kernel[i];
162  if (sum!=0.0)
163  scale = (float)(1.0/sum);
164  }
165 
166  int progress = Math.max((y2-y1)/25,1);
167  double sum;
168  int offset, i;
169  boolean edgePixel;
170  int xedge = width-uc;
171  int yedge = height-vc;
172  for(int y=y1; y<y2; y++) {
173  if (y%progress ==0) IJ.showProgress((double)y/height);
174  for(int x=x1; x<x2; x++) {
175  sum = 0.0;
176  i = 0;
177  edgePixel = y<vc || y>=yedge || x<uc || x>=xedge;
178  for(int v=-vc; v <= vc; v++) {
179  offset = x+(y+v)*width;
180  for(int u = -uc; u <= uc; u++) {
181  if (edgePixel)
182  sum += getPixel(x+u, y+v, pixels2, width, height)*kernel[i++];
183  else
184  sum += pixels2[offset+u]*kernel[i++];
185  }
186  }
187  pixels[x+y*width] = (float)(sum*scale);
188  }
189  }
190  if (nonRectRoi)
191  ip.reset(ip.getMask());
192  IJ.showProgress(1.0);
193  }
194 
195  private float getPixel(int x, int y, float[] pixels, int width, int height) {
196  if (x<=0) x = 0;
197  if (x>=width) x = width-1;
198  if (y<=0) y = 0;
199  if (y>=height) y = height-1;
200  return pixels[x+y*width];
201  }
202 
203 
204 
205 
206 }
207 
208