CoXier - 1 year ago 102
Java Question

# Sobel filter is strange

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:

## First -> Get gray data from input image

`````` try {
} 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;
}
}
``````

## Then -> Calculate gradient of every point

``````  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));
}
}
}
``````

## Last -> Create new image with above gradient

`````` private void createImage() {

for (int y = 1; y < mHeight - 1; ++y)
for (int x = 1; x < mWidth - 1; ++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();
}
}
``````

## What I got

It's so strange that the color is a little blue

## Edit 1:

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) {
``````int gray = Math.max(0, gradient) * 255 / maxGradient;
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.