简体   繁体   中英

How to extract pictogram using boofcv?

I have problems with extracting a pictogram into some further processable format, since now I have got like this:

图片此搜索

Part of the current solution is taken from the BoofCV ImageTresholding example. My code for this solution the following:

import georegression.metric.UtilAngle;

import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;
import java.io.IOException;

import boofcv.alg.color.ColorHsv;
import boofcv.alg.filter.binary.BinaryImageOps;
import boofcv.alg.filter.binary.GThresholdImageOps;
import boofcv.alg.filter.binary.ThresholdImageOps;
import boofcv.gui.ListDisplayPanel;
import boofcv.gui.binary.VisualizeBinaryData;
import boofcv.gui.image.ImagePanel;
import boofcv.gui.image.ShowImages;
import boofcv.io.image.ConvertBufferedImage;
import boofcv.io.image.UtilImageIO;
import boofcv.struct.image.ImageFloat32;
import boofcv.struct.image.ImageUInt8;
import boofcv.struct.image.MultiSpectral;

public class Binaryzation {
    static double splitFraction = 0.05;
    static double minimumSideFraction = 0.1;

    static ListDisplayPanel gui = new ListDisplayPanel();

    public static void printClickedColor(final BufferedImage image) {
        ImagePanel gui = new ImagePanel(image);
        gui.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                float[] color = new float[3];
                int rgb = image.getRGB(e.getX(), e.getY());
                ColorHsv.rgbToHsv((rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF,
                        rgb & 0xFF, color);
                System.out.println("H = " + color[0] + " S = " + color[1]
                        + " V = " + color[2]);
                try {
                    showSelectedColor("Selected", image, color[0], color[1]);
                } catch (IOException e1) {
                    // TODO Auto-generated catch block
                    e1.printStackTrace();
                }
            }
        });

        ShowImages.showWindow(gui, "Color Selector");
    }

    public static void showSelectedColor(String name, BufferedImage image,
            float hue, float saturation) throws IOException {

        ImageUInt8 binary = binaryTreshold(name, image, hue, saturation);
        // MAGIC HAPPENDS -removing small objects
        ImageUInt8 filtered = BinaryImageOps.erode4(binary, 1, null);
        filtered = BinaryImageOps.dilate8(filtered, 1, null);
        filtered = BinaryImageOps.removePointNoise(filtered, filtered);
        ShowImages.showWindow(filtered, "Binary " + name);
        BufferedImage visualFiltered1 = VisualizeBinaryData.renderBinary(
                filtered, true, null);
        ShowImages.showWindow(visualFiltered1, "Mask");
        BufferedImage visualFiltered12 = Fill.fill(visualFiltered1);
        ShowImages.showWindow(visualFiltered12, "Filled Mask");

    ImageUInt8 mask = ConvertBufferedImage.convertFromSingle(
            visualFiltered12, null, ImageUInt8.class);

    ImageUInt8 wynik = new ImageUInt8(mask.width, mask.height);

    //subtraction of images: wynik=mask-filtered;
    int min = 0;
    int max = 1;
    for (int i = 0; i < mask.height; i++) {
        // System.out.println("i=" + i);
        for (int j = 0; j < mask.width; j++) {
            // System.out.println("j=" + j);
            if (filtered.get(j, i) < min)
                min = filtered.get(j, i);
            if (filtered.get(j, i) > max)
                max = filtered.get(j, i);

            int filtInt = filtered.get(j, i);
            if (filtInt >= 1)
                filtInt = 1;
            else if (filtInt < 1)
                filtInt = 0;

            int maskInt = mask.get(j, i);
            if (maskInt >= 1)
                maskInt = 0;
            else if (maskInt < 1)
                maskInt = 1;

            int diff = maskInt - filtInt;
            if (diff == 1) {
                diff = 255;
                wynik.set(j, i, diff);
            } else if (diff == 0) {
                diff = 0;
                wynik.set(j, i, diff);
            } else {
                diff = 255;
                wynik.set(j, i, diff);

            }

        }
    }
    ShowImages.showWindow(wynik, "Wynik=Mask-Filtered");
    wynik = BinaryImageOps.erode4(wynik, 1, null);
    wynik = BinaryImageOps.dilate8(wynik, 1, null);
    wynik = BinaryImageOps.removePointNoise(wynik, wynik);
     UtilImageIO.saveImage(wynik, "C:/dev/zdjeciaTestowe/wynik.jpg");
    ShowImages.showWindow(wynik, "Wynik=Mask-Filtered After noise remove");

}

    private static ImageUInt8 binaryTreshold(String name, BufferedImage image,
            float hue, float saturation) throws IOException {
        MultiSpectral<ImageFloat32> input = ConvertBufferedImage
                .convertFromMulti(image, null, true, ImageFloat32.class);
        MultiSpectral<ImageFloat32> hsv = input.createSameShape();

        // Convert into HSV
        ColorHsv.rgbToHsv_F32(input, hsv);

        // Euclidean distance squared threshold for deciding which pixels are
        // members of the selected set
        float maxDist2 = 0.4f * 0.4f;

        // Extract hue and saturation bands which are independent of intensity
        ImageFloat32 H = hsv.getBand(0);
        ImageFloat32 S = hsv.getBand(1);

        // Adjust the relative importance of Hue and Saturation.
        // Hue has a range of 0 to 2*PI and Saturation from 0 to 1.
        float adjustUnits = (float) (Math.PI / 2.0);

        // step through each pixel and mark how close it is to the selected
        // color
        BufferedImage output = new BufferedImage(input.width, input.height,
                BufferedImage.TYPE_INT_RGB);
        for (int y = 0; y < hsv.height; y++) {
            for (int x = 0; x < hsv.width; x++) {
                // Hue is an angle in radians, so simple subtraction doesn't
                // work
                float dh = UtilAngle.dist(H.unsafe_get(x, y), hue);
                float ds = (S.unsafe_get(x, y) - saturation) * adjustUnits;

                // this distance measure is a bit naive, but good enough for to
                // demonstrate the concept
                float dist2 = dh * dh + ds * ds;
                if (dist2 <= maxDist2) {
                    System.out.println(image.getRGB(x, y));
                    output.setRGB(x, y, image.getRGB(x, y));
                }
            }
        }
        ImageFloat32 output1 = ConvertBufferedImage.convertFromSingle(output,
                null, ImageFloat32.class);
        ImageUInt8 binary = new ImageUInt8(input.width, input.height);

        double threshold = GThresholdImageOps.computeOtsu(output1, 0, 255);
        // Apply the threshold to create a binary image
        ThresholdImageOps.threshold(output1, binary, (float) threshold, true);

        return binary;
    }

    public static void main(String args[]) throws IOException {
        BufferedImage image = UtilImageIO
                .loadImage("C:/dev/zdjeciaTestowe/images.jpg");

        // Let the user select a color
        printClickedColor(image);
        // Display pre-selected colors
        showSelectedColor("Yellow", image, 1f, 1f);

    }
}

import java.awt.image.BufferedImage;
import boofcv.struct.image.ImageUInt8;

public class Fill {
    private static final int BLACK = -16777216;
    private static final int WHITE = -1;

    /**
     * @param input Buffered image
     * @return image with filled holes
     */
    public static BufferedImage fill(BufferedImage input) {
        int width = input.getWidth();
        int height = input.getHeight();
        BufferedImage output=new BufferedImage(width, height, input.getType());
        for (int i = 0; i < height; i++) {
            // System.out.println("i=" + i);
            for (int j = 0; j < width; j++) {
                // System.out.println("j=" + j);
                if (input.getRGB(j, i) == WHITE) {
                    output.setRGB(j, i, WHITE);
                } else if (isPreviusWhite(j, i, input)
                        && isAnotherWhiteInLine(j, i, input)) {
                    output.setRGB(j, i, WHITE);
                }
            }
        }
        return output;
    }

    private static boolean isPreviusWhite(int i, int i2, BufferedImage input) {
        boolean condition = false;
        while (1 < i2) {
            if (input.getRGB(i, i2) == WHITE)
                return true;
            i2--;
        }
        return condition;
    }

    private static boolean isAnotherWhiteInLine(int j, int i,
            BufferedImage input) {
        boolean condition = false;
        while (j < input.getWidth()) {
            if (input.getRGB(j, i) == WHITE)
                return true;
            j++;
        }
        return condition;
    }
}

I know how to extract a pictogram on a sign, and i have done it by subtracting the Mask from Filled Mask but have problem to obtain some processable result, because int the end I have an image in grayscale not a binary image (or as it is in boofCV ImageUInt8 ).

How do I properly do subtraction of two images in ImageUInt8 format so the result would be also ImageUInt8 ?

Today i have wrote futher part of that algorithm and now the problem which i want to ask about is more clarified. Here is added code (part from //subtraction of images: wynik=mask-filtered;) and 2 additional pictures as product of processing.

The problem is that last image after noise remove is solid black and without any information. How to correctly convert image to obtain processable content?? What i'm doing wrong?

我在上一张图片“ Wynik =经过噪声过滤后经过掩码过滤的滤镜”中找到了解决问题的方法,有一个象形图,但是灰度方面的贝特文像素差异很小,很难看到,因此添加了问题求解器:GrayImageOps.stretch(wynik, 125、125、255,wynik);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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