优化自定义洪水填充算法 (Java)
Refining custom flood fill algorithm (Java)
我完全没有使用任何类型的洪水填充算法的经验。但我尽力了。起初,我会在用户点击的地方用洋红色填充一个像素,然后通过一个循环在每个洋红色像素的顶部、左侧、底部和右侧绘制一个像素。这最多需要 8 秒才能完成特别大的区域的填充。所以我添加了另一个循环,向上、向下、向左和向右绘制直的洋红色线条。这将时间减半。我让电脑画了更多的线……左上、左上、左上、左下、左下……等等。现在缩短到 1 到 2 秒之间。我还能做些什么来减少完成填充所需的时间?
for(Point p:shiftDownPoints)
{
//down
for(int y = p.y+1; y<SCREEN_DIM.height; y++)
{
if(capture.getRGB(p.x,y)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x,y,Color.MAGENTA.getRGB());
}
//up
for(int y = p.y-1; y>0; y--)
{
if(capture.getRGB(p.x,y)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x,y,Color.MAGENTA.getRGB());
}
//right
for(int x = p.x+1; x<SCREEN_DIM.width; x++)
{
if(capture.getRGB(x,p.y)==Color.BLACK.getRGB())break;
else capture.setRGB(x,p.y,Color.MAGENTA.getRGB());
}
//left
for(int x = p.x-1; x>0; x--)
{
if(capture.getRGB(x,p.y)==Color.BLACK.getRGB())break;
else capture.setRGB(x,p.y,Color.MAGENTA.getRGB());
}
//down-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i,p.y+i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i,p.y+i,Color.MAGENTA.getRGB());
}
//down-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i,p.y+i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i,p.y+i,Color.MAGENTA.getRGB());
}
//up-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i,p.y-i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i,p.y-i,Color.MAGENTA.getRGB());
}
//up-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i,p.y-i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i,p.y-i,Color.MAGENTA.getRGB());
}
//up-up-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i,p.y-i*2)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i,p.y-i*2,Color.MAGENTA.getRGB());
}
//up-left-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i*2,p.y-i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i*2,p.y-i,Color.MAGENTA.getRGB());
}
//down-left-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i*2,p.y+i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i*2,p.y+i,Color.MAGENTA.getRGB());
}
//down-down-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i,p.y+i*2)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i,p.y+i*2,Color.MAGENTA.getRGB());
}
//down-down-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i,p.y+i*2)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i,p.y+i*2,Color.MAGENTA.getRGB());
}
//down-right-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i*2,p.y+i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i*2,p.y+i,Color.MAGENTA.getRGB());
}
//up-right-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i*2,p.y-i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i*2,p.y-i,Color.MAGENTA.getRGB());
}
//up-up-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i,p.y-i*2)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i,p.y-i*2,Color.MAGENTA.getRGB());
}
}
while(pixelsDrawn)
{
pixelsDrawn=false;
for(int x = 0; x<SCREEN_DIM.width; x++)
for(int y = 0; y<SCREEN_DIM.height; y++)
{
if(capture.getRGB(x,y)==Color.MAGENTA.getRGB())
{
if(capture.getRGB(x-1,y)!=Color.MAGENTA.getRGB()
&&capture.getRGB(x-1,y)!=Color.BLACK.getRGB())
{
capture.setRGB(x-1,y,Color.MAGENTA.getRGB());
pixelsDrawn = true;
}
if(capture.getRGB(x+1,y)!=Color.MAGENTA.getRGB()
&&capture.getRGB(x+1,y)!=Color.BLACK.getRGB())
{
capture.setRGB(x+1,y,Color.MAGENTA.getRGB());
pixelsDrawn = true;
}
if(capture.getRGB(x,y-1)!=Color.MAGENTA.getRGB()
&&capture.getRGB(x,y-1)!=Color.BLACK.getRGB())
{
capture.setRGB(x,y-1,Color.MAGENTA.getRGB());
pixelsDrawn = true;
}
if(capture.getRGB(x,y+1)!=Color.MAGENTA.getRGB()
&&capture.getRGB(x,y+1)!=Color.BLACK.getRGB())
{
capture.setRGB(x,y+1,Color.MAGENTA.getRGB());
pixelsDrawn = true;
}
}
}
}
讨论洪水填充算法可能需要一个完整的 class session。我认为您应该参考 This Link,因为它解释了一切,pixel-by-pixel 如何(有效地)与算法一起绘制。希望这有帮助。
多亏了immibis的建议,我把flood-fill缩短到了半秒。在这个新代码中,我让计算机沿着轮廓的边缘创建一个多边形,然后只使用图形中的 fillPolygon。
for(Point p:iterablePoints)
{
int dir = 2; //0:right, 1:down, 2:left, 3:up
int xPos = p.x;
int yPos = 0;
Polygon poly = new Polygon();
for(int y = p.y; y>0; y--)
{
if(capture.getRGB(p.x,y-1)==Color.BLACK.getRGB())
{
yPos = y;
break;
}
}
Vector<Point> tempRecord = new Vector<Point>();
boolean run = true;
while(run)
{
if(dir==0&&capture.getRGB(xPos+1,yPos)==Color.BLACK.getRGB())dir--;
else if(dir==1&&capture.getRGB(xPos,yPos+1)==Color.BLACK.getRGB())dir--;
else if(dir==2&&capture.getRGB(xPos-1,yPos)==Color.BLACK.getRGB())dir--;
else if(dir==3&&capture.getRGB(xPos,yPos-1)==Color.BLACK.getRGB())dir--;
else
{
if(dir==0)xPos++;
if(dir==1)yPos++;
if(dir==2)xPos--;
if(dir==3)yPos--;
dir++;
tempRecord.add(new Point(xPos,yPos));
if(tempRecord.size()>1)if(tempRecord.get(0)==tempRecord.get(1))tempRecord.remove(tempRecord.firstElement());
else startPoint = tempRecord.get(0);
if(startPoint!=null)if(startPoint.x==xPos&&startPoint.y==yPos) run=false;
poly.addPoint(xPos,yPos);capture.setRGB(xPos,yPos,Color.MAGENTA.getRGB());
}
if(dir==4)dir=0;
if(dir==-1)dir=3;
}
Graphics cg = capture.getGraphics();
cg.setColor(Color.MAGENTA);
cg.fillPolygon(poly);
cg.dispose();
}
我完全没有使用任何类型的洪水填充算法的经验。但我尽力了。起初,我会在用户点击的地方用洋红色填充一个像素,然后通过一个循环在每个洋红色像素的顶部、左侧、底部和右侧绘制一个像素。这最多需要 8 秒才能完成特别大的区域的填充。所以我添加了另一个循环,向上、向下、向左和向右绘制直的洋红色线条。这将时间减半。我让电脑画了更多的线……左上、左上、左上、左下、左下……等等。现在缩短到 1 到 2 秒之间。我还能做些什么来减少完成填充所需的时间?
for(Point p:shiftDownPoints)
{
//down
for(int y = p.y+1; y<SCREEN_DIM.height; y++)
{
if(capture.getRGB(p.x,y)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x,y,Color.MAGENTA.getRGB());
}
//up
for(int y = p.y-1; y>0; y--)
{
if(capture.getRGB(p.x,y)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x,y,Color.MAGENTA.getRGB());
}
//right
for(int x = p.x+1; x<SCREEN_DIM.width; x++)
{
if(capture.getRGB(x,p.y)==Color.BLACK.getRGB())break;
else capture.setRGB(x,p.y,Color.MAGENTA.getRGB());
}
//left
for(int x = p.x-1; x>0; x--)
{
if(capture.getRGB(x,p.y)==Color.BLACK.getRGB())break;
else capture.setRGB(x,p.y,Color.MAGENTA.getRGB());
}
//down-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i,p.y+i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i,p.y+i,Color.MAGENTA.getRGB());
}
//down-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i,p.y+i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i,p.y+i,Color.MAGENTA.getRGB());
}
//up-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i,p.y-i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i,p.y-i,Color.MAGENTA.getRGB());
}
//up-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i,p.y-i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i,p.y-i,Color.MAGENTA.getRGB());
}
//up-up-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i,p.y-i*2)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i,p.y-i*2,Color.MAGENTA.getRGB());
}
//up-left-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i*2,p.y-i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i*2,p.y-i,Color.MAGENTA.getRGB());
}
//down-left-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i*2,p.y+i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i*2,p.y+i,Color.MAGENTA.getRGB());
}
//down-down-left
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x-i,p.y+i*2)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x-i,p.y+i*2,Color.MAGENTA.getRGB());
}
//down-down-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i,p.y+i*2)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i,p.y+i*2,Color.MAGENTA.getRGB());
}
//down-right-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i*2,p.y+i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i*2,p.y+i,Color.MAGENTA.getRGB());
}
//up-right-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i*2,p.y-i)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i*2,p.y-i,Color.MAGENTA.getRGB());
}
//up-up-right
for(int i = 1; i<Math.min(SCREEN_DIM.width,SCREEN_DIM.height); i++)
{
if(capture.getRGB(p.x+i,p.y-i*2)==Color.BLACK.getRGB())break;
else capture.setRGB(p.x+i,p.y-i*2,Color.MAGENTA.getRGB());
}
}
while(pixelsDrawn)
{
pixelsDrawn=false;
for(int x = 0; x<SCREEN_DIM.width; x++)
for(int y = 0; y<SCREEN_DIM.height; y++)
{
if(capture.getRGB(x,y)==Color.MAGENTA.getRGB())
{
if(capture.getRGB(x-1,y)!=Color.MAGENTA.getRGB()
&&capture.getRGB(x-1,y)!=Color.BLACK.getRGB())
{
capture.setRGB(x-1,y,Color.MAGENTA.getRGB());
pixelsDrawn = true;
}
if(capture.getRGB(x+1,y)!=Color.MAGENTA.getRGB()
&&capture.getRGB(x+1,y)!=Color.BLACK.getRGB())
{
capture.setRGB(x+1,y,Color.MAGENTA.getRGB());
pixelsDrawn = true;
}
if(capture.getRGB(x,y-1)!=Color.MAGENTA.getRGB()
&&capture.getRGB(x,y-1)!=Color.BLACK.getRGB())
{
capture.setRGB(x,y-1,Color.MAGENTA.getRGB());
pixelsDrawn = true;
}
if(capture.getRGB(x,y+1)!=Color.MAGENTA.getRGB()
&&capture.getRGB(x,y+1)!=Color.BLACK.getRGB())
{
capture.setRGB(x,y+1,Color.MAGENTA.getRGB());
pixelsDrawn = true;
}
}
}
}
讨论洪水填充算法可能需要一个完整的 class session。我认为您应该参考 This Link,因为它解释了一切,pixel-by-pixel 如何(有效地)与算法一起绘制。希望这有帮助。
多亏了immibis的建议,我把flood-fill缩短到了半秒。在这个新代码中,我让计算机沿着轮廓的边缘创建一个多边形,然后只使用图形中的 fillPolygon。
for(Point p:iterablePoints)
{
int dir = 2; //0:right, 1:down, 2:left, 3:up
int xPos = p.x;
int yPos = 0;
Polygon poly = new Polygon();
for(int y = p.y; y>0; y--)
{
if(capture.getRGB(p.x,y-1)==Color.BLACK.getRGB())
{
yPos = y;
break;
}
}
Vector<Point> tempRecord = new Vector<Point>();
boolean run = true;
while(run)
{
if(dir==0&&capture.getRGB(xPos+1,yPos)==Color.BLACK.getRGB())dir--;
else if(dir==1&&capture.getRGB(xPos,yPos+1)==Color.BLACK.getRGB())dir--;
else if(dir==2&&capture.getRGB(xPos-1,yPos)==Color.BLACK.getRGB())dir--;
else if(dir==3&&capture.getRGB(xPos,yPos-1)==Color.BLACK.getRGB())dir--;
else
{
if(dir==0)xPos++;
if(dir==1)yPos++;
if(dir==2)xPos--;
if(dir==3)yPos--;
dir++;
tempRecord.add(new Point(xPos,yPos));
if(tempRecord.size()>1)if(tempRecord.get(0)==tempRecord.get(1))tempRecord.remove(tempRecord.firstElement());
else startPoint = tempRecord.get(0);
if(startPoint!=null)if(startPoint.x==xPos&&startPoint.y==yPos) run=false;
poly.addPoint(xPos,yPos);capture.setRGB(xPos,yPos,Color.MAGENTA.getRGB());
}
if(dir==4)dir=0;
if(dir==-1)dir=3;
}
Graphics cg = capture.getGraphics();
cg.setColor(Color.MAGENTA);
cg.fillPolygon(poly);
cg.dispose();
}