简体   繁体   English

如何检测图像中的不规则边框?

[英]How do I detect irregular borders in an image?

Given the image below, what algorithm might I use to detect whether regions one and two (identified by color) have a border? 鉴于下面的图像,我可以使用什么算法来检测区域1和2(由颜色标识)是否有边框?

http://img823.imageshack.us/img823/4477/borders.png http://img823.imageshack.us/img823/4477/borders.png

If there's a C# example out there, that would be awesome, but I'm really just looking for any example code. 如果那里有一个C#示例,那将是非常棒的,但我真的只是在寻找任何示例代码。

Edit: Using Jaro's advice, I came up with the following... 编辑:使用Jaro的建议,我想出了以下内容......

public class Shape
{
    private const int MAX_BORDER_DISTANCE = 15;

    public List<Point> Pixels { get; set; }

    public Shape()
    {
        Pixels = new List<Point>();
    }

    public bool SharesBorder(Shape other)
    {
        var shape1 = this;
        var shape2 = other;

        foreach (var pixel1 in shape1.Pixels)
        {
            foreach (var pixel2 in shape2.Pixels)
            {
                var xDistance = Math.Abs(pixel1.X - pixel2.X);
                var yDistance = Math.Abs(pixel1.Y - pixel2.Y);

                if (xDistance > 1 && yDistance > 1)
                {
                    if (xDistance * yDistance < MAX_BORDER_DISTANCE)
                        return true;
                }
                else
                {
                    if (xDistance < Math.Sqrt(MAX_BORDER_DISTANCE) &&
                        yDistance < Math.Sqrt(MAX_BORDER_DISTANCE))
                        return true;
                }
            }
        }

        return false;
    }

    // ...
}

Clicking on two shapes that do share a border returns fairly quickly, but very distance shapes or shapes with a large number of pixels take 3+ seconds at times. 单击两个共享边框的形状返回相当快,但非常距离的形状或具有大量像素的形状有时需要3秒以上。 What options do I have for optimizing this? 我有什么选择来优化它?

2 regions having border means that within a certain small area there should be 3 colors present: red, black and green. 2个具有边界的区域意味着在某个小区域内应该存在3种颜色:红色,黑色和绿色。

So a very ineffective solution presents itself: using Color pixelColor = myBitmap.GetPixel(x, y); 因此,一个非常无效的解决方案呈现出来:使用Color pixelColor = myBitmap.GetPixel(x, y); you could scan an area for those 3 colors. 你可以扫描一个区域的3种颜色。 The area must be larger than the width of the border of course. 当然,该区域必须大于边界的宽度。

There is of course plenty room for optimizations (like going in 50 pixels steps and decreasing the precision continually). 当然有足够的优化空间(比如以50像素的步长并不断降低精度)。 Since black is the least used color, you would search around black areas first. 由于黑色是最少使用的颜色,因此您首先会搜索黑色区域。

This should explain what I have written in various comments in this topic: 这应该解释我在本主题的各种评论中所写的内容:

namespace Phobos.Graphics
{
    public class BorderDetector
    {
        private Color region1Color = Color.FromArgb(222, 22, 46);
        private Color region2Color = Color.FromArgb(11, 189, 63);
        private Color borderColor = Color.FromArgb(11, 189, 63);

        private List<Point> region1Points = new List<Point>();
        private List<Point> region2Points = new List<Point>();
        private List<Point> borderPoints = new List<Point>();

        private Bitmap b;

        private const int precision = 10;
        private const int distanceTreshold = 25;

        public long Miliseconds1 { get; set; }
        public long Miliseconds2 { get; set; }

        public BorderDetector(Bitmap b)
        {
            if (b == null) throw new ArgumentNullException("b");

            this.b = b;
        }

        private void ScanBitmap()
        {
            Color c;

            for (int x = precision; x < this.b.Width; x += BorderDetector.precision)
            {
                for (int y = precision; y < this.b.Height; y += BorderDetector.precision)
                {
                    c = this.b.GetPixel(x, y);

                    if (c == region1Color) region1Points.Add(new Point(x, y));
                    else if (c == region2Color) region2Points.Add(new Point(x, y));
                    else if (c == borderColor) borderPoints.Add(new Point(x, y));
                }
            }
        }

        /// <summary>Returns a distance of two points (inaccurate but very fast).</summary>
        private int GetDistance(Point p1, Point p2)
        {
            return Math.Abs(p1.X - p2.X) + Math.Abs(p1.Y - p2.Y);
        }

        /// <summary>Finds the closests 2 points among the points in the 2 sets.</summary>
        private int FindClosestPoints(List<Point> r1Points, List<Point> r2Points, out Point foundR1, out Point foundR2)
        {
            int minDistance = Int32.MaxValue;
            int distance = 0;

            foundR1 = Point.Empty;
            foundR2 = Point.Empty;

            foreach (Point r1 in r1Points)
                foreach (Point r2 in r2Points)
                {
                    distance = this.GetDistance(r1, r2);

                    if (distance < minDistance)
                    {
                        foundR1 = r1;
                        foundR2 = r2;
                        minDistance = distance;
                    }
                }

            return minDistance;
        }

        public bool FindBorder()
        {
            Point r1;
            Point r2;

            Stopwatch watch = new Stopwatch();

            watch.Start();
            this.ScanBitmap();
            watch.Stop();
            this.Miliseconds1 = watch.ElapsedMilliseconds;

            watch.Start();
            int distance = this.FindClosestPoints(this.region1Points, this.region2Points, out r1, out r2);
            watch.Stop();
            this.Miliseconds2 = watch.ElapsedMilliseconds;

            this.b.SetPixel(r1.X, r1.Y, Color.Green);
            this.b.SetPixel(r2.X, r2.Y, Color.Red);

            return (distance <= BorderDetector.distanceTreshold);
        }
    }
}

It is very simple. 这很简单。 Searching this way only takes about 2 + 4 ms (scanning and finding the closest points). 以这种方式搜索只需要大约2 + 4 ms (扫描并找到最近的点)。

You could also do the search recursively: first with precision = 1000, then precision = 100 and finally precision = 10 for large images. 您也可以递归搜索:首先是精度= 1000,然后是精度= 100,最后精度= 10,用于大图像。 FindClosestPoints will practically give you an estimated rectangual area where the border should be situated (usually borders are like that). FindClosestPoints实际上会给你一个估计的矩形区域,边界应该位于该区域(通常边界就是这样)。

Then you could use the vector approach I have described in other comments. 然后你可以使用我在其他评论中描述的向量方法。

I read your question as asking whether the two points exist in different regions. 我把你的问题看作是问这两个点是否存在于不同的地区。 Is this correct? 它是否正确? If so, I would probably use a variation of Flood Fill . 如果是这样,我可能会使用洪水填充的变化。 It's not super difficult to implement (don't implement it recursively, you will almost certainly run out of stack space) and it will be able to look at complex situations like a U-shaped region that has a border between two points, but are not actually different regions. 实现起来并不困难(不要递归地实现它,你几乎肯定会耗尽堆栈空间)并且它能够看到复杂的情况,比如U形区域,它有两个点之间的边界,但是实际上不是不同的地区 Basically run flood fill, and return true when your coordinate matches the target coordinate (or perhaps when it's close enough for your satisfaction, depending on your use case) 基本上运行泛洪填充,并在您的坐标与目标坐标匹配时返回true(或者当它足够接近您的满意度时,根据您的使用情况返回)

[Edit] Here is an example of flood fill that I wrote for a project of mine. [编辑]这是我为我的一个项目写的洪水填充的一个例子 The project is CPAL-licensed, but the implementation is pretty specific to what I use it for anyway, so don't worry about copying parts of it. 该项目是CPAL许可的,但实现非常具体到我用它的方式,所以不要担心复制它的一部分。 And it doesn't use recursion, so it should be able to scale to pixel data. 并且它不使用递归,因此它应该能够缩放到像素数据。

[Edit2] I misunderstood the task. [编辑2]我误解了这个任务。 I don't have any example code that does exactly what you're looking for, but I can say that comparing pixel-per-pixel the entire two regions is not something you want to do. 我没有任何示例代码可以完全满足您的需求,但我可以说,比较每像素像素并不是您想要做的事情。 You can reduce the complexity by partitioning each region into a larger grid (maybe 25x25 pixels), and comparing those sectors first, and if any of those are close enough, do a pixel-per-pixel comparison just within those two sectors. 您可以通过将每个区域划分为更大的网格(可能是25x25像素)来降低复杂性,并首先比较这些扇区,如果其中任何一个足够接近,则在这两个扇区内进行像素/像素比较。

[Edit2.5] [Quadtree] 3 might be able to help you too. [Edit2.5] [四叉树] 3也许能够帮到你。 I don't have a lot of experience with it, but I know it's popular in 2D collision detection, which is similar to what you're doing here. 我没有很多经验,但我知道它在2D碰撞检测中很受欢迎,这与你在这里做的很相似。 Might be worth researching. 可能值得研究。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM