泛洪算法有3中不同的方式,每种算法有两种形式一种是递归的一种是非递归的。一般来说对于递归的算法我们比较容易实现,但是若所需处理的对象非常大,递归算法非常消耗内存。下面我们将介绍这几种算法:
(1)四邻域泛洪算法
四邻域泛洪算法的思想是对于像素点(x,y),将其着色之后将其周围的上下左右四个点分别进行着色。其递归方式为:
void floodFill4(int x, int y, int newColor, int oldColor)
{
if(x >= 0 && x < w && y >= 0 && y < h && screenBuffer[y][x][y] == oldColor && screenBuffer[x] != newColor)
{
screenBuffer[y][x] = newColor;
floodFill4(x + 1, y , newColor, oldColor);
floodFill4(x - 1, y , newColor, oldColor);
floodFill4(x , y + 1, newColor, oldColor);
floodFill4(x , y - 1, newColor, oldColor);
}
}
递归方式非常消耗内存,若所需着色的面积非常大,会导致溢出现象。因此,下面我们将介绍四邻域泛洪算法的非递归方式。这里我们使用一个栈来存储未被着色的点,然后依次将存在于着色空间内的点的上下左右的点加入栈,依次着色直到栈为空。
void floodFill4Stack(int x, int y, int newColor, int oldColor)
{
if(newColor == oldColor) return; //avoid infinite loop
emptyStack();
static const int dx[4] = {0, 1, 0, -1};
static const int dy[4] = {-1, 0, 1, 0};
if(!push(x, y)) return;
while(pop(x, y))
{
screenBuffer[y][x] = newColor;
for(int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if(nx > 0 && nx < w && ny > 0 && ny < h && screenBuffer[ny][nx] == oldColor) {
if(!push(nx, ny)) return;
}
}
}
}
(2)八邻域泛洪算法
void floodFill8(int x, int y, int newColor, int oldColor)
{
if(x >= 0 && x < w && y >= 0 && y < h && screenBuffer[y][x][y] == oldColor && screenBuffer[x] != newColor)
{
screenBuffer[y][x] = newColor;
floodFill8(x + 1, y , newColor, oldColor);
floodFill8(x - 1, y , newColor, oldColor);
floodFill8(x , y + 1, newColor, oldColor);
floodFill8(x , y - 1, newColor, oldColor);
floodFill8(x + 1, y + 1, newColor, oldColor);
floodFill8(x - 1, y - 1, newColor, oldColor);
floodFill8(x - 1, y + 1, newColor, oldColor);
floodFill8(x + 1, y - 1, newColor, oldColor);
}
}
非递归方式为:
void floodFill8Stack(int x, int y, int newColor, int oldColor)
{
if(newColor == oldColor) return; //avoid infinite loop
emptyStack();
static const int dx[8] = {0, 1, 1, 1, 0, -1, -1, -1};
static const int dy[8] = {-1, -1, 0, 1, 1, 1, 0, -1};
if(!push(x, y)) return;
while(pop(x, y))
{
screenBuffer[y][x] = newColor;
for(int i = 0; i < 8; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
if(nx > 0 && nx < w && ny > 0 && ny < h && screenBuffer[ny][nx] == oldColor) {
if(!push(nx, ny)) return;
}
}
}
}
(3)扫描线算法
void floodFillScanline(int x, int y, int newColor, int oldColor){
if(newColor==oldColor) return;
if(screen[x][y]!=oldColor) return;
int x1=x;
while(x1=0&&screen[x1][y]==oldColor){
screen[x1][y]=newColor;
x1--;
}
x1=x;
while(x10&&screen[x1][y]==newColor){
if(y>0&&screen[x1][y+1]==oldColor) floodFillScanline(x1,y+1,newColor,oldColor);
x1--;
}
x1=x;
while(x10&&screen[x1][y]==newColor){
if(y>0&&screen[x1][y-1]==oldColor) floodFillScanline(x1,y+1,newColor,oldColor);
x1--;
}
}
该算法的非递归方式为:
void floodFillScanline(int x, int y, int newColor, int oldColor){
if(newColor==oldColor) return;
if(screen[x][y]!=oldColor) return;
emptyStack();
int x1;
bool spanAbove, spanBelow;
if(!push(x,y)) return;
while(pop(x,y)){
x1=x;
while(x1>0&&screen[x1][y]==oldColor) x1--;
x1++;
spanAbove = spanBelow = 0;
while(x10&&screen[x1][y-1]==oldColor){
if(!push(x1,y-1)) return;
spanAbove=1;
}
else if(spanAbove&&y>0&&screen[x1][y-1]!=oldColor){
spanAbove=1;
}
if(!spanBelow&&y