简体   繁体   中英

Java BufferedImage map colors

I am trying to write a program that takes bufferedImage as an input and maps all black-close colors (R<32, G<32, B<32) to black and the others to white for the purpose of OCR (the OCR engine takes BufferedImage as an input). Is there a way to do it without iterating over pixels? Namely, I tried

public static BufferedImage BlackAndWhite(BufferedImage image) {

    ColorModel model = new BlackWhiteColorModel(DataBuffer.TYPE_INT);
    WritableRaster raster = image.getRaster();

    BufferedImage newImage = new BufferedImage(model, raster, false, null);

    return newImage;
}

Where BlackWhiteColorModel is defined as

public class BlackWhiteColorModel extends ColorModel {

public BlackWhiteColorModel(int bits) {
    super(bits);
}

@Override
public int getRed(int pixel) {
    int[] rgb = getRgb(pixel);

    if (rgb[0] < 32 && rgb[1] < 32 && rgb[2] < 32) {
        return 0;
    } else {
        return 255;
    }
}

@Override
public int getGreen(int pixel) {
    int[] rgb = getRgb(pixel);

    if (rgb[0] < 32 && rgb[1] < 32 && rgb[2] < 32) {
        return 0;
    } else {
        return 255;
    }
}

@Override
public int getBlue(int pixel) {
    int[] rgb = getRgb(pixel);

    if (rgb[0] < 32 && rgb[1] < 32 && rgb[2] < 32) {
        return 0;
    } else {
        return 255;
    }
}

@Override
public int getAlpha(int pixel) {
    return pixel;
}

private int[] getRgb(int pixel) {
    int r = (pixel) & 0xFF;
    int g = (pixel >> 8) & 0xFF;
    int b = (pixel >> 16) & 0xFF;
    int a = (pixel >> 24) & 0xFF;

    return new int[]{r, g, b, a};
}



}

However, I end up with isCompatibleRasterException. Could anyone give me some advice?

(1) You did not implement one of the methods of the contract: isCompatibleRaster . Here is an overly optimistic implementation that runs fine given your problem statement:

@Override
public boolean isCompatibleRaster(Raster raster) {
    return true;
}

(2) getRed , getGreen and getBlue have the same code. Here is a complete program that factors out the common code into a new method called getColor . This program runs without error:

import java.awt.*;
import java.awt.image.*;

public class BlackWhiteColorModel extends ColorModel {
    public static void main(String[] args) {
        BufferedImage bufferedImage = new BufferedImage(200,200,BufferedImage.TYPE_INT_RGB);
         Graphics g = bufferedImage.getGraphics();
         g.drawString("Hello, World", 20,20);
        blackAndWhite(bufferedImage);
    }

    public static BufferedImage blackAndWhite(BufferedImage image) {
        ColorModel model = new BlackWhiteColorModel(DataBuffer.TYPE_INT);
        WritableRaster raster = image.getRaster();

        BufferedImage newImage = new BufferedImage(model, raster, false, null);

        return newImage;
    }

    public BlackWhiteColorModel(int bits) {
        super(bits);
    }

    private int getColor(int pixel) {
        int[] rgb = getRgb(pixel);

        if (rgb[0] < 32 && rgb[1] < 32 && rgb[2] < 32) {
            return 0;
        } else {
            return 255;
        }
    }

    @Override
    public int getRed(int pixel) {
        return getColor(pixel);
    }

    @Override
    public int getGreen(int pixel) {
        return getColor(pixel);
    }

    @Override
    public int getBlue(int pixel) {
        return getColor(pixel);
    }

    @Override
    public int getAlpha(int pixel) {
        return pixel;
    }

    @Override
    public boolean isCompatibleRaster(Raster raster) {
        return true;
    }

    private int[] getRgb(int pixel) {
        int r = (pixel) & 0xFF;
        int g = (pixel >> 8) & 0xFF;
        int b = (pixel >> 16) & 0xFF;
        int a = (pixel >> 24) & 0xFF;

        return new int[]{r, g, b, a};
    }
}

What you want is a threshold operation eg: 在此处输入图片说明

I guess you don't want to iterate over the pixels due to performance issues. If that is true i would highly recommend you to use OpenCV just like this:

BufferedImage image = null; //use your image here
//Convert image to OpenCv Mat
byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3);
mat.put(0, 0, pixels);

//do something with the Mat e.g:
Imgproc.threshold(...); 

//Convert back
mat.get(0, 0, pixels);

The performance especially if you do more image processing is at least 10x faster

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