|
OvalRoi |
|
package ij.gui;
import java.awt.*;
import java.awt.image.*;
import ij.*;
import ij.process.*;
import ij.measure.Calibration;
/** Oval region of interest */
public class OvalRoi extends Roi {
/** Creates a new OvalRoi.*/
public OvalRoi(int x, int y, int width, int height) {
super(x, y, width, height);
type = OVAL;
}
/** Starts the process of creating a user-defined OvalRoi. */
public OvalRoi(int x, int y, ImagePlus imp) {
super(x, y, imp);
type = OVAL;
}
/** Obsolete */
public OvalRoi(int x, int y, int width, int height, ImagePlus imp) {
this(x, y, width, height);
setImage(imp);
}
protected void moveHandle(int sx, int sy) {
if (clipboard!=null) return;
int ox = ic.offScreenX(sx);
int oy = ic.offScreenY(sy);
//IJ.log("moveHandle: "+activeHandle+" "+ox+" "+oy);
int x1=x, y1=y, x2=x1+width, y2=y+height;
int w2 = (int)(0.14645*width);
int h2 = (int)(0.14645*height);
switch (activeHandle) {
case 0: x=ox-w2; y=oy-h2; break;
case 1: y=oy; break;
case 2: x2=ox+w2; y=oy-h2; break;
case 3: x2=ox; break;
case 4: x2=ox+w2; y2=oy+h2; break;
case 5: y2=oy; break;
case 6: x=ox-w2; y2=oy+h2; break;
case 7: x=ox; break;
}
//if (x<0) x=0; if (y<0) y=0;
if (x<x2)
width=x2-x;
else
{width=1; x=x2;}
if (y<y2)
height = y2-y;
else
{height=1; y=y2;}
if (constrain)
height = width;
updateClipRect();
imp.draw(clipX, clipY, clipWidth, clipHeight);
oldX=x; oldY=y;
oldWidth=width; oldHeight=height;
cachedMask = null;
}
public void draw(Graphics g) {
if (ic==null) return;
g.setColor(instanceColor!=null?instanceColor:ROIColor);
mag = ic.getMagnification();
int sw = (int)(width*mag);
int sh = (int)(height*mag);
int sw2 = (int)(0.14645*width*mag);
int sh2 = (int)(0.14645*height*mag);
int sx1 = ic.screenX(x);
int sy1 = ic.screenY(y);
int sx2 = sx1+sw/2;
int sy2 = sy1+sh/2;
int sx3 = sx1+sw;
int sy3 = sy1+sh;
g.drawOval(sx1, sy1, sw, sh);
if (state!=CONSTRUCTING && clipboard==null) {
int size2 = HANDLE_SIZE/2;
drawHandle(g, sx1+sw2-size2, sy1+sh2-size2);
drawHandle(g, sx3-sw2-size2, sy1+sh2-size2);
drawHandle(g, sx3-sw2-size2, sy3-sh2-size2);
drawHandle(g, sx1+sw2-size2, sy3-sh2-size2);
drawHandle(g, sx2-size2, sy1-size2);
drawHandle(g, sx3-size2, sy2-size2);
drawHandle(g, sx2-size2, sy3-size2);
drawHandle(g, sx1-size2, sy2-size2);
}
drawPreviousRoi(g);
if (updateFullWindow)
{updateFullWindow = false; imp.draw();}
if (state!=NORMAL) showStatus();
}
/** Draws an outline of this OvalRoi on the image. */
public void drawPixels(ImageProcessor ip) {
Polygon p = getPolygon();
if (p.npoints>0) ip.drawPolygon(p);
if (Line.getWidth()>1)
updateFullWindow = true;
}
/** Returns this OvalRoi as a polygon. */
public Polygon getPolygon() {
ImageProcessor mask = getMask();
Wand wand = new Wand(mask);
wand.autoOutline(width/2,height/2, 255, 255);
for (int i=0; i<wand.npoints; i++) {
wand.xpoints[i] += x;
wand.ypoints[i] += y;
}
return new Polygon(wand.xpoints, wand.ypoints, wand.npoints);
}
/** Tests if the specified point is inside the boundary of this OvalRoi.
@author Michael Schmid
*/
public boolean contains(int x, int y) {
// equation for an ellipse is x^2/a^2 + y^2/b^2 = 1
if (!super.contains(x, y))
return false;
else {
int twoDx = 2*x - (2*this.x+width-1);
int twoDy = 2*y - (2*this.y+height-1);
int twoRx = width;
int twoRy = height;
return (twoDx*twoDx/(double)(twoRx*twoRx)
+ twoDy*twoDy/(double)(twoRy*twoRy)) < 1;
}
}
/** Returns a handle number if the specified screen coordinates are
inside or near a handle, otherwise returns -1. */
public int isHandle(int sx, int sy) {
if (clipboard!=null || ic==null) return -1;
double mag = ic.getMagnification();
int size = HANDLE_SIZE+3;
int halfSize = size/2;
int sx1 = ic.screenX(x) - halfSize;
int sy1 = ic.screenY(y) - halfSize;
int sx3 = ic.screenX(x+width) - halfSize;
int sy3 = ic.screenY(y+height) - halfSize;
int sx2 = sx1 + (sx3 - sx1)/2;
int sy2 = sy1 + (sy3 - sy1)/2;
int sw2 = (int)(0.14645*(sx3-sx1));
int sh2 = (int)(0.14645*(sy3-sy1));
if (sx>=sx1+sw2&&sx<=sx1+sw2+size&&sy>=sy1+sh2&&sy<=sy1+sh2+size) return 0;
if (sx>=sx2&&sx<=sx2+size&&sy>=sy1&&sy<=sy1+size) return 1;
if (sx>=sx3-sw2&&sx<=sx3-sw2+size&&sy>=sy1+sh2&&sy<=sy1+sh2+size) return 2;
if (sx>=sx3&&sx<=sx3+size&&sy>=sy2&&sy<=sy2+size) return 3;
if (sx>=sx3-sw2&&sx<=sx3-sw2+size&&sy>=sy3-sh2&&sy<=sy3-sh2+size) return 4;
if (sx>=sx2&&sx<=sx2+size&&sy>=sy3&&sy<=sy3+size) return 5;
if (sx>=sx1+sw2&&sx<=sx1+sw2+size&&sy>=sy3-sh2&&sy<=sy3-sh2+size) return 6;
if (sx>=sx1&&sx<=sx1+size&&sy>=sy2&&sy<=sy2+size) return 7;
return -1;
}
public ImageProcessor getMask() {
if (cachedMask!=null && cachedMask.getPixels()!=null)
return cachedMask;
ImageProcessor mask = new ByteProcessor(width, height);
double a=width/2.0, b=height/2.0;
double a2=a*a, b2=b*b;
a -= 0.5; b -= 0.5;
double xx, yy;
int offset;
byte[] pixels = (byte[])mask.getPixels();
for (int y=0; y<height; y++) {
offset = y*width;
for (int x=0; x<width; x++) {
xx = x - a;
yy = y - b;
if ((xx*xx/a2+yy*yy/b2)<=1.0)
pixels[offset+x] = -1;
}
}
cachedMask = mask;
return mask;
}
/** Returns the perimeter length. */
public double getLength() {
double pw=1.0, ph=1.0;
if (imp!=null) {
Calibration cal = imp.getCalibration();
pw = cal.pixelWidth;
ph = cal.pixelHeight;
}
return Math.PI*(width*pw+height*ph)/2.0;
}
/** Returns Feret's diameter, the greatest distance between
any two points along the ROI boundary. */
public double getFeretsDiameter() {
double pw=1.0, ph=1.0;
if (imp!=null) {
Calibration cal = imp.getCalibration();
pw = cal.pixelWidth;
ph = cal.pixelHeight;
}
return width*pw>=height*ph?width*pw:height*ph;
}
}
|
OvalRoi |
|