2015-07-28 4 views
0

Je fais une application de peinture et l'outil de remplissage d'inondation fonctionne, mais il faut environ deux minutes pour qu'il remplisse un 400x180. Que puis-je faire pour accélérer ce processus? Voici le code que j'utilise actuellement pour cela.Java Floodfill vraiment lent

public void gradientSize(int x, int y, int origRGB, int index){ 
    queue = new ArrayList<String>(); //queue is an ArrayList<String> that holds the points 
    time = System.currentTimeMillis(); // time is a long so I can calculate the time it takes to finish a flood fill 
    if(new Color(origRGB).equals(foreground)){ //foreground is the color the flood fill is using to fill in. origRGB is the RGB of the color I clicked 
     return; 
    } 
    if(!testFill(x, y, origRGB)){ 
     return; 
    } 
    queue.add(pixel(x,y)); 
    while(!queue.isEmpty()){ 
     String pixel = queue.get(0); 
     int x2 = Integer.parseInt(pixel.substring(0, pixel.indexOf(","))); 
     int y2 = Integer.parseInt(pixel.substring(pixel.indexOf(",")+1,pixel.length())); 
     queue.remove(0); 
     if(testFill(x2, y2, origRGB)){ 
      queue.add(pixel(x2+1, y2)); 
      queue.add(pixel(x2-1,y2)); 
      queue.add(pixel(x2,y2+1)); 
      queue.add(pixel(x2,y2-1)); 
      gradientPoints.add(pixel(x2, y2)); //gradientPoints is an ArrayList<String> that contains all the points for the fill 
      processed[y*image.getWidth()+x] = true; //processed[] is a boolean array that has a true or false value for each pixel to determine if it has been looked at yet. 
     } 
    } 
} 

public boolean testFill(int x, int y,int origRGB){ //testFill tests if the current pixel is okay to be filled or not 
    if(x>=0&&x<image.getWidth()&&y>=0&&y<image.getHeight()){ 
     int testRGB = image.getRGB(x, y); 
     Color orig = new Color(origRGB,true); 
     Color test = new Color(testRGB,true); 
     if ((Math.abs(orig.getRed() - test.getRed()) <= difference) && (Math.abs(orig.getGreen() - test.getGreen()) <= difference)&& (Math.abs(orig.getBlue() - test.getBlue()) <= difference)&&(Math.abs(orig.getAlpha() - test.getAlpha()) <= difference)) { 
      if (!gradientPoints.contains(pixel(x,y))) { 
       if (!queue.contains(pixel(x,y))) { 
        if (processed[y*image.getWidth()+x]==false) { 
         return true; 
        } 
       } 
      } 
     } 
    } 
    return false; 

} 

public String pixel(int x, int y){//this returns the String value of a pixel's x and y coordinates. 
    return String.valueOf(x)+","+String.valueOf(y); 
} 
public void gradientFillSolid(){ //This gets all the points from gradientPoints and fills each pixel from there. 
    for(String s:gradientPoints){ 
     int x = Integer.parseInt(s.substring(0, s.indexOf(','))); 
     int y = Integer.parseInt(s.substring(s.indexOf(',')+1,s.length())); 
     image.setRGB(x, y, foreground.getRGB()); 
    } 
    System.out.println(System.currentTimeMillis()-time); 
    repaint(); 
} 

La sortie pour un rectangle de 400 x 180 était de 148566 millisecondes. Y a-t-il un moyen pour moi d'accélérer ce processus? Toute aide est appréciée.

Répondre

1

Voici votre problème:

queue.add(pixel(x2+1, y2)); 
queue.add(pixel(x2-1,y2)); 
queue.add(pixel(x2,y2+1)); 
queue.add(pixel(x2,y2-1)); 

Vous ajoutez chaque pixel plusieurs fois (une fois ici, et une fois pour chaque bloc autour de ce pixel particulier) et revérifier chaque fois qu'il est ajouté à nouveau. Si vous aviez un bloc 4x4, vous ne remarqueriez vraiment pas de ralentissement, mais quand on parle de 400x180 (72 000) pixels ajoutés et vérifiés 3 ou 4 fois par pixel, ça devient énorme.

Ma suggestion est très simple: Vérifiez avant d'ajouter. Ou encore mieux, créez une petite classe "MyPixel" qui a une valeur booléenne qui est retournée à true après l'avoir déjà vérifiée. De cette façon, vous pouvez sauter faire une mathématiques là-dessus et vous pouvez simplement faire quelque chose comme ceci:

if(my_pixel.has_been_checked == false) 
    queue.add(my_pixel); 
0

Vous transformez les coordonnées en pixels à une chaîne, puis l'analyse syntaxique arrière. J'ai trouvé dans mon expérience que la concaténation de chaînes est une action coûteuse. Au lieu de cela, il suffit de stocker les pixels en tant qu'objets java.awt.Point et de lire les coordonnées de ceux-ci.