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.