如何使用boofcv提取象形文字?

How to extract pictogram using boofcv?

我在将象形图提取为某种可进一步处理的格式时遇到了问题,因为现在我遇到了这样的问题:

当前解决方案的一部分取自 BoofCV ImageTresholding 示例。我对此解决方案的代码如下:

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

我知道如何在标志上提取象形图,我已经通过从填充蒙版中减去蒙版来完成,但是在获得一些可处理的结果时遇到问题, 因为最后我有一个灰度图像而不是二进制图像(或者在 boofCV ImageUInt8 中)。

如何正确地减去 ImageUInt8 格式的两个图像,使结果也为 ImageUInt8

今天我已经写了那个算法的更多部分,现在我想问的问题更清楚了。这里添加了代码(部分来自 //subtraction of images: wynik=mask-filtered;)和 2 张附加图片作为处理的产物。

问题是去噪后的最后一张图片是纯黑色的,没有任何信息。如何正确转换图像以获得可处理的内容?? 我做错了什么?

我在最后一张图片上找到了我的问题的解决方案 "Wynik=Mask-Filtered After noise Remove" 有一个象形图,但是灰度中的差异 beetwen piksels 太低以至于很难看到所以问题解决者正在添加: GrayImageOps.stretch(维尼克, 125, 125, 255, 维尼克);