1

我正在使用此处的代码对 2000 x 2000 x 256 位图(在内存中)进行洪水填充:http ://rosettacode.org/wiki/Bitmap/Flood_fill#C.23

当 q Count = 33554432 (~33MB) 时,队列抛出内存不足错误。显然,我有比这更多的内存。我还创建了一个 IntPoint 结构,因此每个点都是 2 个整数而不是 2 个双精度数。

  1. 有没有办法手动为队列分配更多内存?
  2. 如果这不可能,有人有其他建议吗?

仅供参考:我怀疑这是否重要,但我实际上是在内存中的 2000 x 2000 字节数组上进行洪水填充,而不是实际加载位图、检查颜色和替换。

下面是我从上面引用的链接中实现的洪水填充(可能会跳出一个明显的错误):

public struct IntPoint
    {
        public int X, Y;

        public IntPoint(int p1, int p2)
        {
            X = p1;
            Y = p2;
        }
    }


    public void TerrainFloodFill(Point Tpt, byte targetElevation, byte replacementTerrain)
    {
        IntPoint pt = new IntPoint((int)Tpt.X, (int)Tpt.Y);

        Queue<IntPoint> q = new Queue<IntPoint>();
        q.Enqueue(pt);
        while (q.Count > 0)
        {
            IntPoint n = q.Dequeue();
            if (HeightMap[(int)n.X, (int)n.Y] != targetElevation)
                continue;
            IntPoint w = n, e = new IntPoint(n.X + 1, n.Y);
            while ((w.X > 0) && HeightMap[(int)w.X, (int)w.Y] == targetElevation)
            {
                TerrainMap[(int)w.X, (int)w.Y] = replacementTerrain;
                if ((w.Y > 0) && HeightMap[(int)w.X, (int)w.Y - 1] == targetElevation)
                    q.Enqueue(new IntPoint(w.X, w.Y - 1));
                if ((w.Y < MapHeight - 1) && HeightMap[(int)w.X, (int)w.Y + 1] == targetElevation)
                    q.Enqueue(new IntPoint(w.X, w.Y + 1));
                w.X--;
            }
            while ((e.X < MapWidth - 1) && HeightMap[(int)e.X, (int)e.Y] == targetElevation)
            {
                TerrainMap[(int)e.X, (int)e.Y] = replacementTerrain;
                if ((e.Y > 0) && HeightMap[(int)e.X, (int)e.Y - 1] == targetElevation)
                    q.Enqueue(new IntPoint(e.X, e.Y - 1));
                if ((e.Y < MapHeight - 1) && HeightMap[(int)e.X, (int)e.Y + 1] == targetElevation)
                    q.Enqueue(new IntPoint(e.X, e.Y + 1));
                e.X++;
            }
        }

    }

与往常一样,提前感谢您的帮助!

4

2 回答 2

1

这可能是一个碎片问题,您应该真正使用内存分析器来找出发生了什么。

作为首发,

  int estimatedSize = ...;
  Queue<IntPoint> q = new Queue<IntPoint>(estimatedSize);

我认为类似的东西int estimatedSize = MapWidth;会是一个好的开始。


但是您的队列仍然太大。原始算法可能会失败targetColor == replacementColor,在您的情况下是因为HeightMap != TerrainMap. 您需要在一张地图上进行操作,以便设置“像素”将确保在检查其邻居时不会重新排队。

因此,首先将整个 HeightMap 复制到 TerrainMap。

于 2013-05-25T19:53:48.010 回答
0

结构是不可变的,它们的每次修改都会创建一个新对象,就像原始类型一样。我看到了一些 X++;和 X——;结构体的修改。尝试将 IntPoint 改为一个类,这样引用就不会不断更新,看看这是否会有所改善。

于 2013-05-25T19:44:42.173 回答