2009-05-24 87 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