java中的Otsu阈值

时间:2015-12-18 14:57:26

标签: java image-processing

我正在尝试使用tesseract对数字执行ocr,并发现当我在photoshop中使用阈值滤镜来预处理图像时,我得到了一些非常好的结果。我试图以编程方式复制这个并找到以下有用的教程:http://developer.bostjan-cigan.com/java-image-binarization/当我运行代码时,我只是得到一个完全黑色的图像。有谁知道如何解决这个问题?

package otsubinarize;

import java.awt.Color;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;

public class OtsuBinarize {

    private static BufferedImage original, grayscale, binarized;

    public static void main(String[] args) throws IOException {

        File original_f = new File("/Users/unknown1/Desktop/t1.png");
        String output_f = "/Users/unknown1/Desktop/t1";
        original = ImageIO.read(original_f);
        grayscale = toGray(original);
        binarized = binarize(grayscale);
        writeImage(output_f);         

    }

    private static void writeImage(String output) throws IOException {
        File file = new File(output+".jpg");
        ImageIO.write(binarized, "jpg", file);
    }

    // Return histogram of grayscale image
    public static int[] imageHistogram(BufferedImage input) {

        int[] histogram = new int[100];

        for(int i=0; i<histogram.length; i++) histogram[i] = 0;

        for(int i=0; i<input.getWidth(); i++) {
            for(int j=0; j<input.getHeight(); j++) {
                int red = new Color(input.getRGB (i, j)).getRed();
                histogram[red]++;
            }
        }

        return histogram;

    }

    // The luminance method
    private static BufferedImage toGray(BufferedImage original) {

        int alpha, red, green, blue;
        int newPixel;

        BufferedImage lum = new BufferedImage(original.getWidth(), original.getHeight(), original.getType());

        for(int i=0; i<original.getWidth(); i++) {
            for(int j=0; j<original.getHeight(); j++) {

                // Get pixels by R, G, B
                alpha = new Color(original.getRGB(i, j)).getAlpha();
                red = new Color(original.getRGB(i, j)).getRed();
                green = new Color(original.getRGB(i, j)).getGreen();
                blue = new Color(original.getRGB(i, j)).getBlue();

                red = (int) (0.21 * red + 0.71 * green + 0.07 * blue);
                // Return back to original format
                newPixel = colorToRGB(alpha, red, red, red);

                // Write pixels into image
                lum.setRGB(i, j, newPixel);

            }
        }

        return lum;

    }

    // Get binary treshold using Otsu's method
    private static int otsuTreshold(BufferedImage original) {

        int[] histogram = imageHistogram(original);
        int total = original.getHeight() * original.getWidth();

        float sum = 0;
        for(int i=0; i<100; i++) sum += i * histogram[i];

        float sumB = 0;
        int wB = 0;
        int wF = 0;

        float varMax = 0;
        int threshold = 0;

        for(int i=0 ; i<100 ; i++) {
            wB += histogram[i];
            if(wB == 0) continue;
            wF = total - wB;

            if(wF == 0) break;

            sumB += (float) (i * histogram[i]);
            float mB = sumB / wB;
            float mF = (sum - sumB) / wF;

            float varBetween = (float) wB * (float) wF * (mB - mF) * (mB - mF);

            if(varBetween > varMax) {
                varMax = varBetween;
                threshold = i;
            }
        }

        return threshold;

    }

    private static BufferedImage binarize(BufferedImage original) {

        int red;
        int newPixel;

        int threshold = otsuTreshold(original);

        BufferedImage binarized = new BufferedImage(original.getWidth(), original.getHeight(), original.getType());

        for(int i=0; i<original.getWidth(); i++) {
            for(int j=0; j<original.getHeight(); j++) {

                // Get pixels
                red = new Color(original.getRGB(i, j)).getRed();
                int alpha = new Color(original.getRGB(i, j)).getAlpha();
                if(red > threshold) {
                    newPixel = 100;
                }
                else {
                    newPixel = 0;
                }
                newPixel = colorToRGB(alpha, newPixel, newPixel, newPixel);
                binarized.setRGB(i, j, newPixel); 

            }
        }

        return binarized;

    }

    // Convert R, G, B, Alpha to standard 8 bit
    private static int colorToRGB(int alpha, int red, int green, int blue) {

        int newPixel = 0;
        newPixel += alpha;
        newPixel = newPixel << 8;
        newPixel += red; newPixel = newPixel << 8;
        newPixel += green; newPixel = newPixel << 8;
        newPixel += blue;

        return newPixel;

    }

}

1 个答案:

答案 0 :(得分:1)

他们是不同的问题:

  • 如果对方法toGray中的权重系数求和,您将看到总和不是1.查看CIE页面上的系数(精度更高,总和为1)。
  • 在同一方法中,您可以创建新的灰度图像,但使用与原始图像相同的编码,即原始图像,即彩色图像。类型应为TYPE_BYTE_GRAY
  • 在方法直方图中,将实例化为100个元素。您使用通常以256灰度级编码的灰度图像,但也可以是65536。
  • 我没有相同的方法来计算Otsu阈值。看一下ImageJ源代码,你将有一个很好的方法。

总体评论:您使用getRGB来访问像素值,这是一种糟糕的方法。使用getRaster().getSample代替(更快更容易),或者最快的方法是访问DataBuffer