Taylor
Taylor

Reputation: 51

Blur an image using 3x3 Gaussian kernel?

I want to create a method to blur a 24 bit image using 3x3 Gaussian kernel.

I was given the following things.

The 3x3 Gaussian kernel:

https://i.sstatic.net/YAEQR.png

A is the original image and B is the resulting image.

B(i,j) =
1/16 * A(i-1,j-1) +1/8 * A(i,j-1) +1/16 * A(i+1,j-1) +1/8 * A(i-1,j) +1/4 * A(i,j) +1/8 *A(i+1,j) +1/16 * A(i-1,j+1) +1/8 * A(i,j+1) +1/16 * A(i+1,j+1)  

The method:

public static BufferedImage gaussianBlur(Image img)

where img is a reference variable of an input image.
The returned value is an address of an object of the resulting image.

Should I divided the image into 9 parts to implement this method?

Upvotes: 5

Views: 46895

Answers (2)

A_P
A_P

Reputation: 354

Don't divide it into parts. what if you have big image. what you should do is to first write a function that checks if the filter is within the image bounds. in C it would be some thing like this:

int filterWithinImage(Matrix m1, Matrix m2, int i, int j) {
  int b; //min number of pixels that the center of the filter needs to be
         // away from any border of the image to be inbounds


  /***********************odd size filter only*************************/
  //when filter size is odd there is well defined convenient center
  // of the filter
  if (isOdd(m2.height) && isOdd(m2.width)) {
    //to check the bounds subtract 1 from the width and divide by 2
    b = (m2.width - 1) / 2;
    //look at the left border
    if ((j - b)<0) return 0;
    //top border
    if ((i - b)<0) return 0;
    //right border
    if ((j + b)>(m1.width-1)) return 0;
    //bottom border
    if ((i + b)>(m1.height -1)) return 0;
  }
  return 1;
}

than write separate function for calculating the intensities:

double calculateValue(Matrix m1,Matrix m2,int imagei, int imagej) {
  double out = 0;//return value
  int i, j, fli, flj; //for iterating over the filter
  int b = (m2.height -1) / 2;//max number that we add to the center coordinates
                            //to get to the edge of the filter
  fli = 0; flj = 0;
  for(i = imagei - b; i < imagei + b +1; i++) {
    for(j = imagej - b; j < imagej + b +1; j++) {
          //    if (i == 599)
      //printf("calc func image i: %d,  image j %d, b %d,  filter i %d,  filter j %d\n",
      // i,j,b,fli,flj);      
      out += m1.map[i][j] * m2.map[fli][flj++];
    }
    fli++;
    flj=0;
  }
  return out;
}

then just write applyFilter m2 is the filter that you need to rotate 180 degrees. Matrix applyFilter(Matrix m1, Matrix m2) { int x,y; //rotate filter first Matrix rotFilter = createMatrix(m2.height,m2.width); for (x = 0; x < m2.height; x++) for (y = 0; y < m2.width; y++) { rotFilter.map[y][x] = m2.map[m2.height-y-1][m2.width-x-1]; }

  Matrix mOut = createMatrix(m1.height, m1.width);
  int i,j;
  for (i = 0; i < m1.height; i++) {
    for (j = 0; j < m1.width; j++) {
      if (!filterWithinImage(m1,rotFilter,i,j)) { //filter is out of bounds
    mOut.map[i][j] = 0;
      }
      else {
    mOut.map[i][j] = calculateValue(m1,rotFilter,i,j);
      }
    }
  }
  return mOut;
}

this is a general approach that would have to modified to fit java data structures, but the algorithms are the same.

Upvotes: 0

herohuyongtao
herohuyongtao

Reputation: 50667

You don't need to divide it to 9 parts. At least, I don't see a good reason to do this.

But you'd better be careful during this process, remember to copy image data to somewhere and always use this data for computation for new image, avoid to use new image data to compute new image.


Also, I don't understand why you need to write your own function to Gaussian blur a image. This can be easily be done as follows:

float[] matrix = {
    1/16f, 1/8f, 1/16f, 
    1/8f, 1/4f, 1/8f, 
    1/16f, 1/8f, 1/16f, 
};

BufferedImageOp op = new ConvolveOp( new Kernel(3, 3, matrix) );
blurredImage = op.filter(sourceImage, destImage);

Upvotes: 12

Related Questions