füllen

Status
Nicht offen für weitere Antworten.

VdA

Bekanntes Mitglied
Ihr kennt das bestimmt von Paint:
F%FCllen.JPG
:wink:
nun habe ich ein BufferedImage, auf dem schon ein paar Striche und Kreise etc. sind, und ich will von einem Punkt
ausgehend alles was die selbe farbe hat mit einer neuen Farbe füllen zB das innere eines kreises mit rot.

Halt wie in Paint :wink:
Hab aber keine Ahnung wie ich die Farben der Pixel vergleichen kann.
Weiß jemand wie das geht?
 
S

SlaterB

Gast
für die Klasse BufferedImage gibts doch

int getRGB(int x, int y)
Returns an integer pixel in the default RGB color model (TYPE_INT_ARGB) and default sRGB colorspace.


kanntest du die nicht?
 

The_S

Top Contributor
Aber daraus kannst du die Farben extrahieren. Bzw alternativ einfach die Zahl einem neuen Color Objekt im Konstruktor übergeben.
 
S

SlaterB

Gast
aus int ein Color geht sofort (evtl. einmalig Code zu erstellen, Hobbit weiß da Rat ;) ),
und dauert dann in der Ausführungszeit nicht entscheidend länger als direkt ein Color-Objekt,

aber stell dir mal vor es würde standardmäßig Color kommen,
bei der Verarbeitung von Millionen von Pixeln soviele langsame Objekte..,

beide Operationen zur Verfügung zu haben wäre natürlich das Beste ;)
 

VdA

Bekanntes Mitglied
danke! :)
da funzt jetzt nur leider hat sich jetzt ein neues problem aufgetan:
Fuellen_Fehler.jpg

Ich will da 3eck ausfüllen aber er fülllt nur die Pixel die oben schwarz sind
das ist mein Code:
Code:
void fülle(Graphics g, MouseEvent evt, BufferedImage bild)
	{
		//hier füllt er flächen aus
		g.setColor(CurrentColor.current_color);
		Color ausgangs_farbe = null;
		try{
		ausgangs_farbe =new Color(bild.getRGB(evt.getX(), evt.getY()));
		}catch(java.lang.ArrayIndexOutOfBoundsException e){}
		System.out.println(ausgangs_farbe);
		
		
		for(int x=evt.getX();x<this.getSize().width && x>0;x-- )
		{
			Color farbe;
			if(ausgangs_farbe.equals(farbe=new Color(bild.getRGB(x, evt.getY()))))
			{
				for(int y=evt.getY();y<this.getSize().height && y>0;y-- )
				{
					
					if(ausgangs_farbe.equals(farbe=new Color(bild.getRGB(x, y))))
					{
						g.drawLine(x, y, x, y);
					}
					else{
						System.out.println("jetzt");
						break;
					}
					
				}
				for(int y=evt.getY();y<this.getSize().height && y>0;y++ )
				{
					
					if(ausgangs_farbe.equals(farbe=new Color(bild.getRGB(x, y))))
					{
						g.drawLine(x, y, x, y);
					}
					else{
						System.out.println("jetzt");
						break;
					}
				}
			}
			else{
				System.out.println("jetzt");
				break;
			}
		}

		for(int x=evt.getX();x<this.getSize().width && x>0;x++ )
		{
			Color farbe;
			if(ausgangs_farbe.equals(farbe=new Color(bild.getRGB(x, evt.getY()))))
			{
				for(int y=evt.getY();y<this.getSize().height && y>0;y-- )
				{
					
					if(ausgangs_farbe.equals(farbe=new Color(bild.getRGB(x, y))))
					{
						g.drawLine(x, y, x, y);
					}
					else{
						System.out.println("jetzt");
						break;
					}
					
				}
				for(int y=evt.getY();y<this.getSize().height && y>0;y++ )
				{
					
					if(ausgangs_farbe.equals(farbe=new Color(bild.getRGB(x, y))))
					{
						g.drawLine(x, y, x, y);
					}
					else{
						System.out.println("jetzt");
						break;
					}
				}
			}
			else{
				System.out.println("jetzt");
				break;
			}
		}
		
		

		
	}
Ich glaub ich müsste irgendwie das ganze von Grund auf anders angehen mir fällt nur im moment nicht ein wie.
ich gucke immer von der x-Achse ausgehen ob obe und unten alles frei is und spring ein weiter.
Weiß jemand rat? :bahnhof:
 

Illuvatar

Top Contributor
Also ich würde das generell etwas anders angehen, nämlich rekursiv. Pseudocode als Denkanstoß:

Code:
füllen (Pixel p, Color füllFarbe)
{
  Color c = p.farbe;
  p.farbe = füllFarbe;
  for (Pixel otherPixel : p.umliegendePixel){
    if (otherPixel.farbe == c) füllen(otherPixel, füllFarbe);
  }
}

Edit: Ist der Fred absichtlich abgehakt?
 

VdA

Bekanntes Mitglied
Code:
füllen (Pixel p, Color füllFarbe)
{
  Color c = p.farbe;
  p.farbe = füllFarbe;
  for (Pixel otherPixel : p.umliegendePixel){
    if (otherPixel.farbe == c) füllen(otherPixel, füllFarbe);
  }
}
führt das nicht dazu das er die Pixel immer wieder nachguckt und 100%Cpu verursacht?
 

Illuvatar

Top Contributor
IMO nicht, da die Rekursion ja abbricht, wenn der andere Pixel nicht die Farbe hat, wie der geklickte. Und die Pixelfarben werden immer gleich geändert.
 

VdA

Bekanntes Mitglied
jetzt habe ich ein anderes problem:
er fülllt nur die pixel die unter dem angeklickten Punkt liegen
hier mein Code:
Code:
public void fülle(Graphics g, Point pixel, BufferedImage bild, ZeichenBlock block)
	{
		//hier füllt er flächen aus
		System.out.println("füllen");

		try{
			Color ausgangs_farbe = new Color(bild.getRGB(pixel.x, pixel.y)); 
			Color füllFarbe= g.getColor();
			
			Point[] umliegende_Pixel=getUmliegendePixel(pixel, bild, ausgangs_farbe);
			try{
			for(int i=0;i<umliegende_Pixel.length; i++ )
			{
				fülle(g, umliegende_Pixel[i], bild, block);
			}
			}catch(java.lang.StackOverflowError e){}
			g.drawLine(pixel.x, pixel.y, pixel.x, pixel.y);
		}catch(java.lang.ArrayIndexOutOfBoundsException e){System.err.println(e);}
		//System.out.println(ausgangs_farbe);
		
		
		

		
	}
	Point[] getUmliegendePixel(Point pixel, BufferedImage bild, Color ausgangs_farbe)
	{
		Point[] last_Points=new Point[0];
		Point[] Points=new Point[1];
		if(new Color(bild.getRGB(pixel.x-1, pixel.y)).equals(ausgangs_farbe) )
		{
			try{
			Points = new Point[last_Points.length+1];
			}catch(java.lang.NullPointerException e){}
			for(int i=0;i< Points.length-1;i++)
			{
				Points[i] = last_Points[i];
			}
			Points[Points.length-1]=new Point(pixel.x-1, pixel.y);
		}
		if(new Color(bild.getRGB(pixel.x+1, pixel.y)).equals(ausgangs_farbe) )
		{
			try{
			Points = new Point[last_Points.length+1];
			}catch(java.lang.NullPointerException e){}
			for(int i=0;i< Points.length-1;i++)
			{
				Points[i] = last_Points[i];
			}
			Points[Points.length-1]=new Point(pixel.x+1, pixel.y);
		}
		if(new Color(bild.getRGB(pixel.x, pixel.y-1)).equals(ausgangs_farbe) )
		{
			try{
			Points = new Point[last_Points.length+1];
			}catch(java.lang.NullPointerException e){}
			for(int i=0;i< Points.length-1;i++)
			{
				Points[i] = last_Points[i];
			}
			Points[Points.length-1]=new Point(pixel.x, pixel.y-1);
		}
		if(new Color(bild.getRGB(pixel.x, pixel.y+1)).equals(ausgangs_farbe) )
		{
			try{
			Points = new Point[last_Points.length+1];
			}catch(java.lang.NullPointerException e){}
			for(int i=0;i< Points.length-1;i++)
			{
				Points[i] = last_Points[i];
			}
			Points[Points.length-1]=new Point(pixel.x, pixel.y+1);
		}
		
		return Points;	
	}
Und wieder mal hab ich keine Ahnung :bahnhof: :autsch:
 
S

SlaterB

Gast
falls das noch aktuell ist, schreibe ab und zu mal ein 'Erinnerungspost',
solche anschaulichen Knobeleien sind ja spannend
(auch wenns wahrscheinlich ganz simple Fehler sind),

ich persönlich habe im Moment aber keine Zeit (Weihnachten)
 

Illuvatar

Top Contributor
Da ich grad weihnachtlich gestimmt bin ;) hab ich dir daraus mal einen funktionierenden Code gebaut.

Code:
  public void fülle(Graphics g, Point pixel, BufferedImage bild)
   {
      Color ausgangsFarbe = new Color(bild.getRGB(pixel.x, pixel.y));
      bild.setRGB(pixel.x, pixel.y, g.getColor().getRGB());

      Point[] umliegendePixel = getUmliegendePixel(pixel, bild, ausgangsFarbe.getRGB());
      try {
          for(Point newPixel : umliegendePixel)
          {
             if (bild.getRGB(newPixel.x, newPixel.y) == ausgangsFarbe.getRGB()){
                     fülle(g, newPixel, bild);
             }
          }
      } catch (StackOverflowError e) {
          //do nothing
      }
   }
   Point[] getUmliegendePixel(Point pixel, BufferedImage bild, int rgb)
   {
      ArrayList<Point> points = new ArrayList<Point>();
      if (pixel.x > 0){
        points.add (new Point(pixel.x - 1, pixel.y));
      }
      if ((pixel.x + 1) < bild.getWidth()){
        points.add (new Point(pixel.x + 1, pixel.y));
      }
      if (pixel.y > 0){
        points.add (new Point(pixel.x, pixel.y - 1));
      }
      if ((pixel.y + 1) < bild.getHeight()){
        points.add (new Point(pixel.x, pixel.y + 1));
      }
      return points.toArray(new Point[]{});
   }

Allerdings benötigt diese Methode einen viel größeren Stack, als ich es bedacht hatte. Kleinere Flächen lassen sich ausfüllen, große resultieren in einem StackOverflow (den ich zwar ignorieren lasse, dadurch funktioniert das aber nicht mehr richtig). Wenn man das Programm z.B. mit "-ss15m -oss60m" startet, funktioniert das auch für größere Flächen (bis zu, sagen wir, 400*400px²) prima - aber 75MB Stack ist doch auch Performancemäßig nicht gerade toll...
Dann bleibt für dich ja doch noch was zu tun :bae: Du müsstest das jetzt eben noch irgendwie iterativ lösen.
 

VdA

Bekanntes Mitglied
leider füllt er im Moment nur einen Punkt, den auf den Man geklickt hat :(
aber was bringt eigentlich
Code:
 for(Point newPixel : umliegendePixel)
mir ist nicht ganz klar wofür das ":" steht :bahnhof:
 

VdA

Bekanntes Mitglied
öhm das ganze Programm ist um die 62 kilo bytes groß möchtest du das wirklich alles sehen?
 

VdA

Bekanntes Mitglied
ach egal ich poste einfach mal den link:
Mein Malprogramm
vllt findest du den Fehler :?


[Edit:]Wenn das Fertig ist werd ich das sowieso allen die es brauchen zugänglich machen da ich denke das Microsoft-Paint in den Meisten fällen nicht ausreichend ist aber irgenwelche Programmme von sonstwoher zu Umfangreich sind
vor allem soll aus diesem Malprogramm noch mehr werden, was ich dann wiederum nicht veröffenlichen werde. :wink:
 
Status
Nicht offen für weitere Antworten.

Ähnliche Java Themen


Oben