Search code examples
javaimage-processingbufferedimage

Laplacian filter produces weird results (Java)


I'm trying to apply the

[-1][-1][-1]
[-1][8][-1]
[-1][-1][-1]

3*3 Laplacian filter to the grayscale version of the famous photo(png extension) here.

enter image description here

I am mainly using the BufferedImage class for processing images. Here is the Laplacian Filter Method.

private BufferedImage measureContrast(BufferedImage image) {
        BufferedImage grayScale = createGrayscaleImage(image);
        BufferedImage copy = copyImage(grayScale);

        int width = image.getWidth();
        int height = image.getHeight();
        int sum=0;
        int a;
         //3*3 Laplacian filter (-1,-1,-1), (-1,8,-1), (-1,-1,-1)
        for(int y=1;y<height-1;y++)
            for(int x=1;x<width-1;x++) {
                sum = (-1*(grayScale.getRGB(x-1, y-1)&0xff)) + (-1*(grayScale.getRGB(x, y-1)&0xff)) + (-1*(grayScale.getRGB(x+1, y-1)&0xff))
                        + (-1*(grayScale.getRGB(x-1, y)&0xff)) + (8*(grayScale.getRGB(x,y)&0xff)) + (-1*(grayScale.getRGB(x+1, y)&0xff)) +
                        (-1*(grayScale.getRGB(x-1, y+1)&0xff)) + (-1*(grayScale.getRGB(x, y+1)&0xff)) + (-1*(grayScale.getRGB(x+1, y+1)&0xff));             
                a = ((grayScale.getRGB(x, y)>>24)&0xff);
                copy.setRGB(x, y, ((a<<24)|(sum<<16)|(sum<<8)|(sum)));
            }
return copy;

If I run that code, the result turns out like this

enter image description here

Which is obviously wrong. Suddenly weird, thick lines appear in the image.

I can assure that the grayscaled version is correct, since when I just run the following code before applying the filter, the output gives a perfect gray scale image.

private BufferedImage measureContrast(BufferedImage image) {
        BufferedImage grayScale = createGrayscaleImage(image);
        BufferedImage copy = copyImage(grayScale); /*rest of the code is commented*/
return copy;

enter image description here

I've been trying to find the issue for a couple of hours, but I don't think there's anything wrong to the code... Any insight would be very appreciated. Thanks in advance!


For copying the image, I used the following code. I borrowed it from a chosen answer in stack overflow, so I don't think it would be wrong though.

BufferedImage copyImage(BufferedImage bi) {
         ColorModel cm = bi.getColorModel();
         boolean isAlphaPremultiplied = cm.isAlphaPremultiplied();
         WritableRaster raster = bi.copyData(null);
         return new BufferedImage(cm, raster, isAlphaPremultiplied, null);
    }

Also, the result image is printed like this

BufferedImage Contrast = measureContrast(image);
//write image
try {
    ImageIO.write(Contrast, "png", new File(outputPath));
    System.out.println("Printing complete");
}catch(IOException e) {
    System.out.println("File Printing Error: "+e);
}

Just in case, here is the grayscale image producing method.

private BufferedImage createGrayscaleImage(BufferedImage image) {
        int width = image.getWidth();
        int height = image.getHeight();
        BufferedImage copy = copyImage(image);

        int p=0, a=0, r=0, g=0, b=0, avg=0;
        for(int y=0;y<height;y++)
            for(int x=0;x<width;x++) {
                p=image.getRGB(x, y);
                a=(p>>24)&0xff;
                r=(p>>16)&0xff;
                g=(p>>8)&0xff;
                b=p&0xff;
                avg = (r+g+b)/3;
                p = (a<<24) | (avg<<16) | (avg<<8) | avg;
                copy.setRGB(x, y, p);
            }
        return copy;
    }

Solution

  • private BufferedImage measureContrast(BufferedImage image) {
            BufferedImage grayScale = createGrayscaleImage(image);
            BufferedImage copy = copyImage(grayScale);
    
            int width = image.getWidth();
            int height = image.getHeight();
            int sum=0;
            int a;
             //3*3 Laplacian filter (-1,-1,-1), (-1,8,-1), (-1,-1,-1)
            for(int y=1;y<height-1;y++)
                for(int x=1;x<width-1;x++) {
                    sum = (-1*(grayScale.getRGB(x-1, y-1)&0xff)) + (-1*(grayScale.getRGB(x, y-1)&0xff)) + (-1*(grayScale.getRGB(x+1, y-1)&0xff))
                            + (-1*(grayScale.getRGB(x-1, y)&0xff)) + (8*(grayScale.getRGB(x,y)&0xff)) + (-1*(grayScale.getRGB(x+1, y)&0xff)) +
                            (-1*(grayScale.getRGB(x-1, y+1)&0xff)) + (-1*(grayScale.getRGB(x, y+1)&0xff)) + (-1*(grayScale.getRGB(x+1, y+1)&0xff));             
                    a = ((grayScale.getRGB(x, y)>>24)&0xff);
                    copy.setRGB(x, y, ((a<<24)|(sum<<16)|(sum<<8)|(sum)));
                }
    return copy;
    

    This method was wrong. I should've considered when sum was a negative value. So I added sum = (sum>0)?sum:0; inside the nested for loop to make sure the pixel value is 0 in those situations.