0
votes

The code below is an image processing routine. The x and y represent the coordinated of all of the pixels that make up the image. The basics are as follows:

  • x, y - coordinates of each pixel.
  • imgH, imgW - height and width in pixels of the image
  • r, g, b - The red, green, and blue levels of each pixel

The code uses a double for loop to do something to each pixel in the image. What I want to do inside this for loops is for each pixel, I want to average the r,g,b values of the 8 surrounding pixels, and make that average the value of the center pixel. This will create the effect of blurring the image. Could anybody help me with this?

    protected void proc_17() {
    info = "";
    for (int y = 0; y < imgH; y++) {
        for (int x = 0; x < imgW; x++) {
            int xNext = (x+1) % imgW;
            int yNext = (y+1) % imgH;
            float r = (imgOld.getR(xNext, yNext) + imgOld.getR(xNext, yNext)) / 8;
            float g = (imgOld.getG(xNext, yNext) + imgOld.getG(xNext, yNext)) / 8;
            float b = (imgOld.getB(xNext, yNext) + imgOld.getB(xNext, yNext)) / 8;
            imgNew.setR(x, y, r);
            imgNew.setG(x, y, g);
            imgNew.setB(x, y, b);
        }
    }
}
1
you are going to need to loop twice, once to calculate new values and once to apply them. otherwise the calculation will be performed using some pixels that have already been blurrednhouser9
Why not replace (imgOld.getR(xNext, yNext) + imgOld.getR(xNext, yNext)) / 8; with imgOld.getR(xNext, yNext) / 4;?CraigR8806
Adding the division by 4 just divides the RGB values of each pixel making them lower, which in turn makes the image darker since the values are uniformly being reduced.Teej
Yes, but you are adding the value returned from this call imgOld.getR(xNext, yNext) to itself because you make the same exact call again. Then you divide that by 8. Essentially, what you are doing is this: (2 * imgOld.getR(xNext, yNext)) / 8;CraigR8806

1 Answers

0
votes

smoothing and or averaging is usually done with convolution with symmetrical nonzero matrix with only nonnegative elements (weights) with sum equal to one. usual 4-neighbor smoothing matrix looks like this:

0.0 0.1 0.0
0.1 0.6 0.1
0.0 0.1 0.0

8-neighbor:

0.05 0.10 0.05
0.10 0.20 0.10
0.05 0.10 0.05
  • if Weights are summed to one then result's magnitude will be the same as inputs.
  • symmetrical matrix will not shift result ...
  • resolution of matrix will give you smooth distance

Now you can do this also in-place so no additional image storage is needed by using:

0.50 0.25
0.25 0.00

and then:

0.00 0.25
0.25 0.50

As you can see matrices are not centered nor symmetrical so result is shifted but the shifts are opposing and negates each-other. The code would look like this:

for (y=0;y<ys-1;y++)
 for (x=0;x<xs-1;x++)
  pixel[y][x]=(2*pixel[y][x]+pixel[y+1][x]+pixel[y][x+1])/4;

for (y=ys-1;y>0;y--)
 for (x=xs-1;x>0;x--)
  pixel[y][x]=(2*pixel[y][x]+pixel[y-1][x]+pixel[y][x-1])/4;

You have to handle r,g,b of each pixel separately of coarse. The xs,ys is image resolution and pixel[][] is direct pixel access of image. Also you have to handle the border pixels so either smooth them with different matrix or shrink the result image by one pixel from each side (depends on what you need). The weights results in multiplication by 2 and division by 4 which can be done by bit-shift operation for speed (in case you compiler does not do it on its own)

To increase strength of smooth you can loop all this few times.

for (i=0;i<smooth_strength;i++)
 {
 for (y=0;y<ys-1;y++)
  for (x=0;x<xs-1;x++)
   pixel[y][x]=(2*pixel[y][x]+pixel[y+1][x]+pixel[y][x+1])/4;

 for (y=ys-1;y>0;y--)
  for (x=xs-1;x>0;x--)
   pixel[y][x]=(2*pixel[y][x]+pixel[y-1][x]+pixel[y][x-1])/4;
 }

For more ideas take look at: