Как разделить изображение на Java с помощью BoofCV? - PullRequest
0 голосов
/ 08 ноября 2018

Я пытаюсь сегментировать простое изображение, используя функцию водораздела, предоставленную BoofCV в Java. Поэтому я написал (скопировал, отредактировал и настроил) следующий код:

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");
    }

}

Этот код, однако, не работает хорошо. В частности, вместо окрашивания различными цветами объектов переднего плана и оставления фона, как это возможно, он просто разбивает все изображение на области, в то время как каждая область состоит только из одного объекта переднего плана и некоторой части фона и закрашивает всю эту часть одним и тем же цвет (рисунок 3). Итак, что я делаю не так?

Я загружаю Исходное изображение Изображение маркеров и Изображение водораздела

Спасибо заранее, Катерина

1 Ответ

0 голосов
/ 08 ноября 2018

Вы получаете этот результат, потому что вы не обрабатываете фон как регион. Маркеры, которые вы предоставляете водоразделу, являются только контуром ваших форм. Поскольку фон не является регионом, алгоритм водораздела разделяет его поровну по каждому региону. Это делается одинаково, потому что расстояние в исходном изображении каждой фигуры до фона одинаково (двоичное изображение).

Если вы хотите получить фон в качестве другого региона, предоставьте алгоритму водораздела некоторые точки фона в качестве маркеров, например, такие как углы.

...