2009-05-24 57 views
0

我写了这个函数来填充闭环,pixvali是全局声明的,用于存储第一次点击将完成的像素的颜色值(闭环内)。为什么堆栈在这段代码中溢出?

但问题是,当它的第一个*填充(..,..)*渡过这个递归并不终止,并说栈溢出...

void fill(int x,int y) 
{ 
    GLfloat pixval[3]; 
    glReadPixels(x,y,1,1,GL_RGB,GL_FLOAT,pixval); 
    if(pixval[0]==pixvali[0] && pixval[1]==pixvali[1] && pixval[2]== pixvali[2]) 
    { 
     glBegin(GL_POINTS); 
      glVertex2i(x,y); 
     glEnd(); 
     glFlush(); 
     fill(x-1,y); 
     fill(x+1,y); 
     fill(x,y-1); 
     fill(x,y+1); 
    } 
} 
+1

并将语言添加到标签。它可能看起来像C,但有相当多的语言看起来像C :) – extraneon 2009-05-24 12:16:29

+0

是设置在任何地方的像素值? – Dario 2009-05-24 12:19:04

+0

我的水晶球告诉我'pixvali'是应该充满水的颜色。 – 2009-05-24 12:22:48

回答

0

实现您自己的堆栈,不要使用递归进行填充填充,除非您填充的像素比较小的表面区域的形状。

一个典型的实现是:

Stack stack; 
stack.push(firstPoint); 

while(!stack.isEmpty()){ 
    Point currentPoint= stack.pop(); 
    //do what ever you want to do here, namely paint. 
    //boundary check ur surrounding points and push them in the stack if they are inbounds 
} 
4

的堆栈溢出因为您正在使用递归,并且递归的深度与要填充的形状中的像素数成线性关系。

也可能是因为您试图以与原来相同的颜色填充形状。也就是说,当前的gl颜色与pixvali相同。在这种情况下,你会得到无限递归。

3

这个问题很难说,但我的猜测是,你开始进入一个像素循环。例如,假设您只有4个像素需要着色(0,0),(0,1),(1,0),(1,1)。

你开始着色(0,0)。然后你的递归将进入(1,0),因为(-1,0)不需要着色。然后再次(0,0),因为它的像素是(x-1,y),等等。

您需要添加一些方法来标记已经着色的像素。但这只是一种猜测,因为你无法真正了解那些功能以外发生了什么。

1

不知道的实施细则,但如果12字节本地数组在栈上分配(3漂浮每4个字节),那么你必须每4个字节为x和y参数,并可能返回地址的四个字节。每次你递归的时候至少有24次。这意味着如果没有其他东西,你只需要多于40,000个电话就可以通过1MB的堆栈空间,这不会是真的。

为了说明这一点,43'690像素仅为800x600显示器的10%左右。

1

你需要检查你正在编辑的像素。

例如如果你有一个从0,0到10,10的图像,并且你编辑了11,10,你会得到记忆。

所以你需要检查x,y是否在图像边界之间。

x>=left&&x<=right&&y>=top&&y<=bottom 
0

乍一看,算法看起来不错。我有点担心“==”,因为它们不适用于浮点值。我建议使用

abs(val1 - val2) < limit 

代替(其中limit是< 1和> 0尝试0.0001,例如)。

为了追踪这个错误,我建议在函数的开头添加一个printf()。当你看到函数试图填充什么时,这将有所帮助。也许它卡在某个地方,并以相同的坐标一次又一次地调用自己?

此外,对于您尝试填充的区域,堆栈可能太简单。先尝试一个小区域,例如一个只有4 x 3像素的小矩形。不要试图用鼠标点击它,而是从内部已知的好点开始(只需在代码中调用fill())。

也打印颜色的值可能会有所帮助。

0

你为什么要滥用OpenGL?你在那里做什么是非常不稳定的。例如,如果使用精心选择的投影和模型视图矩阵组合,那么由glReadPixels读取的像素将只对应于顶点位置。每次填充的迭代都会进行一次完整的往返。仅仅因为你使用的是OpenGL,它并没有神奇的速度。

如果您想在帧缓冲区中填充一些区域,读取整个帧缓冲区,对其进行填充并将结果推回到OpenGL。此外,如果帧缓冲区的某些部分被遮挡(通过窗口或类似物体),那些部分将不会是

现在理解为什么最终会出现无限递归。试想一下:

fill(4, 4)将调用fill(5, 4)将调用fill(5, 5)将调用fill(4, 5)将调用fill(4, 4)热潮

现在你已经有了测试有:

if(pixval[0] == pixvali[0] && 
    pixval[1] == pixvali[1] && 
    pixval[2] == pixvali[2]) 

注意,这个判断为真如果要设置的像素已经具有目标颜色,则再次以无限递归的方式卷绕起来。您应该测试不等式

最后但并非最不重要:一张图片可能容易由数百万像素组成。通常的堆栈大小只允许最多1000个函数嵌套级别,因此您必须将尾部递归转换为迭代。

TL; DR:不要为此使用OpenGL,在本地缓冲区上操作,使用正确的迭代条件测试并使用迭代而不是递归(或者使用函数式语言,那么编译器会处理尾部递归)。

http://en.wikipedia.org/wiki/Flood_fill