繁体   English   中英

如何用java将图像分成两部分

[英]How to separate an image into two with java

我想知道是否存在基于某些特征分割图像的“智能”方式。

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

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

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

由此产生的分裂将是这样的:

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

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

  1. 将图像从一侧扫描到另一侧。
  2. 确定blob的边缘。
  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"));
}

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

此列可能不会是blob之间差距的中心。 您可以从此列进行另一次向外搜索,向左移动以查找所有类似的列,然后向右移动。

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

col avg:

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

根据两个blob之间空白的空白(像素值),您可以将阈值设置得相当低。 如果有一些噪音,它必须要高一点。

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

我不知道边缘检测 算法不需要迭代像素,所以你现在的方法可能是最佳的。 根据其他因素,您可以利用ImageJ ,它具有大量的分析插件

附录:鉴于偏好避免外部依赖, BufferedImage是一个不错的选择。 一旦识别出边缘, getSubimage()方法getSubimage()方便了。 您可以在卷积中有效地使用其中一种Raster getPixels()方法。 ImageIO可以写出结果。

我认为没有任何理由除了扫描每一条线以外的任何事情,当你得到白色 - >黑色 - >白色过渡时停止(不需要扫描整条线!)。 如果您可以对blob的位置进行任何猜测,您可以通过在图像中间选择一个起点然后从那里向左和向右搜索来稍微改进它。 但我非常怀疑这是值得的。

也不需要首先在图像上运行边缘检测算法。 只需扫描线条!

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

blob之间的差距是否重要? 如果您不需要平衡空白区域,则只需要在blob之间找到垂直白线就可以减少工作量。 检查中心垂直线是否只有白色像素。 如果中间线具有黑色像素,则向左和向右扫描仅具有白色像素的第一行。 要检查两个斑点都在中心一侧的情况,请扫描水平线以获得黑白黑色间隔。 如果所选垂直线位于由黑色间隔围绕的白色间隔内,则您将知道图像分割的每一侧至少有一个斑点。

如果未通过这些检查,则需要扫描其他线条,但对于所有格式良好的图像,斑点位于图像左右两半的中心位置,此方法仅需扫描两行。 对于边缘情况图像,该方法对于其他图像可能花费更长时间,或甚至中断。 这会打破这个例子:

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

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

暂无
暂无

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

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