Tuesday 28 March 2017

ImageFilter - Java Tutorials ( Page 2 of 2 )

Contrast.java
The Contrast filter is very similar to Grayscale, except its override of filterRGB( ) is slightly more complicated. The algorithm it uses for contrast enhancement takes the red, green, and blue values separately and boosts them by 1.2 times if they are already brighter than 128. If they are below 128, then they are divided by 1.2. The boosted values are properly clamped at 255 by the multclamp( ) method.

  import java.applet.*;
  import java.awt.*;
  import java.awt.image.*;

  public class Contrast extends RGBImageFilter implements 
                                           PlugInFilter {

    public Image filter(Applet a, Image in) {
      return a.createImage(new FilteredImageSource(in.getSource(), 
                           this));
    }

    private int multclamp(int in, double factor) {
      in = (int) (in * factor);
      return in > 255 ? 255 : in;
    }

    double gain = 1.2;
    private int cont(int in) {
      return (in < 128) ? (int)(in/gain) : multclamp(in, gain);
    }

    public int filterRGB(int x, int y, int rgb) {
      int r = cont((rgb >> 16) & 0xff);
      int g = cont((rgb >> 8) & 0xff);
      int b = cont(rgb & 0xff);
      return (0xff000000 | r << 16 | g << 8 | b);
    }
  }

Convolver.java
The abstract class Convolver handles the basics of a convolution filter by implementing the ImageConsumer interface to move the source pixels into an array called imgpixels. It also creates a second array called newimgpixels for the filtered data. Convolution filters sample a small rectangle of pixels around each pixel in an image, called the convolution kernel. This area, 3×3 pixels in this demo, is used to decide how to change the center pixel in the area. The two concrete subclasses, shown in the next section, simply implement the convolve( ) method, using imgpixels for source data and newimgpixels to store the result.

The reason that the filter can’t modify the imgpixels array in place is that the next pixel on a scan line would try to use the original value for the previous pixel, which would have just been filtered away.

  import java.applet.*;
  import java.awt.*;
  import java.awt.image.*;

  abstract class Convolver implements ImageConsumer, PlugInFilter {
    int width, height;
    int imgpixels[], newimgpixels[];

    abstract void convolve(); // filter goes here...

    public Image filter(Applet a, Image in) {
      in.getSource().startProduction(this);
      waitForImage();
      newimgpixels = new int[width*height];

      try {
        convolve();
      } catch (Exception e) {
        System.out.println("Convolver failed: " + e);
        e.printStackTrace();
      }

      return a.createImage(
        new MemoryImageSource(width, height, newimgpixels, 0, 
                              width));
    }

    synchronized void waitForImage() {
      try { wait(); } catch (Exception e) { };
    }

    public void setProperties(java.util.Hashtable dummy) { }
    public void setColorModel(ColorModel dummy) { }
    public void setHints(int dummy) { }

    public synchronized void imageComplete(int dummy) {
      notifyAll();
    }

    public void setDimensions(int x, int y) {
      width = x;
      height = y;
      imgpixels = new int[x*y];
    }

    public void setPixels(int x1, int y1, int w, int h,
      ColorModel model, byte pixels[], int off, int scansize) {
      int pix, x, y, x2, y2, sx, sy;

      x2 = x1+w;
      y2 = y1+h;
      sy = off;
      for(y=y1; y<y2; y++) {
        sx = sy;
        for(x=x1; x<x2; x++) {
          pix = model.getRGB(pixels[sx++]);
          if((pix & 0xff000000) == 0)
              pix = 0x00ffffff;
          imgpixels[y*width+x] = pix;
        }
        sy += scansize;
      }
    }

    public void setPixels(int x1, int y1, int w, int h,
      ColorModel model, int pixels[], int off, int scansize) {
      int pix, x, y, x2, y2, sx, sy;

      x2 = x1+w;
      y2 = y1+h;
      sy = off;
      for(y=y1; y<y2; y++) {
        sx = sy;
        for(x=x1; x<x2; x++) {
          pix = model.getRGB(pixels[sx++]);
          if((pix & 0xff000000) == 0)
              pix = 0x00ffffff;
          imgpixels[y*width+x] = pix;
        }
        sy += scansize;
      }
    }
  }

Blur.java
The Blur filter is a subclass of Convolver and simply runs through every pixel in the source image array, imgpixels, and computes the average of the 3×3 box surrounding it. The corresponding output pixel in newimgpixels is that average value.

  public class Blur extends Convolver {
    public void convolve() {
      for(int y=1; y<height-1; y++) {
        for(int x=1; x<width-1; x++) {
          int rs = 0;
          int gs = 0;
          int bs = 0;

          for(int k=-1; k<=1; k++) {
            for(int j=-1; j<=1; j++) {
              int rgb = imgpixels[(y+k)*width+x+j];
              int r = (rgb >> 16) & 0xff;
              int g = (rgb >> 8) & 0xff;
              int b = rgb & 0xff;
              rs += r;
              gs += g;
              bs += b;
            }
          }

          rs /= 9;
          gs /= 9;
          bs /= 9;

          newimgpixels[y*width+x] = (0xff000000 |
                                     rs << 16 | gs << 8 | bs);
        }
      }
    }
  }

Sharpen.java
The Sharpen filter is also a subclass of Convolver and is (more or less) the inverse of Blur. It runs through every pixel in the source image array, imgpixels, and computes the average of the 3×3 box surrounding it, not counting the center. The corresponding output pixel in newimgpixels has the difference between the center pixel and the surrounding average added to it. This basically says that if a pixel is 30 brighter than its surroundings, make it another 30 brighter. If, however, it is 10 darker, then make it another 10 darker. This tends to accentuate edges while leaving smooth areas unchanged.

  public class Sharpen extends Convolver {

    private final int clamp(int c) {
      return (c > 255 ? 255 : (c < 0 ? 0 : c));
    }

    public void convolve() {
      int r0=0, g0=0, b0=0;
      for(int y=1; y<height-1; y++) {
        for(int x=1; x<width-1; x++) {
          int rs = 0;
          int gs = 0;
          int bs = 0;

          for(int k=-1; k<=1; k++) {
            for(int j=-1; j<=1; j++) {
              int rgb = imgpixels[(y+k)*width+x+j];
              int r = (rgb >> 16) & 0xff;
              int g = (rgb >> 8) & 0xff;
              int b = rgb & 0xff;
              if (j == 0 && k == 0) {
                r0 = r;
                g0 = g;
                b0 = b;
              } else {
                rs += r;
                gs += g;
                bs += b;
              }
            }
          }

          rs >>= 3;
          gs >>= 3;
          bs >>= 3;
          newimgpixels[y*width+x] = (0xff000000 |
                                  clamp(r0+r0-rs) << 16 |
                                  clamp(g0+g0-gs) << 8 |
                                  clamp(b0+b0-bs));
        }
      }
    }
  }

No comments:

Post a Comment