2013-04-09 59 views
1

我的程序應該使用邊界填充方法中指定的顏色(開頭爲黑色和白色)填充非規則形狀。這裏是鏈接到myImage.png:https://dl.dropbox.com/u/41007907/myImage.png 我用一個很簡單的洪水填充算法,但它不以某種方式工作...以下是完整的代碼:使用Flood Fill算法時,爲什麼會出現java.lang.StackOverflowError?

import java.awt.Color; 
    import java.awt.Container; 
    import java.awt.Image; 
    import java.awt.image.BufferedImage; 
    import javax.swing.ImageIcon; 
    import javax.swing.JFrame; 
    import javax.swing.JLabel; 

     public class MyPolygon extends JFrame { 

private JLabel my; 

public MyPolygon() throws InterruptedException { 
    createMy(); 
} 

private void createMy() throws InterruptedException { 
    Container contentPane = getContentPane(); 
    contentPane.setBackground(Color.WHITE); 
    contentPane.setLayout(null); 
    contentPane.setSize(1000, 700); 

    my = new JLabel(); 
    my.setIcon(new ImageIcon("myImage.png")); 
    my.setBounds(50, 50, 300, 300); 
    contentPane.add(my); 

    setSize(1000, 700); 
    setVisible(true); 
    setLocationRelativeTo(null); 

    int fill = 100; 
    boundaryFill4(100, 100, fill, 50); 
} 

// Flood Fill method 
public void boundaryFill4(int x, int y, int fill, int boundary) { 
    int current; 
    current = getPixel(x, y); 
    if ((current >= boundary) && (current != fill)) { 
     setPixel(x, y, fill); 
     boundaryFill4(x + 1, y, fill, boundary); 
     boundaryFill4(x - 1, y, fill, boundary); 
     boundaryFill4(x, y + 1, fill, boundary); 
     boundaryFill4(x, y - 1, fill, boundary); 
    } 
} 

// Getting the color integer at specified point(x, y) 
private int getPixel(int x, int y) { 
    Image img = ((ImageIcon) my.getIcon()).getImage(); 
    BufferedImage buffered = new BufferedImage(img.getWidth(null), 
      img.getHeight(null), BufferedImage.TYPE_INT_ARGB); 
    buffered.getGraphics().drawImage(img, 0, 0, null); 
    Color c = new Color(buffered.getRGB(x, y)); 
    int current = buffered.getRGB(x, y); 
    return current; 
} 

// Setting the color integer to a specified point(x, y) 
private void setPixel(int x, int y, int fill) { 
    Image img = ((ImageIcon) my.getIcon()).getImage(); 
    BufferedImage buffered = new BufferedImage(img.getWidth(null), 
      img.getHeight(null), BufferedImage.TYPE_INT_ARGB); 
    buffered.getGraphics().drawImage(img, 0, 0, null); 
    int red = fill; 
    int green = fill; 
    int blue = fill; 
    Color c = new Color(buffered.getRGB(x, y)); 
    c = new Color(red, green, blue); 
    buffered.setRGB(x, y, c.getRGB()); 
} 

// Main method 
public static void main(String args[]) throws InterruptedException { 
    MyPolygon my = new MyPolygon(); 
    my.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
} 
} 

爲什麼會StackOverflow的錯誤?我如何糾正它,以便我的代碼工作?

+0

看起來像'boundaryFill4'會導致無限循環。它沒有這麼難調試,並找到自己的答案... – BobTheBuilder 2013-04-09 08:31:48

+0

可能重複[什麼是堆棧溢出錯誤?](http://stackoverflow.com/questions/214741/what-is-a-stack-溢出錯誤) – fglez 2013-04-10 09:25:45

回答

2

StackOverflowException意味着,你的遞歸太深了你的記憶或不會結束。 試試更小的圖片。當這不能解決問題時,遞歸結束條件會出現問題。 (setPixel()和getPixel是否真的改變圖像?寫一個JUnitTest

另外你真的應該簡化你的setPixel和getPixel方法。他們太複雜了。 對於您設置的每個像素,或者創建一個新的BufferedImage-Instance,然後在設置一個像素後進行處理。 您可以存儲和重用BufferedImage。

+0

一個問題是,我甚至沒有看到任何變化是顏色。該程序運行前10秒就好了,只有這樣它纔會卡住......所以我的觀點是我必須能夠在10秒內看到顏色的任何變化。我沒有看到? – Buras 2013-04-09 08:40:12

+0

好的,問題很簡單:您正在創建Icon的副本(如BufferedImage)。然後修改副本,但不要將更改回寫到圖標。也不要指望看到圖像修改,即使您將修改寫回來,因爲更改會在同一個線程中執行,並且只有在對圖像進行了所有更改之後,纔會更新窗口。 – MaPePeR 2013-04-09 08:45:19

+0

以前我一直在做沒有floodFill算法,即通過使用組合set/getter方法。我想我正在編譯器中寫入更改:buffered.serRGB ...我錯過了什麼。你會善意地糾正我應該如何將改變寫回到我的形象。 – Buras 2013-04-09 08:52:43

1

你應該調試你的boundaryFill4方法:它是發生無限循環的地方。使用簡單的情況來跟蹤方法如何反應。

此外,您應該避免在遞歸的每次迭代時寫入/讀取圖像。在開始時實例化一個表示圖像的正確且高效的數據結構,然後修改此數據結構,並在算法結束時將結果寫爲圖像。

+0

一個問題是,我甚至沒有看到任何改變是在程序工作正常的前10秒內的顏色。它只會在10秒後卡住...所以我的觀點是我必須能夠在這10秒內看到顏色的任何變化。我沒有看到? – Buras 2013-04-09 08:43:30

3

您可以嘗試將遞歸方法(boundaryFill4調用自己)轉換爲非遞歸方法。這樣JVM堆棧就不會溢出。

另一種辦法是增加堆棧的大小 - 見What is the maximum depth of the java call stack?

+0

你是什麼意思非遞歸。你的意思是我應該將圖像的每一部分分開作爲一個單獨的.png文件?如果是的話,我已經完成了...它工作正常...我想測試一個洪水填充方法 – Buras 2013-04-09 08:41:48

+0

我的意思是說你使用的遞歸很容易消耗一臺機器(在這種情況下,JVM) 。您可以嘗試重寫您的代碼來代替使用迭代,但也可以考慮其他答案。看到這個:http://stackoverflow.com/questions/931762/can-every-recursion-be-converted-into-iteration – orique 2013-04-09 08:46:47

相關問題