是否有适当的算法来检测图形的背景颜色?

Vol*_*ort 8 java image

对于大学,我们已经给出了一个任务,在给定图像的情况下,我们必须识别"数字",它们的颜色以及它们内部的"像素组"的数量.让我解释:

在此输入图像描述

上面的图像有一个图形(在图像中可以有多个图形,但让我们暂时忘记它).

  • 画布的背景颜色是0,0处的像素(在本例中为黄色)
  • 图形的边框颜色为黑色(可以是除画布背景颜色以外的任何颜色).
  • 图的背景颜色为白色(也可以与画布的背景颜色相同).
  • 图形只能有一种背景颜色.
  • 图中有两个像素组.一个是蓝色像素池,另一个是红色池,里面有一些绿色.如您所见,像素组像素的颜色无关紧要(它与图形的背景颜色不同).重要的是他们有联系(甚至是对角线).因此,尽管有两种不同的颜色,但无论如何这种群体只被认为是一种.
  • 如您所见,边界可以像您希望的那样不规则.然而,它只有一种颜色.
  • 众所周知,像素组不会触及边界.
  • 有人告诉我,除了图的背景颜色外,像素组的颜色可以是任何颜色.我假设它可以与图的边框颜色(黑色)相同.

我们已经给出了一个能够拍摄图像并将它们转换为矩阵的类(每个元素是表示像素颜色的整数).

就是这样.我是用Java做的.

我做了什么

  • 遍历矩阵中的每个像素
  • 如果我发现一个与背景颜色不同的像素,我会认为它属于图的边界.initialPixel从现在开始我会调用这个像素.
  • 请注意,initialPixel我提供的图像中的黑色像素位于图的左上角.我有目的地在那里做了一个尖锐的切口来说明它.
  • 我现在的任务是找到图形的背景颜色(在这种情况下是白色).

但是我找到这样的背景颜色(白色)会遇到很多麻烦.这是我做的最接近的方法,适用于某些情况 - 但不适用于此图像:

  • 因为我知道边框的颜色,我能找到的第一个不同的颜色,是对南方initialPixel.听起来好像是个好主意 - 它确实有效,但它不适用于所提供的图像:在这种情况下它将返回黄色,因为initialPixel它远离图形的内容.

假设我确实找到了图形的背景颜色(白色),我的下一个任务就是要意识到图中存在两个像素组.这个似乎更容易:

  • 由于我现在知道图形的背景颜色(白色),我可以尝试遍历图中的每个像素,如果我发现一个不属于边框并且不是图形背景的一部分,我已经可以告诉它有一个像素组.我可以开始递归函数来找到与这样的组相关的所有像素并"标记"它们,以便在将来的迭代中我可以完全忽略这些像素.

我需要的

是的,我的问题是关于如何找到图形的背景颜色(请记住它可以与整个图像的背景颜色相同 - 现在它是黄色的,但它也可以是白色的)基于我之前描述的内容.

我不需要任何代码 - 我只是在为这样的代码思考一个合适的算法.边界可能有如此奇怪的不规则线条的事实正在扼杀我.

或者甚至更好:我一直都做错了吗?也许我根本不应该如此关注这一点initialPixel.也许一种不同的初始方法会起作用?有关于此类主题的文档/示例吗?我意识到有很多关于"计算机视觉"等的研究,但我对这个特殊问题找不到多少.

一些代码

我的函数检索带有所有数字的向量:*注意:Figure只是一个包含一些值的类,如背景颜色和元素数量.

public Figure[] getFiguresFromImage(Image image) {
    Figure[] tempFigures = new Figure[100];
    int numberOfFigures = 0;
    matrixOfImage = image.getMatrix();
    int imageBackgroundColor = matrixOfImage[0][0];
    int pixel = 0;

    for (int y = 0; y < matrixOfImage.length; ++y) {
        for (int x = 0; x < matrixOfImage[0].length; ++x) {
            pixel = matrixOfImage[y][x];
            if (!exploredPixels[y][x]) {
                // This pixel has not been evaluated yet
                if (pixel != imageBackgroundColor ) {
                    // This pixel is different than the background color
                    // Since it is a new pixel, I assume it is the initial pixel of a new figure
                    // Get the figure based on the initial pixel found
                    tempFigures[numberOfFigures] = retrieveFigure(y,x);
                    ++numberOfFigures;
                }
            }
        }   
    }

    // ** Do some work here after getting my figures **

    return null;
}
Run Code Online (Sandbox Code Playgroud)

然后,显然,功能retrieveFigure(y,x)是我无法做到的.

笔记:

  • 出于学习目的,我不应该使用任何外部库.

Cam*_*Cam 5

解决此问题的一种好方法是将图像视为图表,其中每个颜色填充区域都有一个节点(此答案中的“组件”)。

这是实现此方法的一种方法:

  1. 将所有像素标记为未访问。
  2. 对于每个像素,如果未访问该像素,请对其执行泛洪填充算法。在填充期间,将每个已连接的像素标记为已访问。

    现在,您应该在图像(或“组件”)中具有纯色区域的列表,因此您只需要弄清楚它们如何相互连接:

  3. 查找像素与背景颜色分量相邻的分量-这是图形边框。请注意,您可以通过找到具有0,0像素的成分来找到背景颜色成分。

  4. 现在,找到像素与新发现的“图边框”组件相邻的组件。将有两个这样的组件-选择一个不是背景的组件(即没有0​​,0像素的组件)。这是您的图形背景。

  5. 要查找像素组,只需计算与图形背景分量相邻的像素的分量数(当然忽略图形边界分量)

这种方法的优点:

  • 以O(#像素)时间运行。
  • 易于理解和实施。
  • 不假定背景色和图形背景色不同。

为了确保您了解如何遍历组件及其邻居,下面是步骤5的示例伪代码实现:

List<Component> allComponents; // created in step 2
Component background; // found in step 3 (this is the component with the 0,0 pixel)
Component figureBorder; // found in step 4
List<Component> pixelGroups = new List<Component>(); // list of pixel groups

for each Component c in allComponents:
    if c == background:
        continue;
    for each Pixel pixel in c.pixelList:
        for each Pixel neighbor in pixel.neighbors:
            if neighbor.getComponent() == figureBorder:
                c.isPixelGroup = true;

int numPixelGroups = 0;
for each Component c in allComponents:
    if (c.isPixelGroup)
        numPixelGroups++;
Run Code Online (Sandbox Code Playgroud)