帆软使用的第三方框架。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

223 lines
6.5 KiB

package ij.process;
import ij.*;
import ij.gui.Toolbar;
import java.awt.Rectangle;
/** This class, which does flood filling, is used by the floodFill() macro function and
by the particle analyzer
The Wikipedia at "http://en.wikipedia.org/wiki/Flood_fill" has a good
description of the algorithm used here as well as examples in C and Java.
*/
public class FloodFiller {
int maxStackSize = 500; // will be increased as needed
int[] xstack = new int[maxStackSize];
int[] ystack = new int[maxStackSize];
int stackSize;
ImageProcessor ip;
int max;
boolean isFloat;
public FloodFiller(ImageProcessor ip) {
this.ip = ip;
isFloat = ip instanceof FloatProcessor;
}
/** Does a 4-connected flood fill using the current fill/draw
value, which is defined by ImageProcessor.setValue(). */
public boolean fill(int x, int y) {
int width = ip.getWidth();
int height = ip.getHeight();
int color = ip.getPixel(x, y);
fillLine(ip, x, x, y);
int newColor = ip.getPixel(x, y);
ip.putPixel(x, y, color);
if (color==newColor) return false;
stackSize = 0;
push(x, y);
while(true) {
x = popx();
if (x ==-1) return true;
y = popy();
if (ip.getPixel(x,y)!=color) continue;
int x1 = x; int x2 = x;
while (ip.getPixel(x1,y)==color && x1>=0) x1--; // find start of scan-line
x1++;
while (ip.getPixel(x2,y)==color && x2<width) x2++; // find end of scan-line
x2--;
fillLine(ip, x1,x2,y); // fill scan-line
boolean inScanLine = false;
for (int i=x1; i<=x2; i++) { // find scan-lines above this one
if (!inScanLine && y>0 && ip.getPixel(i,y-1)==color)
{push(i, y-1); inScanLine = true;}
else if (inScanLine && y>0 && ip.getPixel(i,y-1)!=color)
inScanLine = false;
}
inScanLine = false;
for (int i=x1; i<=x2; i++) { // find scan-lines below this one
if (!inScanLine && y<height-1 && ip.getPixel(i,y+1)==color)
{push(i, y+1); inScanLine = true;}
else if (inScanLine && y<height-1 && ip.getPixel(i,y+1)!=color)
inScanLine = false;
}
}
}
/** Does a 8-connected flood fill using the current fill/draw
value, which is defined by ImageProcessor.setValue(). */
public boolean fill8(int x, int y) {
int width = ip.getWidth();
int height = ip.getHeight();
int color = ip.getPixel(x, y);
int wm1=width-1;
int hm1=height-1;
fillLine(ip, x, x, y);
int newColor = ip.getPixel(x, y);
ip.putPixel(x, y, color);
if (color==newColor) return false;
stackSize = 0;
push(x, y);
while(true) {
x = popx();
if (x==-1) return true;
y = popy();
int x1 = x; int x2 = x;
if(ip.getPixel(x1,y)==color){
while (ip.getPixel(x1,y)==color && x1>=0) x1--; // find start of scan-line
x1++;
while (ip.getPixel(x2,y)==color && x2<width) x2++; // find end of scan-line
x2--;
fillLine(ip, x1,x2,y); // fill scan-line
}
if(y>0){
if (x1>0){
if (ip.getPixel(x1-1,y-1)==color){
push(x1-1,y-1);
}
}
if (x2<wm1){
if (ip.getPixel(x2+1,y-1)==color){
push(x2+1,y-1);
}
}
}
if(y<hm1){
if (x1>0){
if (ip.getPixel(x1-1,y+1)==color){
push(x1-1,y+1);
}
}
if (x2<wm1){
if (ip.getPixel(x2+1,y+1)==color){
push(x2+1,y+1);
}
}
}
boolean inScanLine = false;
for (int i=x1; i<=x2; i++) { // find scan-lines above this one
if (!inScanLine && y>0 && ip.getPixel(i,y-1)==color)
{push(i, y-1); inScanLine = true;}
else if (inScanLine && y>0 && ip.getPixel(i,y-1)!=color)
inScanLine = false;
}
inScanLine = false;
for (int i=x1; i<=x2; i++) {// find scan-lines below this one
if (!inScanLine && y<hm1 && ip.getPixel(i,y+1)==color)
{push(i, y+1); inScanLine = true;}
else if (inScanLine && y<hm1 && ip.getPixel(i,y+1)!=color)
inScanLine = false;
}
}
}
int count=0;
/** This method is used by the particle analyzer to remove interior holes from particle masks. */
public void particleAnalyzerFill(int x, int y, double level1, double level2, ImageProcessor mask, Rectangle bounds) {
int width = ip.getWidth();
int height = ip.getHeight();
//IJ.log("ff: "+x+" "+y+" "+level1+" "+level2+" "+ip+" "+mask+" "+bounds);
if (x==0&&y==0&&level1==0.0&&level2==255.0&&ip.getBitDepth()==8) {
ip.fill();
return;
}
mask.setColor(0);
mask.fill();
mask.setColor(255);
stackSize = 0;
push(x, y);
while(true) {
x = popx();
if (x ==-1) return;
y = popy();
if (!inParticle(x,y,level1,level2)) continue;
int x1 = x; int x2 = x;
while (inParticle(x1,y,level1,level2) && x1>=0) x1--; // find start of scan-line
x1++;
while (inParticle(x2,y,level1,level2) && x2<width) x2++; // find end of scan-line
x2--;
fillLine(mask, x1-bounds.x, x2-bounds.x, y-bounds.y); // fill scan-line i mask
fillLine(ip,x1,x2,y); // fill scan-line in image
boolean inScanLine = false;
if (x1>0) x1--; if (x2<width-1) x2++;
for (int i=x1; i<=x2; i++) { // find scan-lines above this one
if (!inScanLine && y>0 && inParticle(i,y-1,level1,level2))
{push(i, y-1); inScanLine = true;}
else if (inScanLine && y>0 && !inParticle(i,y-1,level1,level2))
inScanLine = false;
}
inScanLine = false;
for (int i=x1; i<=x2; i++) { // find scan-lines below this one
if (!inScanLine && y<height-1 && inParticle(i,y+1,level1,level2))
{push(i, y+1); inScanLine = true;}
else if (inScanLine && y<height-1 && !inParticle(i,y+1,level1,level2))
inScanLine = false;
}
}
}
final boolean inParticle(int x, int y, double level1, double level2) {
if (isFloat)
return ip.getPixelValue(x,y)>=level1 && ip.getPixelValue(x,y)<=level2;
else {
int v = ip.getPixel(x,y);
return v>=level1 && v<=level2;
}
}
final void push(int x, int y) {
stackSize++;
if (stackSize==maxStackSize) {
int[] newXStack = new int[maxStackSize*2];
int[] newYStack = new int[maxStackSize*2];
System.arraycopy(xstack, 0, newXStack, 0, maxStackSize);
System.arraycopy(ystack, 0, newYStack, 0, maxStackSize);
xstack = newXStack;
ystack = newYStack;
maxStackSize *= 2;
}
xstack[stackSize-1] = x;
ystack[stackSize-1] = y;
}
final int popx() {
if (stackSize==0)
return -1;
else
return xstack[stackSize-1];
}
final int popy() {
int value = ystack[stackSize-1];
stackSize--;
return value;
}
final void fillLine(ImageProcessor ip, int x1, int x2, int y) {
if (x1>x2) {int t = x1; x1=x2; x2=t;}
for (int x=x1; x<=x2; x++)
ip.drawPixel(x, y);
}
}