2013-04-09 4 views
1

Mon programme est censé remplir une forme non-régulière avec une couleur (noir et blanc pour le début) que je spécifie dans la méthode boundaryFill4. Voici le lien vers myImage.png: https://dl.dropbox.com/u/41007907/myImage.png J'utilise un algorithme de remplissage d'inondation très simple, mais il ne fonctionne pas en quelque sorte ... Voici le code complet:Pourquoi ai-je java.lang.StackOverflowError lors de l'utilisation de l'algorithme Flood Fill?

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); 
} 
} 

Pourquoi puis-je obtenir l'erreur StackOverflow? Comment puis-je corriger pour que mon code fonctionne?

+0

On dirait que 'borderFill4' provoque une boucle infinie. Ce n'est pas si difficile de déboguer et de trouver la réponse par vous-même ... – BobTheBuilder

+0

duplication possible de [Qu'est-ce qu'une erreur de débordement de pile?] (Http://stackoverflow.com/questions/214741/what-is-a-stack- erreur de débordement) – fglez

Répondre

2

StackOverflowException signifie que votre récursion est trop profond pour votre mémoire ou ne se termine pas. Essayez une image plus petite. Lorsque cela ne résout pas le problème, il y a quelque chose qui ne va pas dans votre condition de fin de récursivité. (Est-ce que setPixel() et getPixel changent vraiment l'image? Écrivez un JUnitTest)

Aussi vous devriez vraiment simplifier vos méthodes setPixel et getPixel. Ils sont trop complexes. Pour chaque Pixel que vous définissez ou obtenez vous créez une nouvelle BufferedImage-Instance et puis le disposer après avoir réglé un pixel. Vous pouvez stocker et réutiliser le BufferedImage.

+0

Un problème est que je ne vois même pas les changements de couleur. Le programme tourne bien pendant les 10 premières secondes et seulement alors il sera coincé ... donc mon point est que je dois être capable de voir au moins les changements de couleur pendant ces 10 secondes. Et je n'en vois pas? – Buras

+0

Ok, le problème est très facile: vous créez une copie de votre icône (comme BufferedImage). Ensuite, vous modifiez la copie, mais n'écrivez jamais les modifications sur votre icône. Ne vous attendez pas non plus à voir la modification de l'image, même lorsque vous écrivez les modifications, car les modifications sont exécutées dans le même thread et la fenêtre ne se mettra pas à jour tant que toutes les modifications de l'image n'auront pas été effectuées. – MaPePeR

+0

Auparavant, je le faisais sans algorithme floodFill, c'est-à-dire en utilisant une méthode combinée set/getter. Je pense que j'écris les changements dans le setter: buffered.serRGB ... Ai-je raté quelque chose?Souhaitez-vous apporter des corrections à la façon dont je devrais écrire des modifications à mon image. – Buras

1

Vous devez déboguer votre méthode boundaryFill4: c'est là qu'une boucle infinie se produit. Utilisez des cas simples pour suivre la réaction de la méthode.

De plus, vous devriez éviter d'écrire/lire l'image à chaque itération de la récursivité. Instancier une structure de données correcte et efficace représentant l'image au début, puis modifier cette structure de données et lorsque l'algorithme se termine, écrire les résultats sous forme d'image.

+0

Un problème est que je ne vois même pas les changements de couleur pendant les 10 premières secondes lorsque le programme fonctionne correctement. Il restera bloqué seulement après ces 10 secondes ... donc mon point est que je dois être capable de voir au moins les changements de couleur pendant ces 10 secondes. Et je n'en vois pas? – Buras

3

Vous pouvez essayer de transformer votre approche récursive (boundaryFill4 en s'appelle lui-même) en une approche non récursive. De cette façon, la pile JVM ne déborderait pas.

Une autre option serait d'augmenter la taille de la pile - voir What is the maximum depth of the java call stack?

+0

que voulez-vous dire par non récursif. Voulez-vous dire que je devrais séparer chaque section de l'image dans un fichier .png distinct? Si oui, je l'ai fait ... ça marche bien ... Je voulais tester une méthode de remplissage d'inondation – Buras

+0

Je veux dire que vous utilisez la récursivité qui est susceptible de consommer la pile d'une machine (dans ce cas, la JVM) . Vous pourriez essayer de réécrire votre code pour utiliser l'itération à la place, mais aussi considérer les autres réponses. Voir ceci: http://stackoverflow.com/questions/931762/can-every-recursion-be-converted-into-iteration – orique

Questions connexes