简体   繁体   English

如何检测图像中的彩色矩形?

[英]How to detect a colored rectangles in an image?

I'm trying to write an AI maze solver program. 我正在尝试编写AI迷宫求解器程序。 To do this, I will draw 2-color mazes in GIMP with red being walls and blue being background or floor. 为此,我将在GIMP中绘制2色迷宫,红色是墙壁,蓝色是背景或地板。 Then I will export from GIMP as a png and use ImageIO.read() to get a BufferedImage object of the maze. 然后,我将从GIMP导出为png并使用ImageIO.read()获得迷宫的BufferedImage对象。 Finally, I will assign Rectangle hitboxes to walls and store them in an ArrayList so I can use .intersect() to check for sprite contact with walls. 最后,我将Rectangle hitboxs分配给墙壁,并将它们存储在ArrayList以便可以使用.intersect()来检查精灵是否与墙壁接触。 I can work with it from here. 我可以在这里使用它。

However, there is one thing I want to be able to do for my program that I don't know how to do: Once I have stored my image as a BufferedImage , how can I detect the red parts (all the exact same RGB shade of red) and create matching Rectangle s? 但是,我想对我的程序做一件事,我不知道该怎么做:将图像存储为BufferedImage ,如何检测红色部分(所有完全相同的RGB阴影)红色)并创建匹配的Rectangle s?

Notes: 笔记:

  • Mazes will always be of fixed size (1000x1000 pixels). 迷宫将始终具有固定大小(1000x1000像素)。
  • There is a fixed starting point for each maze 每个迷宫都有一个固定的起点
  • The red areas will always form straight rectangles. 红色区域将始终形成直线矩形。 The Rectangle objects which I create are just used as hitboxes so I can use .intersect() , never drawn or anything like that. 我创建的Rectangle对象仅用作hitbox,因此我可以使用.intersect() ,从不绘制或类似的东西。
  • Rectangle s that are created will be stored in an ArrayList . 创建的Rectangle将存储在ArrayList

Example Maze: (a simple one) 迷宫示例:(一个简单的例子 在此处输入图片说明

What I want to be able to do: (green areas being where the java.awt.Rectangles are created and stored into ArrayList ) 我想要做的是:(绿色区域是java.awt.Rectangles的创建位置,并存储在ArrayList

在此处输入图片说明

I will provide a quite naive way of solving the problem (not fully implemented, just so you get the idea).. Have a list of all rectangles List<Rectangle> mazeRectangles . 我将提供一种非常幼稚的方法来解决该问题(尚未完全实现,只是为了您能理解主意)。具有所有矩形的List<Rectangle> mazeRectangles All rectangles will be stored here.. And of course the image BufferedImage image; 所有矩形都将存储在这里。当然,图像BufferedImage image; Now we will iterate over all pictures until we find one with the right colour Every time we found a rectangle, we will skip all x values for the width of the rectangle.. 现在,我们将遍历所有图片,直到找到一张具有正确颜色的图片。每次找到一个矩形时,我们将跳过所有x值以获取矩形的宽度。

//iterate over every pixel..
for (int y = 0; y < image.getHeight(); y++) {
    for (int x = 0; x < image.getWidth(); x++) {
        //check if current pixel has maze colour
        if(isMazeColour(image.getRGB(x, y))){
            Rectangle rect = findRectangle(x, y);
            x+=rect.width;
        }
    }
}

Your method for checking the colour: 您检查颜色的方法:

public boolean isMazeColour(int colour){
    // here you should actually check for a range of colours, since you can
    // never expect to get a nicely encoded image..
    return colour == Color.RED.getRGB();
}

The interesting part is the findRectangle method.. We see if there is already a Rectangle which contains our coordinates. 有趣的部分是findRectangle方法。.我们看是否已经存在一个包含我们坐标的Rectangle If so return it, otherwise create a new Rectangle , add it to the list and return it. 如果是这样,则返回它,否则创建一个新的Rectangle ,将其添加到列表中并返回。 If we have to create a new Rectangle , we will first check it's width. 如果必须创建一个新的Rectangle ,我们将首先检查它的宽度。 The annoying part about this is, that you'll still have to check every pixel for the rest of the rectangle, since you might have a configuration like that: 烦人的部分是,您仍然必须检查矩形其余部分的每个像素,因为您可能具有如下配置:

+++++++
+++++++
###
###

where # and + are separate boxes. 其中#+是单独的框。 So we first find the width: 所以我们首先找到宽度:

public Rectangle findRectangle(int x, int y){
    // this could be optimized. You could keep a separate collection where
    // you remove rectangles from, once your cursor is below that rectangle
    for(Rectangle rectangle : mazeRectangles){ 
        if(!rectangle.contains(x, y)){
            return rectangle;
        }
    }
    //find the width of the `Rectangle`
    int xD = 0;
    while(x+xD < width && isMazeColour(image.getRGB(x+xD+1, y))){
        xD++;
    }

    int yD = 0; //todo: find height of rect..

    Rectangle toReturn = new Rectangle(x, y, xD, yD);
    mazeRectangles.add(toReturn);
    return toReturn;
}

I didn't implement the yD part, since it's a bit messy and I am a little lazy, but you'd need to iterate over y and check each row (so two nested loops) 我没有实现yD部分,因为它有点混乱并且有点懒,但是您需要遍历y并检查每一行(因此有两个嵌套循环)

Note that this algorithm might result in overlapping Rectangle s. 请注意,此算法可能会导致Rectangle重叠。 if you don't want that, when finding xD check for each pixel if it is already contained in a Rectangle . 如果您不希望这样做,请在查找xD检查每个像素是否已包含在Rectangle Only expand xD as long as you are not inside another Rectangle . 只要您不在另一个Rectangle ,请仅扩展xD

Another thing: You might end up with strange artefacts at the border of your rectangles, due to the interpolation of colours between red and blue. 另一件事:由于红色和蓝色之间的颜色插值,您最终可能会在矩形的边界处留下奇怪的伪像。 Maybe you want to check for Rectangles being to small (like only 1 pixel wide) and get rid of them.. 也许您想检查矩形是否变小(例如只有1像素宽),并摆脱它们。

Last year, someone asked about a more general case for solving a maze. 去年,有人问到解决迷宫的更一般的情况。 They had one additional complexity in that there were multiple paths, but the "correct" path through an intersection was straight. 它们还有一个额外的复杂性,那就是有多条路径,但是通过交叉点的“正确”路径是笔直的。

Python: solve "n-to-n" maze Python:解决“ N对N”迷宫

The solution provided solves the maze by ray-casting. 提供的解决方案通过射线投射解决了迷宫问题。 Starting at the beginning of a path, it projects lines down the path in all directions. 从路径的起点开始,它将沿所有方向沿路径向下投射线条。 Then it sorts the list and chooses the longest line and uses that to calculate the next starting point. 然后,它对列表进行排序并选择最长的线,然后使用该线来计算下一个起点。 Now, it repeats projecting lines in all directions except in the direction it came - the backtrack could be longer than the forward progress. 现在,它会在所有方向上重复投影线, 除了其到达的方向 -回溯可能会比前进进度更长。 That would just bounced the solution around in the longest leg of the maze. 那只会在迷宫中最长的腿周围反弹解决方案。

If you are certain your angles are always 90 degrees, you could modify the code accordingly. 如果确定角度始终为90度,则可以相应地修改代码。

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

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