Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
Wand.java
1 package ij.gui;
2 
3 import java.awt.*;
4 import ij.*;
5 import ij.process.*;
6 
8 public class Wand {
9  static final int UP=0, DOWN=1, UP_OR_DOWN=2, LEFT=3, RIGHT=4, LEFT_OR_RIGHT=5, NA=6;
10 
12  public int npoints;
13  private int maxPoints = 1000; // will be increased if necessary
15  public int[] xpoints = new int[maxPoints];
17  public int[] ypoints = new int[maxPoints];
18 
19  private ImageProcessor ip;
20  private byte[] bpixels;
21  private int[] cpixels;
22  private short[] spixels;
23  private float[] fpixels;
24  private int width, height;
25  private float lowerThreshold, upperThreshold;
26 
28  public Wand(ImageProcessor ip) {
29  if (ip instanceof ByteProcessor)
30  bpixels = (byte[])ip.getPixels();
31  else if (ip instanceof ColorProcessor)
32  cpixels = (int[])ip.getPixels();
33  else if (ip instanceof ShortProcessor)
34  spixels = (short[])ip.getPixels();
35  else if (ip instanceof FloatProcessor)
36  fpixels = (float[])ip.getPixels();
37  width = ip.getWidth();
38  height = ip.getHeight();
39  }
40 
41  private float getColorPixel(int x, int y) {
42  if (x>=0 && x<width && y>=0 && y<height)
43  return cpixels[y*width + x];
44  else
45  return Float.MAX_VALUE;
46  }
47 
48  private float getBytePixel(int x, int y) {
49  if (x>=0 && x<width && y>=0 && y<height)
50  return bpixels[y*width + x] & 0xff;
51  else
52  return Float.MAX_VALUE;
53  }
54 
55  private float getShortPixel(int x, int y) {
56  if (x>=0 && x<width && y>=0 && y<height)
57  return spixels[y*width + x] & 0xffff;
58  else
59  return Float.MAX_VALUE;
60  }
61 
62  private float getFloatPixel(int x, int y) {
63  if (x>=0 && x<width && y>=0 && y<height)
64  return fpixels[y*width + x];
65  else
66  return Float.MAX_VALUE;
67  }
68 
69  private float getPixel(int x, int y) {
70  if (bpixels!=null)
71  return getBytePixel(x,y);
72  else if (spixels!=null)
73  return getShortPixel(x,y);
74  else if (fpixels!=null)
75  return getFloatPixel(x,y);
76  else
77  return getColorPixel(x,y);
78  }
79 
80  private boolean inside(int x, int y) {
81  float value;
82  if (bpixels!=null)
83  value = getBytePixel(x,y);
84  else if (spixels!=null)
85  value = getShortPixel(x,y);
86  else if (fpixels!=null)
87  value = getFloatPixel(x,y);
88  else
89  value = getColorPixel(x,y);
90  return value>=lowerThreshold && value<=upperThreshold;
91  }
92 
93  /* Are we tracing a one pixel wide line? */
94  boolean isLine(int xs, int ys) {
95  int r = 5;
96  int xmin=xs;
97  int xmax=xs+2*r;
98  if (xmax>=width) xmax=width-1;
99  int ymin=ys-r;
100  if (ymin<0) ymin=0;
101  int ymax=ys+r;
102  if (ymax>=height) ymax=height-1;
103  int area = 0;
104  int insideCount = 0;
105  for (int x=xmin; (x<=xmax); x++)
106  for (int y=ymin; y<=ymax; y++) {
107  area++;
108  if (inside(x,y))
109  insideCount++;
110  }
111  if (IJ.debugMode)
112  IJ.log((((double)insideCount)/area>=0.75?"line ":"blob ")+insideCount+" "+area+" "+IJ.d2s(((double)insideCount)/area));
113  return ((double)insideCount)/area>=0.75;
114  }
115 
121  public void autoOutline(int startX, int startY) {
122  int x = startX;
123  int y = startY;
124  int direction;
125  lowerThreshold = upperThreshold = getPixel(startX, startY);
126  do {x++;} while (inside(x,y));
127  if (isLine(x, y)) {
128  lowerThreshold = upperThreshold = getPixel(x, y);
129  direction = UP;
130  } else {
131  if (!inside(x-1,y-1))
132  direction = RIGHT;
133  else if (inside(x,y-1))
134  direction = LEFT;
135  else
136  direction = DOWN;
137  }
138  traceEdge(x, y, direction);
139  }
140 
143  public void autoOutline(int startX, int startY, double lower, double upper) {
144  npoints = 0;
145  int x = startX;
146  int y = startY;
147  int direction;
148  lowerThreshold = (float)lower;
149  upperThreshold = (float)upper;
150  if (inside(x,y)) {
151  do {x++;} while (inside(x,y));
152  if (!inside(x-1,y-1))
153  direction = RIGHT;
154  else if (inside(x,y-1))
155  direction = LEFT;
156  else
157  direction = DOWN;
158  } else {
159  do {x++;} while (!inside(x,y) && x<width);
160  direction = UP;
161  if (x>=width) return;
162  }
163  traceEdge(x, y, direction);
164  }
165 
167  public void autoOutline(int startX, int startY, int lower, int upper) {
168  autoOutline(startX, startY, (double)lower, (double)upper);
169  }
170 
171  void traceEdge(int xstart, int ystart, int startingDirection) {
172  int[] table = {
173  // 1234, 1=upper left pixel, 2=upper right, 3=lower left, 4=lower right
174  NA, // 0000, should never happen
175  RIGHT, // 000X,
176  DOWN, // 00X0
177  RIGHT, // 00XX
178  UP, // 0X00
179  UP, // 0X0X
180  UP_OR_DOWN, // 0XX0 Go up or down depending on current direction
181  UP, // 0XXX
182  LEFT, // X000
183  LEFT_OR_RIGHT, // X00X Go left or right depending on current direction
184  DOWN, // X0X0
185  RIGHT, // X0XX
186  LEFT, // XX00
187  LEFT, // XX0X
188  DOWN, // XXX0
189  NA, // XXXX Should never happen
190  };
191  int index;
192  int newDirection;
193  int x = xstart;
194  int y = ystart;
195  int direction = startingDirection;
196 
197  boolean UL = inside(x-1, y-1); // upper left
198  boolean UR = inside(x, y-1); // upper right
199  boolean LL = inside(x-1, y); // lower left
200  boolean LR = inside(x, y); // lower right
201  //xpoints[0] = x;
202  //ypoints[0] = y;
203  int count = 0;
204  //IJ.write("");
205  //IJ.write(count + " " + x + " " + y + " " + direction + " " + insideValue);
206  do {
207  index = 0;
208  if (LR) index |= 1;
209  if (LL) index |= 2;
210  if (UR) index |= 4;
211  if (UL) index |= 8;
212  newDirection = table[index];
213  if (newDirection==UP_OR_DOWN) {
214  if (direction==RIGHT)
215  newDirection = UP;
216  else
217  newDirection = DOWN;
218  }
219  if (newDirection==LEFT_OR_RIGHT) {
220  if (direction==UP)
221  newDirection = LEFT;
222  else
223  newDirection = RIGHT;
224  }
225  if (newDirection!=direction) {
226  xpoints[count] = x;
227  ypoints[count] = y;
228  count++;
229  if (count==xpoints.length) {
230  int[] xtemp = new int[maxPoints*2];
231  int[] ytemp = new int[maxPoints*2];
232  System.arraycopy(xpoints, 0, xtemp, 0, maxPoints);
233  System.arraycopy(ypoints, 0, ytemp, 0, maxPoints);
234  xpoints = xtemp;
235  ypoints = ytemp;
236  maxPoints *= 2;
237  }
238  //if (count<10) IJ.write(count + " " + x + " " + y + " " + newDirection + " " + index);
239  }
240  switch (newDirection) {
241  case UP:
242  y = y-1;
243  LL = UL;
244  LR = UR;
245  UL = inside(x-1, y-1);
246  UR = inside(x, y-1);
247  break;
248  case DOWN:
249  y = y + 1;
250  UL = LL;
251  UR = LR;
252  LL = inside(x-1, y);
253  LR = inside(x, y);
254  break;
255  case LEFT:
256  x = x-1;
257  UR = UL;
258  LR = LL;
259  UL = inside(x-1, y-1);
260  LL = inside(x-1, y);
261  break;
262  case RIGHT:
263  x = x + 1;
264  UL = UR;
265  LL = LR;
266  UR = inside(x, y-1);
267  LR = inside(x, y);
268  break;
269  }
270  direction = newDirection;
271  } while ((x!=xstart || y!=ystart || direction!=startingDirection));
272  npoints = count;
273  }
274 
275 }