简体   繁体   English

如何使用 BoofCV 在 Java 中分水岭(分割)图像?

[英]How to watershed(segment) an image in Java with BoofCV?

I am trying to segment a simple image using watershed function provided by BoofCV in Java.我正在尝试使用 BoofCV 在 Java 中提供的分水岭函数来分割一个简单的图像。 So I have writen (copied, edited and adjusted) the following code :所以我写了(复制、编辑和调整)以下代码:

package alltestshere;

import boofcv.alg.filter.binary.BinaryImageOps;
import boofcv.alg.filter.binary.Contour;
import boofcv.alg.filter.binary.GThresholdImageOps;
import boofcv.gui.ListDisplayPanel;
import boofcv.gui.binary.VisualizeBinaryData;
import boofcv.gui.image.ShowImages;
import boofcv.io.UtilIO;
import boofcv.io.image.ConvertBufferedImage;
import boofcv.io.image.UtilImageIO;
import boofcv.struct.ConnectRule;
import boofcv.struct.image.GrayS32;
import boofcv.struct.image.GrayU8;
import java.awt.image.BufferedImage;
import java.util.List;
import boofcv.alg.segmentation.watershed.WatershedVincentSoille1991;
import boofcv.factory.segmentation.FactorySegmentationAlg;
import boofcv.gui.feature.VisualizeRegions;



public class examp {

   public static void main( String args[] ) {
    // load and convert the image into a usable format
    BufferedImage image = UtilImageIO.loadImage(UtilIO.pathExample("C:\\\\Users\\\\Caterina\\\\Downloads\\\\boofcv\\\\data\\\\example\\\\shapes\\\\shapes02.png"));
    // convert into a usable format
    GrayU8 input = ConvertBufferedImage.convertFromSingle(image, null, GrayU8.class);

//declare some of my working data
    GrayU8 binary = new GrayU8(input.width,input.height);
    GrayS32 markers = new GrayS32(input.width,input.height);

    // Select a global threshold using Otsu's method.
    GThresholdImageOps.threshold(input, binary, GThresholdImageOps.computeOtsu(input, 0, 255),true);

    //through multiple erosion you can obtain the sure foreground and use it as marker in order to segment the image
    GrayU8 filtered = new GrayU8 (input.width, input.height);
    GrayU8 filtered2 = new GrayU8 (input.width, input.height);
    GrayU8 filtered3 = new GrayU8 (input.width, input.height);
    BinaryImageOps.erode8(binary, 1, filtered);
    BinaryImageOps.erode8(filtered, 1, filtered2);
    BinaryImageOps.erode8(filtered2, 1, filtered3);

//count how many markers you have (one for every foreground part +1 for the background
    int numRegions = BinaryImageOps.contour(filtered3, ConnectRule.EIGHT, markers).size()+1 ;


    // Detect foreground imagea using an 8-connect rule
    List<Contour> contours = BinaryImageOps.contour(binary, ConnectRule.EIGHT, markers);

    //Watershed function which takes the original b&w image as input and the markers 
    WatershedVincentSoille1991 watershed = FactorySegmentationAlg.watershed(ConnectRule.FOUR);
    watershed.process(input, markers);

    //get the results of the watershed as output
    GrayS32 output = watershed.getOutput();


    // display the results
    BufferedImage visualBinary = VisualizeBinaryData.renderBinary(input, false, null);
    BufferedImage visualFiltered = VisualizeBinaryData.renderBinary(filtered3, false, null);
    BufferedImage visualLabel = VisualizeBinaryData.renderLabeledBG(markers , contours.size(), null);
    BufferedImage outLabeled = VisualizeBinaryData.renderLabeledBG(output, numRegions, null);


    ListDisplayPanel panel = new ListDisplayPanel();
    panel.addImage(visualBinary, "Binary Original");
    panel.addImage(visualFiltered, "Binary Filtered");
    panel.addImage(visualLabel, "Markers");
    panel.addImage(outLabeled, "Watershed");
    ShowImages.showWindow(panel,"Watershed");
    }

}

This code, however does not work well.但是,此代码效果不佳。 Specifically, instead of colouring with different colours the foreground objects and leave the background as it may, it just splits all the image into region while each regions consists of only one foreground object and some part of the background and paints all this part with the same colour (picture 3).具体来说,与其用不同颜色的前景对象着色并保留背景,它只是将所有图像分割成区域,而每个区域仅由一个前景对象和一部分背景组成,并用相同的颜色绘制所有这部分颜色(图 3)。 So, what do I do wrong?那么,我做错了什么?

I am uploading the Original Picture Markers Picture and Watershed Picture我正在上传原始图片标记图片分水岭图片

Thanks in advance, Katerina提前致谢,卡特琳娜

You get this result because you are not processing the background as a region.你得到这个结果是因为你没有将背景作为一个区域来处理。 The markers you provide to watershed are only the contour of your shapes.您提供给分水岭的标记只是形状的轮廓。 Since the background isn't a region, the watershed algorithm splits it equally to each region.由于背景不是一个区域,分水岭算法将其平均分割为每个区域。 It is done equally because the distance in your original image of each shape to the background is the same (binary image).这样做是一样的,因为每个形状的原始图像与背景的距离是相同的(二进制图像)。

If you want to get the background as another region, then provide to the watershed algorithm some points of the background as markers such as the corners for example.如果您想将背景作为另一个区域,则向分水岭算法提供一些背景点作为标记,例如角点。

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

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