我正在开发一个应用程序来均匀地分割图像网格并使图像居中(基于它们的相似性)。到目前为止,我可以设法修复一个小尺寸的图像网格,但每当我尝试更大的“精灵”大小(例如100x100)时,我就会出现Stack Overflow错误。
是的我正在使用递归,但每当检查一个像素时,我设置一个布尔值来停用它,将它复制到一个列表并继续检查其他(在所有方向),直到列表填满一个来自网格的图像。我不确定这是否是最好的方式,因为对于每个调用,我调用相同的方法7次(假设有7个相邻的像素尚未检查)...直到没有像素可以检查,并且我可以转到网格中的下一个图像。
我尝试跟踪错误开始发生的位置,检查了大约1600像素并将它们添加到List中。 MyPixel是一个包含4个变量的类:x(int),y(int),color(Color)和checked(bool)
public void processSprite(int i, int j)
{
//OOO
//OXO
//OOO
pixeltemp.Add(new MyPixel(imap.pixels[i, j].x, imap.pixels[i, j].y, imap.pixels[i, j].color));
imap.pixels[i, j].read = true;
//OOO
//OOX
//OOO
try
{
if (!imap.pixels[i + 1, j].read)
{
if (imap.pixels[i + 1, j].color.A == 0) //Found a Border
{
imap.pixels[i + 1, j].read = true;
}
else
{
processSprite(i + 1, j);
}
}
}
//... (code goes on)
}
(List<MyPixel>)
(List<MyPixel>)
我想这不是内存问题,因为我的应用只占用了大约16mb。
我的问题是,如果不是无限递归,为什么我会出现“堆栈溢出”错误?有更简单的方法吗?我认为我的代码看起来很难看,我只是不知道如何让它变得更好。
提前致谢!
答案 0 :(得分:1)
堆栈溢出不是由无限递归引起的,而是由进程可以处理的更多递归(或者更确切地说,调用堆栈)引起的。在您的情况下,每次递归调用processSprite
将对processSprite
进行相同数量的递归调用。因此,在没有找到边界的1600像素的最坏情况下,您的调用树将如下所示:
processSprite(0, j) processSprite(1, j) processSprite(2, j) ... processSprite(1599, j) <-- That's 1600 call frames, enough for an overflow.
您需要将算法重新组织为执行深度优先搜索的线性循环,如果您想要找到最接近起点的像素,则可能采用螺旋模式。我确信已经有其他已经开发出的其他spiffy算法来解决这个问题。
修改强>
我想我现在更清楚你要解决的问题了。听起来你的图像可能包含多个由0-alpha像素包围的图像切片,并且您希望找到每个切片的边界矩形。这看起来像一个有趣的问题需要解决,所以我实现了它:
IEnumerable<Rectangle> FindImageTiles(Bitmap compositeImage)
{
var result = new List<Rectangle>();
// Scan for a non-empty region that hasn't already been "captured"
for (var x = 0; x < compositeImage.Width; x++)
{
for (var y = 0; y < compositeImage.Height; y++)
{
// Only process the pixel if we don't have a rectangle that
// already contains this and if it's not empty
if (!result.Any(r => r.Contains(x, y))
&& compositeImage.GetPixel(x, y).A != 0)
{
// Now that we've found a point, create a rectangle
// surrounding that point, then expand outward until
// we have a bounding rectangle that doesn't intersect
// with the tile
var rect = new Rectangle(x - 1, y - 1, 2, 2);
bool foundBounds = false;
while (!foundBounds)
{
var xRange = Enumerable.Range(rect.Left, rect.Right)
.Where(px => px >= 0 && px < compositeImage.Width);
var yRange = Enumerable.Range(rect.Top, rect.Bottom)
.Where(py => py >= 0 && py < compositeImage.Height);
// Adjust the top
if (rect.Top >= 0
&& xRange
.Select(bx => compositeImage.GetPixel(bx, rect.Top))
.Any(p => p.A != 0))
{
rect.Y--;
rect.Height++;
}
else if (rect.Bottom < compositeImage.Height
&& xRange
.Select(bx => compositeImage.GetPixel(bx, rect.Bottom))
.Any(p => p.A != 0))
{
rect.Height++;
}
else if (rect.Left >= 0
&& yRange
.Select(by => compositeImage.GetPixel(rect.Left, by))
.Any(p => p.A != 0))
{
rect.X--;
rect.Width++;
}
else if (rect.Right < compositeImage.Width
&& yRange
.Select(by => compositeImage.GetPixel(rect.Right, by))
.Any(p => p.A != 0))
{
rect.Width++;
}
else
{
foundBounds = true;
}
}
result.Add(rect);
}
}
}
return result;
}