【问题标题】:How to separate an image into two with java如何使用java将图像分成两部分
【发布时间】:2011-01-10 01:49:35
【问题描述】:

我想知道是否有一种“智能”方法可以根据某些特征分割图像。

图像为 300x57,黑白(实际上是灰度,但大多数颜色是黑色或白色),它由两个主要特征(我们称之为斑点)组成,由黑色空间隔开,每个斑点的宽度和高度,斑点的位置也不同,斑点永远不会重叠!

这是图像“看起来”的样子:

-------------------------
----WWW---------WWWWW----
---WWWWWWW----WWWWWW-----
-----WWWW-------WWW------
-------------------------

生成的拆分将是这样的:

------------     -------------
----WWW-----     ----WWWWW----
---WWWWWWW--     --WWWWWW-----
-----WWWW---     ----WWW------
------------     -------------

为了分割图像,我计划采取的步骤:

  1. 将图像从一侧扫描到另一侧。
  2. 确定斑点的边缘。
  3. 测量两个内边缘之间的距离。
  4. 在内距离的中间分割图像。
  5. 将这两个图像保存为单独的文件。

如果我标准化图像宽度会很好,这样我的所有图像在保存时都有统一的宽度。

我没有图像处理方面的经验,所以我不知道这样做的有效方法是什么。我目前正在使用 BufferedImage,获取宽度/高度,迭代每个像素等。我的问题没有错误的解决方案,但我正在寻找更高效的解决方案(更少的代码 + 更快)。我也一直在研究 java.awt.Graphics...

如果我能得到一些想法来更有效地完成这项任务,我将不胜感激。我想坚持使用 Java 的内置库,那么在这种情况下使用 BufferedImage 或 Graphics2D 是最有效的吗?

编辑: 以下是阅读建议后的代码:

public void splitAndSaveImage( BufferedImage image ) throws IOException
{
    // Process image ------------------------------------------         
    int height = image.getHeight();
    int width = image.getWidth();
    boolean edgeDetected = false;
    double averageColor = 0;
    int threshold = -10;
    int rightEdge = 0;
    int leftEdge = 0;
    int middle = 0;

    // Scan the image and determine the edges of the blobs.
    for(int w = 0; w < width; ++w)
    {               
        for(int h = 0; h < height; ++h)
        {
            averageColor += image.getRGB(w, h);
        }

        averageColor = Math.round(averageColor/(double)height);

        if( averageColor /*!=-1*/< threshold && !edgeDetected )
        {
            // Detected the beginning of the right blob
            edgeDetected = true;
            rightEdge = w;
        }else if( averageColor >= threshold && edgeDetected )
        {
            // Detected the end of the left blob
            edgeDetected = false;
            leftEdge = leftEdge==0? w:leftEdge;
        }

        averageColor = 0;
    }

    // Split the image at the middle of the inside distance.
    middle = (leftEdge + rightEdge)/2;

    // Crop the image
    BufferedImage leftImage = image.getSubimage(0, 0, middle, height);

    BufferedImage rightImage = image.getSubimage(middle, 0, (width-middle), height);

    // Save the image
    // Save to file -------------------------------------------
    ImageIO.write(leftImage, "jpeg", new File("leftImage.jpeg"));

    ImageIO.write(rightImage, "jpeg", new File("rightImage.jpeg"));
}

【问题讨论】:

  • 注意:检测到右边缘后,可以简单地跳出for循环。

标签: java graphics image-processing image-manipulation


【解决方案1】:

我不知道 edge detection algorithm 不需要遍历像素,因此您目前的方法可能是最佳的。根据其他因素,您或许可以利用 ImageJ,它拥有大量的 analytical plugins

附录:考虑到避免外部依赖的偏好,BufferedImage 是一个不错的选择。一旦你确定了边缘,getSubimage() 方法就很方便了。您可以在卷积中有效地使用RastergetPixels() 方法之一。 ImageIO可以写结果。

【讨论】:

  • @trashgod 好点...那么 BufferedImage 和 Graphics2D 是在 java 库中使用的最好的东西吗(我不想去外部)?
  • 是的;我在上面添加了一些细节。
【解决方案2】:

我认为除了扫描每一行并在获得白色->黑色->白色过渡时停止(无需扫描整行!)之外,没有任何理由做任何事情。 如果您可以对 blob 的位置做出任何猜测,可能可以通过在图像中间选择一个起点然后从那里左右搜索来稍微改进它。 但我严重怀疑这是否值得。

也无需先对图像运行边缘检测算法。只需扫描线条!

编辑:伯纳先生指出,这不适用于凹面物体。

【讨论】:

  • 当 blob 为凹形时会中断。如果 blob 的顶部形状像手指,则可以在没有找到第一个 blob 的边缘的情况下获得白色 -> 黑色 -> 白色过渡。
  • @Mr.伯纳:是的。它只会(可靠地)用于凸斑点。
【解决方案3】:

blob 之间的间隔重要吗?如果您不需要平衡空白空间,只需在 blob 之间找到一条垂直白线即可。检查中心垂直线是否只有白色像素。如果中间行有黑色像素,则左右扫描第一行只有白色像素。要检查两个斑点都位于中心一侧的情况,请扫描水平线以获得黑白间隔。如果选定的垂直线位于由黑色间隔包围的白色间隔内,您将知道图像分割的每一侧至少有一个斑点。

如果这些检查失败,则需要扫描额外的行,但对于所有格式良好的图像,其中斑点位于图像的左右两半的中心,此方法将只进行两次行扫描。对于其他图像,此方法可能需要更长的时间,甚至对于边缘情况图像会中断。这个例子会中断:

-------------------------
----WWW----WWWWWWWWWW----
---WWWWWWW----WWWWWW-----
-----WWWWWWWW---WWW------
-------------------------

但问题似乎表明这种情况是不可能的。如果此图像拆分背后的原因需要处理每张图像,您将需要一个后备方法。如果可以拒绝边缘情况,则不需要回退方法。一旦扫描发现图像超出可接受的范围,您可以停止检查图像。例如,如果在图像的中心三分之一处找不到垂直的全白线,您可以拒绝该图像。或者您可以只使用此方法作为优化,仅在两行上运行此检查以查找并分割格式良好的图像,然后将格式不佳的图像传递给更彻底的算法。

【讨论】:

  • 我喜欢扫描水平线的想法...我会尝试一下。在我的 1000 多张图像样本中,我没有一张图像中两个斑点的一部分占据同一条垂直线,斑点总是被几条白线隔开。
【解决方案4】:

执行此操作的一种简单方法是将每列(向下)中的像素值相加,以创建一个平均值数组(与输入图像的宽度相同)。从数组的中间开始,搜索最小值。这将是您可以分割图像的列。

此列可能不会是您的 blob 之间间隙的中心。您可以从该列再次向外搜索,先向左查找所有相似的列,然后再向右。

-------------------------
----WWW---------WWWWW----
---WWWWWWW----WWWWWW-----
-----WWWW-------WWW------
-------------------------

col 平均:

---wwWWwww-----wWWWWww---

根据两个斑点之间的空白程度(像素值),您可以将阈值设置得非常低。如果有一些噪音,它必须更高一点。

找到正确的阈值可能是一件苦差事,除非您可以通过算法确定它。

【讨论】:

  • 是的,这就是我最终做的。我会把代码贴出来给别人看看。
猜你喜欢
  • 2017-12-06
  • 1970-01-01
  • 2023-04-01
  • 1970-01-01
  • 2019-11-05
  • 1970-01-01
  • 2010-11-27
  • 2014-09-02
  • 1970-01-01
相关资源
最近更新 更多