Squiz Matrix  4.12.2
 All Data Structures Namespaces Functions Variables Pages
Selection.java
1 package ij.plugin;
2 import ij.*;
3 import ij.gui.*;
4 import ij.process.*;
5 import ij.measure.Calibration;
6 import java.awt.*;
7 
8 
10 public class Selection implements PlugIn {
11  ImagePlus imp;
12  float[] kernel = {1f, 1f, 1f, 1f, 1f};
13  float[] kernel3 = {1f, 1f, 1f};
14 
16  public void run(String arg) {
17  imp = IJ.getInstance().getImagePlus();
18  if (imp==null)
19  {IJ.noImage(); return;}
20  if (arg.equals("all"))
21  imp.setRoi(0,0,imp.getWidth(),imp.getHeight());
22  else if (arg.equals("none"))
23  imp.killRoi();
24  else if (arg.equals("restore"))
25  imp.restoreRoi();
26  else if (arg.equals("spline"))
27  fitSpline();
28  else if (arg.equals("ellipse"))
29  drawEllipse(imp);
30  else if (arg.equals("hull"))
31  convexHull(imp);
32  else if (arg.equals("mask"))
33  createMask(imp);
34  else if (arg.equals("inverse"))
35  invert(imp);
36  }
37 
38  void fitSpline() {
39  Roi roi = imp.getRoi();
40  if (roi==null)
41  {IJ.showMessage("Spline", "Selection required"); return;}
42  int type = roi.getType();
43  boolean segmentedSelection = type==Roi.POLYGON||type==Roi.POLYLINE;
44  if (!(segmentedSelection||type==Roi.FREEROI||type==Roi.TRACED_ROI||type==Roi.FREELINE))
45  {IJ.showMessage("Spline", "Polygon or polyline selection required"); return;}
46  PolygonRoi p = (PolygonRoi)roi;
47  double length = getLength(p);
48  if (!segmentedSelection)
49  p = trimPolygon(p, length);
50  int evaluationPoints = (int)(length/2.0);
51  double mag = imp.getCanvas().getMagnification();
52  if (mag<1.0)
53  evaluationPoints *= mag;;
54  if (evaluationPoints<100)
55  evaluationPoints = 100;
56  p.fitSpline(evaluationPoints);
57  imp.draw();
58  }
59 
60  double getLength(PolygonRoi roi) {
61  Calibration cal = imp.getCalibration();
62  double spw=cal.pixelWidth, sph=cal.pixelHeight;
63  cal.pixelWidth=1.0; cal.pixelHeight=1.0;
64  double length = roi.getLength();
65  cal.pixelWidth=spw; cal.pixelHeight=sph;
66  return length;
67  }
68 
69  PolygonRoi trimPolygon(PolygonRoi roi, double length) {
70  int[] x = roi.getXCoordinates();
71  int[] y = roi.getYCoordinates();
72  int n = roi.getNCoordinates();
73  float[] curvature = getCurvature(x, y, n);
74  Rectangle r = roi.getBounds();
75  double threshold = rodbard(length);
76  //IJ.log("trim: "+length+" "+threshold);
77  double distance = Math.sqrt((x[1]-x[0])*(x[1]-x[0])+(y[1]-y[0])*(y[1]-y[0]));
78  x[0] += r.x; y[0]+=r.y;
79  int i2 = 1;
80  int x1,y1,x2=0,y2=0;
81  for (int i=1; i<n-1; i++) {
82  x1=x[i]; y1=y[i]; x2=x[i+1]; y2=y[i+1];
83  distance += Math.sqrt((x2-x1)*(x2-x1)+(y2-y1)*(y2-y1)) + 1;
84  distance += curvature[i]*2;
85  if (distance>=threshold) {
86  x[i2] = x2 + r.x;
87  y[i2] = y2 + r.y;
88  i2++;
89  distance = 0.0;
90  }
91  }
92  int type = roi.getType()==Roi.FREELINE?Roi.POLYLINE:Roi.POLYGON;
93  if (type==Roi.POLYLINE && distance>0.0) {
94  x[i2] = x2 + r.x;
95  y[i2] = y2 + r.y;
96  i2++;
97  }
98  PolygonRoi p = new PolygonRoi(x, y, i2, type);
99  imp.setRoi(p);
100  return p;
101  }
102 
103  double rodbard(double x) {
104  // y = c*((a-x/(x-d))^(1/b)
105  // a=3.9, b=.88, c=712, d=44
106  double ex;
107  if (x == 0.0)
108  ex = 5.0;
109  else
110  ex = Math.exp(Math.log(x/700.0)*0.88);
111  double y = 3.9-44.0;
112  y = y/(1.0+ex);
113  return y+44.0;
114  }
115 
116  float[] getCurvature(int[] x, int[] y, int n) {
117  float[] x2 = new float[n];
118  float[] y2 = new float[n];
119  for (int i=0; i<n; i++) {
120  x2[i] = x[i];
121  y2[i] = y[i];
122  }
123  ImageProcessor ipx = new FloatProcessor(n, 1, x2, null);
124  ImageProcessor ipy = new FloatProcessor(n, 1, y2, null);
125  ipx.convolve(kernel, kernel.length, 1);
126  ipy.convolve(kernel, kernel.length, 1);
127  float[] indexes = new float[n];
128  float[] curvature = new float[n];
129  for (int i=0; i<n; i++) {
130  indexes[i] = i;
131  curvature[i] = (float)Math.sqrt((x2[i]-x[i])*(x2[i]-x[i])+(y2[i]-y[i])*(y2[i]-y[i]));
132  }
133  //ImageProcessor ipc = new FloatProcessor(n, 1, curvature, null);
134  //ipc.convolve(kernel3, kernel3.length, 1);
135  //PlotWindow pw = new PlotWindow("Curvature", "X", "Y", indexes, curvature);
136  //pw.draw();
137  return curvature;
138  }
139 
140  void drawEllipse(ImagePlus imp) {
141  IJ.showStatus("Fitting ellipse");
142  Roi roi = imp.getRoi();
143  ImageProcessor ip = imp.getProcessor();
144  ImageStatistics stats = imp.getStatistics();
145  EllipseFitter ef = new EllipseFitter();
146  ef.fit(ip, stats);
147  ef.makeRoi(ip);
148  imp.setRoi(new PolygonRoi(ef.xCoordinates, ef.yCoordinates, ef.nCoordinates, roi.FREEROI));
149  IJ.showStatus("");
150  }
151 
152  void convexHull(ImagePlus imp) {
153  Roi roi = imp.getRoi();
154  int type = roi!=null?roi.getType():-1;
155  if (!(type==Roi.FREEROI||type==Roi.TRACED_ROI||type==Roi.POLYGON))
156  {IJ.showMessage("Convex Hull", "Polygonal selection required"); return;}
157  imp.setRoi(makeConvexHull(imp, (PolygonRoi)roi));
158  }
159 
160  // Finds the convex hull using the gift wrap algorithm
161  Roi makeConvexHull(ImagePlus imp, PolygonRoi roi) {
162  int n = roi.getNCoordinates();
163  int[] xCoordinates = roi.getXCoordinates();
164  int[] yCoordinates = roi.getYCoordinates();
165  Rectangle r = roi.getBounds();
166  int xbase = r.x;
167  int ybase = r.y;
168  int[] xx = new int[n];
169  int[] yy = new int[n];
170  int n2 = 0;
171  int p1 = findFirstPoint(xCoordinates, yCoordinates, n, imp);
172  int pstart = p1;
173  int x1, y1, x2, y2, x3, y3, p2, p3;
174  int determinate;
175  do {
176  x1 = xCoordinates[p1];
177  y1 = yCoordinates[p1];
178  p2 = p1+1; if (p2==n) p2=0;
179  x2 = xCoordinates[p2];
180  y2 = yCoordinates[p2];
181  p3 = p2+1; if (p3==n) p3=0;
182  do {
183  x3 = xCoordinates[p3];
184  y3 = yCoordinates[p3];
185  determinate = x1*(y2-y3)-y1*(x2-x3)+(y3*x2-y2*x3);
186  if (determinate>0)
187  {x2=x3; y2=y3; p2=p3;}
188  p3 += 1;
189  if (p3==n) p3 = 0;
190  } while (p3!=p1);
191  if (n2<n) {
192  xx[n2] = xbase + x1;
193  yy[n2] = ybase + y1;
194  n2++;
195  }
196  p1 = p2;
197  } while (p1!=pstart);
198  return new PolygonRoi(xx, yy, n2, roi.POLYGON);
199  }
200 
201  // Finds the index of the upper right point that is guaranteed to be on convex hull
202  int findFirstPoint(int[] xCoordinates, int[] yCoordinates, int n, ImagePlus imp) {
203  int smallestY = imp.getHeight();
204  int x, y;
205  for (int i=0; i<n; i++) {
206  y = yCoordinates[i];
207  if (y<smallestY)
208  smallestY = y;
209  }
210  int smallestX = imp.getWidth();
211  int p1 = 0;
212  for (int i=0; i<n; i++) {
213  x = xCoordinates[i];
214  y = yCoordinates[i];
215  if (y==smallestY && x<smallestX) {
216  smallestX = x;
217  p1 = i;
218  }
219  }
220  return p1;
221  }
222 
223  void createMask(ImagePlus imp) {
224  Roi roi = imp.getRoi();
225  if (roi==null || !roi.isArea())
226  {IJ.showMessage("Create Mask", "Area selection required"); return;}
227  ImagePlus maskImp = IJ.getInstance().getImagePlus();
228  if (maskImp==null) {
229  ImageProcessor ip = new ByteProcessor(imp.getWidth(), imp.getHeight());
230  ip.invertLut();
231  maskImp = new ImagePlus("Mask", ip);
232  maskImp.show();
233  }
234  ImageProcessor ip = maskImp.getProcessor();
235  ip.setRoi(roi);
236  ip.setValue(255);
237  ip.fill(ip.getMask());
238  maskImp.updateAndDraw();
239  }
240 
241  void invert(ImagePlus imp) {
242  if (!IJ.isJava2())
243  {IJ.showMessage("Inverse", "Java 1.2 or later required"); return;}
244  Roi roi = imp.getRoi();
245  if (roi==null || !roi.isArea())
246  {IJ.showMessage("Inverse", "Area selection required"); return;}
247  ShapeRoi s1, s2;
248  if (roi instanceof ShapeRoi)
249  s1 = (ShapeRoi)roi;
250  else
251  s1 = new ShapeRoi(roi);
252 
253  s2 = new ShapeRoi(new Roi(0,0, imp.getWidth(), imp.getHeight()));
254  imp.setRoi(s1.xor(s2));
255  }
256 
257 }
258