【问题标题】:Algorithm for finding a painted region on a canvas在画布上查找绘制区域的算法
【发布时间】:2010-06-24 18:25:31
【问题描述】:

更新:我试图从这篇文章中抽出一点混乱并更简洁地总结一下。如果需要,请查看原始编辑。

我目前正在尝试在位图画布上追踪一系列单色斑点。

例如我试图跟踪的位图示例如下所示: alt text http://www.refuctored.com/polygons.bmp

在成功追踪图像上 3 个斑点的轮廓后,我将创建一个类,该类将斑点的颜色与表示斑点轮廓的点列表(不是斑点内的所有像素)相关联。

我遇到的问题是相邻像素除了前一个像素之外没有周围像素的情况下的逻辑。

例如,上面的示例可以很好地跟踪,但第二个示例将失败,因为该像素无处可去,因为之前的像素已被使用。

alt text http://www.refuctored.com/error.jpg

我从左到右、从上到下进行追踪,偏爱对角而不是直角。我必须能够根据我提取的数据重新绘制该区域的精确副本,因此列表中的像素必须按照正确的顺序进行复制。

到目前为止,我的尝试一直以失败告终,而且我花了几天的时间试图重写算法,每次都略有不同,以解决问题。到目前为止,我一直没有成功。有没有其他人像我一样有类似的问题,他有一个很好的算法来找到边缘?

【问题讨论】:

    标签: c# image-processing


    【解决方案1】:

    避免这些死胡同的一个简单技巧是在跟踪之前使用最近邻缩放算法将要跟踪的图像大小加倍。这样你就永远不会得到单条了。

    另一种方法是使用行进正方形算法 - 但似乎仍然有一两种失败的情况:http://www.sakri.net/blog/2009/05/28/detecting-edge-pixels-with-marching-squares-algorithm/

    【讨论】:

    • 将大小翻倍——这是个好主意。我很惊讶我没想到。我会检查一下!
    【解决方案2】:

    您是否研究过斑点检测算法?例如,http://opencv.willowgarage.com/wiki/cvBlobsLib 如果您可以将 OpenCV 集成到您的应用程序中。结合阈值处理为图像中的每种颜色(或颜色范围)创建二进制图像,您可以轻松找到相同颜色的斑点。对图像中的每种颜色重复此操作,您将得到一个按颜色排序的 blob 列表。

    如果您不能直接使用 OpenCV,那么该库引用的论文(“使用轮廓跟踪技术的线性时间组件标记算法”,F.Chang 等人)可能会提供一种很好的查找 blob 的方法。

    【讨论】:

      【解决方案3】:

      与其使用递归,不如使用堆栈。

      伪代码:

      Add initial pixel to polygon
      Add initial pixel to stack
      while(stack is not empty) {
          pop pixel off the stack
          foreach (neighbor n of popped pixel) {
              if (n is close enough in color to initial pixel) {
                  Add n to polygon
                  Add n to stack
              }
          }
      }
      

      与使用递归的相同解决方案相比,这将使用更少的内存。

      【讨论】:

        【解决方案4】:

        只需将您的“图像”发送到 BuildPixelArray 函数,然后调用 FindRegions。 之后,“colors”变量将在每个列表成员中保存您的颜色列表和像素坐标。

        我从我的一个项目中复制了源代码,可能有一些未定义的变量或语法错误。

            public class ImageProcessing{
            private int[,] pixelArray;
            private int imageWidth;
            private int imageHeight;
            List<MyColor> colors;
        
            public void BuildPixelArray(ref Image myImage)
            {
                imageHeight = myImage.Height;
                imageWidth = myImage.Width;
                pixelArray = new int[imageWidth, imageHeight];
                Rectangle rect = new Rectangle(0, 0, myImage.Width, myImage.Height);
                Bitmap temp = new Bitmap(myImage);
                BitmapData bmpData = temp.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
                int remain = bmpData.Stride - bmpData.Width * 3;
                unsafe
                {
                    byte* ptr = (byte*)bmpData.Scan0;
                    for (int j = 15; j < bmpData.Height; j++)
                    {
                        for (int i = 0; i < bmpData.Width; i++)
                        {
                            pixelArray[i, j] = ptr[0] + ptr[1] * 256 + ptr[2] * 256 * 256;
                            ptr += 3;
                        }
                        ptr += remain;
                    }
                }
                temp.UnlockBits(bmpData);
            }
        
            public void FindRegions()
            {
                colors = new List<MyColor>();
        
                for (int i = 0; i < imageWidth; i++)
                {
                    for (int j = 0; j < imageHeight; j++)
                    {
                        int tmpColorValue = pixelArray[i, j];
                        MyColor tmp = new MyColor(tmpColorValue);
                        if (colors.Contains(tmp))
                        {
                            MyColor tmpColor = (from p in colors
                                                where p.colorValue == tmpColorValue
                                                select p).First();
        
                            tmpColor.pointList.Add(new MyPoint(i, j));
                        }
                        else
                        {
                            tmp.pointList.Add(new MyPoint(i, j));
                            colors.Add(tmp);
                        }
                    }
                }
            }
        }
        
        public class MyColor : IEquatable<MyColor>
        {
            public int colorValue { get; set; }
            public List<MyPoint> pointList = new List<MyPoint>();
            public MyColor(int _colorValue)
            {
                colorValue = _colorValue;
            }
            public bool Equals(MyColor other)
            {
                if (this.colorValue == other.colorValue)
                {
                    return true;
                }
                return false;
            }
        }
        public class MyPoint
        {
            public int xCoord { get; set; }
            public int yCoord { get; set; }
        
            public MyPoint(int _xCoord, int _yCoord)
            {
                xCoord = _xCoord;
                yCoord = _yCoord;
            }
        }
        

        【讨论】:

        • 这很酷——但看起来它给了我一个区域内的每一个点。我需要做的是找到一个区域周围的轮廓。
        • 操作被误解了!好吧,我已经用 c++ 编写了您要求的代码,但我现在找不到它。但是你仍然可以检查 pointList 上的点是否所有的邻居都是相同的颜色。如果所有邻居都是相同的颜色,您可以将其移除,但不是那么有效,但只是一个技巧。
        • 顺便说一句,您可以尝试使用 sobel 边缘过滤器来找出区域的轮廓。
        【解决方案5】:

        如果您遇到堆栈溢出,我猜您并未排除已检查的像素。参观广场的第一个检查应该是您以前是否来过这里。

        另外,不久前我正在研究一个相关问题,我想出了一种使用更少内存的不同方法:

        一个队列:

        AddPointToQueue(x, y);
        repeat
           x, y = HeadItem;
           AddMaybe(x - 1, y); x + 1, y; x, y - 1; x, y + 1;
        until QueueIsEmpty;
        
        AddMaybe(x, y):
        if Visited[x, y] return;
        Visited[x, y] = true;
        AddPointToQueue(x, y);
        

        这种方法的要点是,您的队列基本上会在映射区域周围保留一条线。这比堆栈更好地限制了内存使用。

        如果相关,也可以对其进行简单修改以产生到任何正方形的行进距离。

        【讨论】:

          【解决方案6】:

          尝试使用 AForge.net。我会选择按颜色、阈值进行过滤,然后你可以做一些形态学来减少黑/白区域以失去对象之间的接触。然后你就可以去找 Blob。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-10-08
            • 1970-01-01
            • 1970-01-01
            • 2020-11-23
            • 2018-03-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多