Recently I am preparing for Low Poly
like this:
My first thing is to pick up some points of the input image.I want to try Sobel
for detection and I have read soble article.
Now I meet problem where I don't know how to implement sobel filter.Folowing is my try:
try {
mImage = ImageIO.read(new File("D:\\Documents\\Pictures\\engine.png"));
} catch (IOException e) {
e.printStackTrace();
}
mWidth = mImage.getWidth();
mHeight = mImage.getHeight();
mNewImage = new BufferedImage(mWidth, mHeight, mImage.getType());
mGrayData = new int[mWidth * mHeight];
// get pixel data from image
for (int i = 0; i < mHeight; i++) {
for (int j = 0; j < mWidth; j++) {
int rgb = mImage.getRGB(j, i);
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = rgb & 0xff;
int grayLevel = (r + g + b) / 3;
mGrayData[i * mWidth + j] = grayLevel;
}
}
private int[] getGradient() {
int[] gradient = new int[mWidth * mHeight];
for (int x=1;x<mWidth-1;x++){
for (int y=1;y<mHeight-1;y++){
int grayX = getGrayPoint(x+1,y-1)+2*getGrayPoint(x+1,y)+getGrayPoint(x+1,y+1)-
(getGrayPoint(x-1,y-1)+2*getGrayPoint(x-1,y)+getGrayPoint(x-1,y+1));
int grayY = (getGrayPoint(x-1, y+1) + 2*getGrayPoint(x,y+1)+getGrayPoint(x+1,y+1))-
(getGrayPoint(x-1,y-1) + 2*getGrayPoint(x,y-1) + getGrayPoint(x+1,y-1));
gradient[x+y*mWidth] = (int) Math.sqrt(grayX*grayX+grayY*grayY);
}
}
return gradient;
}
private void createImage() {
int[] gradient = getGradient();
for (int y = 1; y < mHeight - 1; ++y)
for (int x = 1; x < mWidth - 1; ++x)
mNewImage.setRGB(x,y,gradient[y * mWidth + x]);
File file = new File("D:\\Documents\\Pictures\\engine3.png");
if (!file.exists()) {
file.getParentFile().mkdir();
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
ImageIO.write(mNewImage, "png", file);
} catch (IOException e) {
e.printStackTrace();
}
}
It's so strange that the color is a little blue
Now I get:
why is it so black?
You set the color here:
mNewImage.setRGB(x,y,gradient[y * mWidth + x]);
You're not doing anything to ensure that the values in the red, green and blue channels are the same.
The 32 bits of the integer are used to pack 4 8-bit channels, representing alpha, red, green and blue.
0x01234567 = overall color
01 = alpha
23 = red
45 = green
67 = blue
You are only setting a single value; this looks like it doesn't fall outside the range 0 to 255, so you are effectively only setting bits in the blue channel. (Presumably you're also using an RGB color model, rather than ARGB, which is why the pixels aren't fully transparent).
Set the three channels to the same value (and clamp the value to be between 0-255, so you don't accidentally set bits in the other channels):
int gray = Math.max(0, Math.min(gradient[...], 255);
int color = (0xff << 24) | (gray << 16) | (gray << 8) | (gray);
// Alpha Red Green Blue
Note that you may also want to scale your gradient values so that the point with maximum gradient is assigned the gray value 255:
int maxGradient = 0;
for (int g : gradient) {
maxGradient = Math.max(maxGradient, g);
}
then:
int gray = Math.max(0, gradient) * 255 / maxGradient;
(You no longer need to clamp it to be at most 255).
Also, you might want to make your gradient array float[]
or double[]
(and use the same element type for maxGradient
), so that you get less quantized output.