Robby Goz
Robby Goz

Reputation: 57

Adding Blur effect to BufferredImage in Java

I am writing a Image Processing project. Everything is done except blur effect. The common simple algorithm says :

  1. Take the 8 pixels surrounding your pixel and your pixel
  2. Average the RGB values of all 9 pixels and stick them in your current pixel location
  3. Repeat for every pixel

Below the I implemented to add blur effect

BufferedImage result = new BufferedImage(img.getWidth(),
            img.getHeight(), img.getType());

    int height = img.getHeight();
    int width = img.getWidth();

    for (int x = 0; x < width; x++)
        for (int y = 0; y < height; y++) {

            int pixel1 = (x == 0 || y == 0) ? 0 : img.getRGB(x - 1, y - 1);
            int pixel2 = (y == 0) ? 0 : img.getRGB(x, y - 1);
            int pixel3 = (y == 0 || x >= width-1) ? 0 : img.getRGB(x + 1, y - 1);
            int pixel4 = (x == 0) ? 0 :img.getRGB(x - 1, y);
            int pixel5 = img.getRGB(x, y);
            int pixel6 = (x >= height -1) ? 0 :img.getRGB(x + 1, y);
            int pixel7 = (x == 0 || y >= height -1) ? 0 :img.getRGB(x - 1, y + 1);
            int pixel8 = (y >= height -1) ? 0 :img.getRGB(x, y + 1);
            int pixel9 = (x >= width-1 || y >= height - 1) ? 0 :img.getRGB(x + 1, y + 1);

            int newPixel = pixel1 + pixel2 + pixel3 + pixel4 + pixel5
                    + pixel6 + pixel7 + pixel8 + pixel9;

            newPixel = newPixel/9;

            int redAmount = (newPixel >> 16) & 0xff;
            int greenAmount = (newPixel >> 8) & 0xff;
            int blueAmount = (newPixel >> 0) & 0xff;

            newPixel = (redAmount<< 16) | (greenAmount << 8) | blueAmount ;
            result.setRGB(x, y, newPixel);
        }

I got noisy image as result rather than blurred image. I think I am doing something wrong.

Thanks in advance. Note : Any external API is restricted like Kernal, AffineTransfomation or etc...

Upvotes: 2

Views: 1763

Answers (3)

FiReTiTi
FiReTiTi

Reputation: 5888

Here is version with just loops:

BufferedImage result = new BufferedImage(img.getWidth(), img.getHeight(), img.getType()) ;
final int H = img.getHeight() - 1 ;
final int W = img.getWidth() - 1 ;

for (int c=0 ; c < img.getRaster().getNumBands() ; c++) // for all the channels/bands
    for (int x=1 ; x < W ; x++) // For all the image
        for (int y=1; y < H ; y++)
            {
            int newPixel = 0 ;
            for (int i=-1 ; i <= 1 ; i++) // For the neighborhood
                for (int j=-1 ; j <= 1 ; j++)
                    newPixel += img.getRaster().getSample(x+i, y+j, c) ;
            newPixel = (int)(newPixel/9.0 + 0.5) ;
            result.getRaster().setSample(x, y, c, newPixel) ;
            }

Don't use getRGB, it's really slow and you have to deal with the conversions. getSample does everything for you.

Upvotes: 2

Robby Goz
Robby Goz

Reputation: 57

As I said written algorithms are proved. Just forgot to calculate the average for red, green and blue separately. Here is the answer.

BufferedImage result = new BufferedImage(img.getWidth(),
            img.getHeight(), img.getType());

    int height = img.getHeight();
    int width = img.getWidth();

    for (int x = 1; x < width-1; x++)
        for (int y = 1; y < height-1; y++) {

            int redAmount = 0;
            int greenAmount = 0;
            int blueAmount = 0;

            int pixel1 = img.getRGB(x - 1, y - 1);
            redAmount += (pixel1 >> 16) & 0xff;
            greenAmount += (pixel1 >> 8) & 0xff;
            blueAmount += (pixel1 >> 0) & 0xff;

            int pixel2 = img.getRGB(x, y - 1);
            redAmount += (pixel2 >> 16) & 0xff;
            greenAmount += (pixel2 >> 8) & 0xff;
            blueAmount += (pixel2 >> 0) & 0xff;

            int pixel3 = img.getRGB(x + 1, y - 1);
            redAmount += (pixel3 >> 16) & 0xff;
            greenAmount += (pixel3 >> 8) & 0xff;
            blueAmount += (pixel3 >> 0) & 0xff;

            int pixel4 = img.getRGB(x - 1, y);
            redAmount += (pixel4 >> 16) & 0xff;
            greenAmount += (pixel4 >> 8) & 0xff;
            blueAmount += (pixel4 >> 0) & 0xff;

            int pixel5 = img.getRGB(x, y);
            redAmount += (pixel5 >> 16) & 0xff;
            greenAmount += (pixel5 >> 8) & 0xff;
            blueAmount += (pixel5 >> 0) & 0xff;

            int pixel6 = img.getRGB(x + 1, y);
            redAmount += (pixel6 >> 16) & 0xff;
            greenAmount += (pixel6 >> 8) & 0xff;
            blueAmount += (pixel6 >> 0) & 0xff;

            int pixel7 = img.getRGB(x - 1, y + 1);
            redAmount += (pixel7 >> 16) & 0xff;
            greenAmount += (pixel7 >> 8) & 0xff;
            blueAmount += (pixel7 >> 0) & 0xff;

            int pixel8 = img.getRGB(x, y + 1);
            redAmount += (pixel8 >> 16) & 0xff;
            greenAmount += (pixel8 >> 8) & 0xff;
            blueAmount += (pixel8 >> 0) & 0xff;

            int pixel9 = img.getRGB(x + 1, y + 1);
            redAmount += (pixel9 >> 16) & 0xff;
            greenAmount += (pixel9 >> 8) & 0xff;
            blueAmount += (pixel9 >> 0) & 0xff;

            redAmount /= 9;
            greenAmount /= 9;
            blueAmount /= 9;

            int newPixel = (redAmount << 16) | (greenAmount << 8) | blueAmount;
            result.setRGB(x, y, newPixel);
        }

Upvotes: 0

J. Dow
J. Dow

Reputation: 563

You can not do calculations with the raw RGB integers like you do. This will certainly cause wrong results. (e.g. integer overflows) You have to take care of the each color component on their own.

Edit Just to give you an example: think about what it would mean to calculate the "average" of two pixels 00FFFF and 0000CC?.

What you actually want as result is something like 007FE5, but calculating with the raw integers will cause the "blue" part to be carried over to the yellow part resulting in 008065.

Upvotes: 1

Related Questions