Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

public static void FillArea(Bitmap editBitmap, int x, int y, Color replThisColor, Color withThisColor)
		{
			if(editBitmap.GetPixel(x,y)==replThisColor)
			{
				editBitmap.SetPixel(x,y, withThisColor);

				int l= x-1;
				int r= x+1;
				int u= y-1;
				int d= y+1;

				if(r < editBitmap.Width)
				{
					if(editBitmap.GetPixel(r, y)==replThisColor) FillArea(editBitmap, r, y, replThisColor, withThisColor);
				}
				if(d < editBitmap.Height)
				{
					if(editBitmap.GetPixel(x, d)==replThisColor) FillArea(editBitmap, x, d, replThisColor, withThisColor);
				}
				if(l > -1)
				{
					if(editBitmap.GetPixel(l, y)==replThisColor) FillArea(editBitmap, l, y, replThisColor, withThisColor);
				}
				/*if(u > -1)
				{
					if(editBitmap.GetPixel(x, u)==replThisColor) FillArea(editBitmap, x, u, replThisColor, withThisColor);
				}*/
			}

I always get a stack overflow right away if I have all 4 directions running. Is there a better way to do this?

C#
  • *Experts*
Posted

Your code will keep hitting the same pixels over and over. You could try passing something like a "direction" to your function so that you know which way you were coming from. Using that direction you would NO check the IF for pixels in that direction.

 

For example, say you had a 3x3 grid. The first pixel is in the upper left. Say your second pixel is to the right, so you call your function again. When checking the pixels around this second pixel (top middle pixel in the 3x3) you don't want to go back and do anything with the top left pixel since you've already visited it. By using a direction you can avoid that.

 

That's the easiest change, using your existing code. A better solution involves more work as you would create a structure to know which pixels you'd already hit. With my solution (just using a direction), you'll still revisit pixels but not indefinately.

 

Isn't there some kind of FloodFill function built into GDI or GDI+? I don't know...

 

-Nerseus

"I want to stand as close to the edge as I can without going over. Out on the edge you see all the kinds of things you can't see from the center." - Kurt Vonnegut
Posted

"It may be roundly asserted that human ingenuity cannot concoct a cipher which human ingenuity cannot resolve."

 

- Edgar Allan Poe, 1841

 

I long to accomplish great and noble tasks, but it is my chief duty to accomplish humble tasks as though they were great and noble. The world is moved along, not only by the mighty shoves of its heroes, but also by the aggregate of the tiny pushes of each honest worker.

 

- Helen Keller

Posted (edited)

It looks like he left something out- using the points he added...

 

I didn't notice the first time divil, that you did not write a + after GDI. It is an api call. I'll just stick with my own.

Edited by aewarnick
C#
Posted

Now it is even worse. I don't even get an error, the program just quits!

Are you suggesting using an array list and looping through each element(point structure) to see if I did that one already?

public static void FloodFill(Bitmap editBitmap, int x, int y, Color replThisColor, Color withThisColor, char direction)
		{
			if(editBitmap.GetPixel(x,y)==replThisColor)
			{
				editBitmap.SetPixel(x,y, withThisColor);

				int l= x-1;
				int r= x+1;
				int u= y-1;
				int d= y+1;

				if(direction != 'R')
				{
					if(r < editBitmap.Width)
					{
						if(editBitmap.GetPixel(r, y)==replThisColor) FloodFill(editBitmap, r, y, replThisColor, withThisColor, 'L');
					}
				}
				if(direction != 'D')
				{
					if(d < editBitmap.Height)
					{
						if(editBitmap.GetPixel(x, d)==replThisColor) FloodFill(editBitmap, x, d, replThisColor, withThisColor, 'U');
					}
				}
				if(direction != 'L')
				{
					if(l > -1)
					{
						if(editBitmap.GetPixel(l, y)==replThisColor) FloodFill(editBitmap, l, y, replThisColor, withThisColor, 'R');
					}
				}
				if(direction != 'U')
				{
					if(u > -1)
					{
						if(editBitmap.GetPixel(x, u)==replThisColor) FloodFill(editBitmap, x, u, replThisColor, withThisColor, 'D');
					}
				}
						
			}
		}

C#
Posted

I thought this was an interesting problem and searched for a way to solve it - first I ran into the same problems mentioned above (stack overflow/app exiting without throwing any exception etc...) but then I remembered my Math lessons - Pythagoras!!

 

one of his most famous discoverys says that the sides of a rectangular triangle always have the relationship (a*a) + (b*b) = (c*c) where a and b have a 90° angle between each other. I used this to calculate the distance between start and current point.

 

what I tried to do is minimizing double "pixel-checking" by checking wheter the distance © from the current point to the startpoint is shorter than the next point I'm about to work on. if this is the case - keep working.... if not leave it. this method has one disadvantage - it doesn't fill "around corners" but maybe this is a approach you can use...

 

Hope this helps!

 

Andreas

 

...the code:

 

    Private Sub FloodFill(ByVal BMP As Bitmap, ByVal Start As Point, ByVal SearchCol As Color, ByVal ReplaceCol As Color)
       Try
           If Start.X < BMP.Width And Start.X > -1 And Start.Y < BMP.Height And Start.Y > -1 Then
               If BMP.GetPixel(Start.X, Start.Y).Equals(SearchCol) And Not BMP.GetPixel(Start.X, Start.Y).Equals(ReplaceCol) Then
                   Console.WriteLine("Starting FloodFill at " + Start.ToString())
                   Console.WriteLine("replacing " + SearchCol.ToString() + " with " + ReplaceCol.ToString())
                   BMP.SetPixel(Start.X, Start.Y, ReplaceCol)

                   internalFloodFill(BMP, Start, New Point(Start.X, Start.Y - 1), SearchCol, ReplaceCol)
                   Console.WriteLine("")
                   Console.WriteLine("- -")
                   internalFloodFill(BMP, Start, New Point(Start.X + 1, Start.Y), SearchCol, ReplaceCol)
                   Console.WriteLine("")
                   Console.WriteLine("- -")
                   internalFloodFill(BMP, Start, New Point(Start.X, Start.Y + 1), SearchCol, ReplaceCol)
                   Console.WriteLine("")
                   Console.WriteLine("- -")
                   internalFloodFill(BMP, Start, New Point(Start.X - 1, Start.Y), SearchCol, ReplaceCol)
                   Console.WriteLine("")
                   Console.WriteLine("- -")
                   Console.WriteLine("Done!!")
               End If
           End If
       Catch e As Exception
           Console.WriteLine("ERROR in FloodFill")
           Console.WriteLine(e.Message)
       End Try
   End Sub

   Private Sub internalFloodFill(ByVal BMP As Bitmap, ByVal Start As Point, ByVal CurrPos As Point, ByVal SearchCol As Color, ByVal ReplaceCol As Color)
       Try
           If CurrPos.X < BMP.Width And CurrPos.X > -1 And CurrPos.Y < BMP.Height And CurrPos.Y > -1 Then
               If BMP.GetPixel(CurrPos.X, CurrPos.Y).Equals(SearchCol) And Not BMP.GetPixel(CurrPos.X, CurrPos.Y).Equals(ReplaceCol) Then
                   Console.Write(".")
                   BMP.SetPixel(CurrPos.X, CurrPos.Y, ReplaceCol)

                   Dim newPos As New Point(CurrPos.X, CurrPos.Y - 1)

                   If newPos.X < BMP.Width And newPos.X > -1 And newPos.Y < BMP.Height And newPos.Y > -1 Then
                       If (Math.Abs(newPos.X - Start.X)) ^ 2 + (Math.Abs(newPos.Y - Start.Y)) ^ 2 > (Math.Abs(CurrPos.X - Start.X)) ^ 2 + (Math.Abs(CurrPos.Y - Start.Y)) ^ 2 Then
                           If BMP.GetPixel(newPos.X, newPos.Y).Equals(SearchCol) And Not BMP.GetPixel(newPos.X, newPos.Y).Equals(ReplaceCol) Then
                               internalFloodFill(BMP, Start, newPos, SearchCol, ReplaceCol)
                           End If
                       End If
                   End If

                   newPos.Y += 2

                   If newPos.X < BMP.Width And newPos.X > -1 And newPos.Y < BMP.Height And newPos.Y > -1 Then
                       If (Math.Abs(newPos.X - Start.X)) ^ 2 + (Math.Abs(newPos.Y - Start.Y)) ^ 2 > (Math.Abs(CurrPos.X - Start.X)) ^ 2 + (Math.Abs(CurrPos.Y - Start.Y)) ^ 2 Then
                           If BMP.GetPixel(newPos.X, newPos.Y).Equals(SearchCol) And Not BMP.GetPixel(newPos.X, newPos.Y).Equals(ReplaceCol) Then
                               internalFloodFill(BMP, Start, newPos, SearchCol, ReplaceCol)
                           End If
                       End If
                   End If

                   newPos.Y -= 1
                   newPos.X -= 1

                   If newPos.X < BMP.Width And newPos.X > -1 And newPos.Y < BMP.Height And newPos.Y > -1 Then
                       If (Math.Abs(newPos.X - Start.X)) ^ 2 + (Math.Abs(newPos.Y - Start.Y)) ^ 2 > (Math.Abs(CurrPos.X - Start.X)) ^ 2 + (Math.Abs(CurrPos.Y - Start.Y)) ^ 2 Then
                           If BMP.GetPixel(newPos.X, newPos.Y).Equals(SearchCol) And Not BMP.GetPixel(newPos.X, newPos.Y).Equals(ReplaceCol) Then
                               internalFloodFill(BMP, Start, newPos, SearchCol, ReplaceCol)
                           End If
                       End If
                   End If

                   newPos.X += 2

                   If newPos.X < BMP.Width And newPos.X > -1 And newPos.Y < BMP.Height And newPos.Y > -1 Then
                       If (Math.Abs(newPos.X - Start.X)) ^ 2 + (Math.Abs(newPos.Y - Start.Y)) ^ 2 > (Math.Abs(CurrPos.X - Start.X)) ^ 2 + (Math.Abs(CurrPos.Y - Start.Y)) ^ 2 Then
                           If BMP.GetPixel(newPos.X, newPos.Y).Equals(SearchCol) And Not BMP.GetPixel(newPos.X, newPos.Y).Equals(ReplaceCol) Then
                               internalFloodFill(BMP, Start, newPos, SearchCol, ReplaceCol)
                           End If
                       End If
                   End If
               End If
           End If
       Catch e As Exception
           Console.WriteLine("ERROR in internalFloodFill")
           Console.WriteLine(e.Message)
       End Try
   End Sub

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...