I'm creating a sprite and animation editor like this one. I'm having performance issues with my flood-fill algorithm.
Basically, I open an image with the different modules that are part of a frame of an animation. When I double-click a module I run a depth-first search algorithm that checks all the pixels of that part of the image that are surrounded by transparency. From that I get the rectangle of said module (the position and size). With large images, when I double-click that part of the image the application freezes.
How can I improve my algorithm?
Right now what I do is maintain an array of already-checked pixels and a list of pixels to check. I start with the pixel that I double-clicked and check if the surrounding pixels have transparency. If they do not, I check for the surrounding pixels of those pixels and so on until all the surrounding pixels are transparent. Then I can get the minimum and maximum position in the X-axis and Y-axis and use that to construct the bounding rectangle of the frame.
This is my code:
private Rectangle widthSearch(int posX, int posY)
{
Rectangle result = new Rectangle();
int leftX, topY, rightX, botY;
leftX = rightX = posX;
topY = botY = posY;
List<Point> closedList = new List<Point>();
List<Point> toProcessList = new List<Point>();
Point processingNode;
Color colorAux;
int alphaAux;
int offsetX = 0;
int offsetY = 0;
toProcessList.Add(new Point(posX, posY));
int[] dx = { 1, 1, 0, -1, -1, -1, 0, 1 };
int[] dy = { 0, -1, -1, -1, 0, 1, 1, 1 };
while (toProcessList.Count > 0)
{
processingNode = toProcessList.ElementAt(0);
closedList.Add(processingNode);
toProcessList.Remove(toProcessList.ElementAt(0));
for (int i = 0; i < dx.Count(); i++)
{
offsetX = dx[i];
offsetY = dy[i];
try{
if (!closedListContains(closedList, processingNode.X + offsetX, processingNode.Y + offsetY) && !closedListContains(toProcessList, processingNode.X + offsetX, processingNode.Y + offsetY))
{
colorAux = bmp.GetPixel(processingNode.X + offsetX, processingNode.Y + offsetY);
alphaAux = (colorAux.ToArgb() >> 24) & 0xFF;
if (alphaAux > 0)
{
toProcessList.Add(new Point(processingNode.X + offsetX, processingNode.Y + offsetY));
}
}
}
catch (Exception e)
{
Console.Write(">>>>>>>>\n" + e + "\n>>>>>>>>>");
}
}
}
for (int i = 0; i < closedList.Count(); i++)
{
if (closedList.ElementAt(i).X > rightX)
rightX = (int)closedList.ElementAt(i).X;
if (closedList.ElementAt(i).X < leftX)
leftX = (int)closedList.ElementAt(i).X;
if (closedList.ElementAt(i).Y < topY)
topY = (int)closedList.ElementAt(i).Y;
if (closedList.ElementAt(i).Y > botY)
botY = (int)closedList.ElementAt(i).Y;
}
result.X = leftX;
result.Y = topY;
result.Width = rightX - leftX;
result.Height = botY - topY;
return result;
}
private Boolean closedListContains(List<Point> closedList, int posX, int posY)
{
Point pointer = new Point(posX, posY);
for (int i = 0; i < closedList.Count(); i++)
{
if (closedList.ElementAt(i).Equals(pointer))
return true;
}
return false;
}
I only call the widthSearch()
method when I double-click a PictureBox
. It is not inside a loop.
widthSearch
recursively ? can you show us more of the code? How are you calling it, I suspect it's called inside a loop ? please provide more details. \$\endgroup\$