CoXier - 4 months ago 23

Java Question

Recently I am preparing for

`Low Poly`

My first thing is to pick up some points of the input image.I want to try

`Sobel`

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();

}

}

Now I get:

Answer

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.