C# - 找到一个图像的边界(不是大小) [英] C# - Finding the Boundaries of an Image (not the size)

查看:408
本文介绍了C# - 找到一个图像的边界(不是大小)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我开发的应用程序到平分一图像框格和中心图像(基于它们的相似性)。到目前为止,我可以想办法解决小尺寸图像的网格,但每当我尝试一个更大的雪碧大小(100×100,例如),我得到堆栈溢出错误。

I'm developing an application to split an image grid equally and center the images (based on their similarity). So far, I could manage to fix a grid of images with small sizes, but whenever I try a larger "sprite" size (100x100, for instance), I get Stack Overflow error.

是我使用递归,但每当像素被选中,我设置一个布尔值,禁用它,将它复制到一个列表,并继续检查其他人(在所有方向),直到列表与一个充满从格栅图像。我不知道这是否是最好的方法,因为每个电话,我调用相同的方法7倍(假设有而尚未检查7相邻像素)......直到有没有留下像素检查,并我可以在网格上移动到下一个图像。

Yes I'm using recursion, but whenever a pixel is checked, I set a boolean to deactivate it, copy it to a list and go on checking the others (in all directions), until the list is filled up with an image from the grid. I'm not sure if this is the best way since for each call, I call the same method 7 times (supposing there are 7 adjacent pixels which weren't checked yet)... until there are no pixels left to check, and I can move on to the next image in the grid.

我试图追查其中的错误开始发生,这是检查或多或少1600像素,并将它们添加到列表之后。 MyPixel是包含4个变量的类:X(INT),Y(INT),颜色(彩色),并检查(布尔)

I tried tracing where the error started happening, it was after checking more or less 1600 pixels and adding them to the List. MyPixel is a class which contains 4 variables: x(int), y(int), color (Color), and 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)
    }


  • pixeltemp是保存图像像素的临时列表(列表< MyPixel>)

  • IMAP包含整个图像(列表< MyPixel>)

    • pixeltemp is the temporary list of pixels which holds the image (List<MyPixel>)
    • imap contains the entire image (List<MyPixel>)
    • 我想这不是一个记忆的问题,因为我的应用程序只需要大约16MB的顶部。

      I guess it's not a memory problem since my app just takes about 16mb tops.

      我的问题是,为什么我有这样的堆栈溢出错误,如果它不是一个无限递归?是否有更简单的方法来做到这一点?我认为我的code长相丑陋,我只是不知道如何使它更好。

      My question is, why do I have this "Stack overflow" error if it's not an infinite recursion? Is there an easier way to do this? I do think my code looks ugly, I just have no idea how to make it better.

      在此先感谢!

      推荐答案

      堆栈溢出不会被无限递归而是由多个递归(或者,更确切地说,调用栈)以外的进程可以处理造成的。在你的情况,每次递归调用 processSprite 会做相同数量的递归调用到 processSprite 。所以在1600像素的最坏的情况没有找到一个边界,您的通话将树是这样的:

      Stack overflows aren't caused by infinite recursion but by more recursion (or, rather, call stack) than the process can handle. In your case, each recursive call to processSprite is going to do the same number of recursive calls to processSprite. So in the worst-case scenario of 1600 pixels without finding a boundary, your call tree would look like this:

      
        processSprite(0, j)
          processSprite(1, j)
            processSprite(2, j)
              ...
                processSprite(1599, j) <-- That's 1600 call frames,
                                           enough for an overflow.
      

      您会希望你的算法重组为一个线性循环,做了深度优先搜索,或许以螺旋方式,如果你想找到一个像素这是最接近的起点。我敢肯定,已经有其他漂亮的算法,别人已经发展到解决这个问题。

      You'll want to reorganize your algorithm into a linear loop that does a depth-first search, perhaps in a spiral pattern if you're wanting to to find a pixel that's closest to the starting point. I'm sure there are already other spiffy algorithms others have already developed to solve this problem.

      编辑:

      我想我更好地了解现在你正在试图解决这个问题。这听起来像你有可能含有由0-α像素包围多个图像块的图像,并且希望找到这些瓷砖的边界矩形。这看起来像一个有趣的问题来解决,所以我实现它:

      I think I understand better now the problem that you're trying to solve. It sounds like you have an image that may contain multiple image tiles surrounded by 0-alpha pixels and you want to find the bounding rectangles for each of these tiles. That looked like an interesting problem to solve, so I implemented it:

      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;
      }
      

      这篇关于C# - 找到一个图像的边界(不是大小)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆