Package org.jwildfire.transform

Source Code of org.jwildfire.transform.ConvolveTransformer$KernelTypeEditor

/*
  JWildfire - an image and animation processor written in Java
  Copyright (C) 1995-2011 Andreas Maschke

  This is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser
  General Public License as published by the Free Software Foundation; either version 2.1 of the
  License, or (at your option) any later version.
  This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
  even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public License along with this software;
  if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
  02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jwildfire.transform;

import org.jwildfire.base.Property;
import org.jwildfire.base.PropertyMax;
import org.jwildfire.base.PropertyMin;
import org.jwildfire.base.Tools;
import org.jwildfire.image.Pixel;
import org.jwildfire.image.SimpleImage;
import org.jwildfire.image.WFImage;

import com.l2fprod.common.beans.editor.ComboBoxPropertyEditor;

public class ConvolveTransformer extends Mesh2DTransformer {
  public enum EdgeMode {
    MIRROR, WRAP, BLACK
  }

  public enum ColorMode {
    COLOR, GREY
  }

  public enum KernelType {
    EDGE_DETECT_3x3, EMBOSS_3x3, LAPLACE_3x3, SHARPEN_3x3, SHARPEN_LESS_3x3, SOBEL_3X3,
    GAUSSIAN_BLUR_5x5, GAUSSIAN_BLUR_3x3
  }

  public enum KernelDirection {
    NORTH, EAST, SOUTH, WEST
  }

  @Property(description = "Effect transparency")
  @PropertyMin(0)
  @PropertyMax(100)
  private int transparency;

  @Property(description = "Constant part to add to each pixel value")
  @PropertyMin(0)
  @PropertyMax(255)
  private int bias;

  @Property(description = "How to treat the outer space of the source image", editorClass = EdgeModeEditor.class)
  private EdgeMode edgeMode;

  @Property(description = "Color or Grey mode", editorClass = ColorModeEditor.class)
  private ColorMode colorMode;

  @Property(description = "The convolution kernel", editorClass = KernelTypeEditor.class)
  private KernelType kernelType;

  @Property(description = "The kernel alignment", editorClass = KernelDirectionEditor.class)
  private KernelDirection kernelDirection;

  @Override
  protected void performPixelTransformation(WFImage pImg) {
    SimpleImage img = (SimpleImage) pImg;
    int kernel[][] = getKernel();
    int width = srcImg.getImageWidth();
    int height = srcImg.getImageHeight();

    int m1 = this.transparency;
    int m2 = (100 - this.transparency);

    int kernelSize = kernel.length;
    int halveKernelSize = kernelSize / 2;
    int kernelSum = 0;
    for (int i = 0; i < kernelSize; i++) {
      for (int j = 0; j < kernelSize; j++) {
        kernelSum += kernel[i][j];
      }
    }
    if (kernelSum == 0)
      kernelSum = 1;
    Pixel pixel = new Pixel();
    if (colorMode == ColorMode.GREY) {
      srcImg = srcImg.clone();
      new ColorToGrayTransformer().transformImage(srcImg);
      for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
          int intSumR = 0;
          for (int k = 0; k < kernelSize; k++) {
            int y = i - halveKernelSize + k;
            addPixels: for (int l = 0; l < kernelSize; l++) {
              int x = j - halveKernelSize + l;
              if (x < 0) {
                switch (this.edgeMode) {
                  case MIRROR:
                    x = -x;
                    break;
                  case WRAP:
                    x += width;
                    break;
                  case BLACK:
                    continue addPixels;
                }
              }
              else if (x >= width) {
                switch (this.edgeMode) {
                  case MIRROR:
                    x = 2 * width - x - 1;
                    break;
                  case WRAP:
                    x -= width;
                    break;
                  case BLACK:
                    continue addPixels;
                }
              }
              if (y < 0) {
                switch (this.edgeMode) {
                  case MIRROR:
                    y = -y;
                    break;
                  case WRAP:
                    y += height;
                    break;
                  case BLACK:
                    continue addPixels;
                }
              }
              else if (y >= height) {
                switch (this.edgeMode) {
                  case MIRROR:
                    y = 2 * height - y - 1;
                    break;
                  case WRAP:
                    y -= height;
                    break;
                  case BLACK:
                    continue addPixels;
                }
              }
              intSumR += srcImg.getRValue(x, y) * kernel[k][l];
            }
          }
          intSumR = Tools.limitColor((intSumR / kernelSum) + this.bias);
          if (this.transparency == 0) {
            img.setRGB(j, i, intSumR, intSumR, intSumR);
          }
          else {
            pixel.setARGBValue(srcImg.getARGBValue(j, i));
            int rval = Tools.limitColor(((pixel.r * m1 + intSumR * m2) / 100));
            img.setRGB(j, i, rval, rval, rval);
          }
        }
      }
    }
    else {
      for (int i = 0; i < height; i++) {
        for (int j = 0; j < width; j++) {
          int intSumR = 0;
          int intSumG = 0;
          int intSumB = 0;
          for (int k = 0; k < kernelSize; k++) {
            int y = i - halveKernelSize + k;
            addPixels: for (int l = 0; l < kernelSize; l++) {
              int x = j - halveKernelSize + l;
              if (x < 0) {
                switch (this.edgeMode) {
                  case MIRROR:
                    x = -x;
                    break;
                  case WRAP:
                    x += width;
                    break;
                  case BLACK:
                    continue addPixels;
                }
              }
              else if (x >= width) {
                switch (this.edgeMode) {
                  case MIRROR:
                    x = 2 * width - x - 1;
                    break;
                  case WRAP:
                    x -= width;
                    break;
                  case BLACK:
                    continue addPixels;
                }
              }
              if (y < 0) {
                switch (this.edgeMode) {
                  case MIRROR:
                    y = -y;
                    break;
                  case WRAP:
                    y += height;
                    break;
                  case BLACK:
                    continue addPixels;
                }
              }
              else if (y >= height) {
                switch (this.edgeMode) {
                  case MIRROR:
                    y = 2 * height - y - 1;
                    break;
                  case WRAP:
                    y -= height;
                    break;
                  case BLACK:
                    continue addPixels;
                }
              }
              pixel.setARGBValue(srcImg.getARGBValue(x, y));
              intSumR += pixel.r * kernel[k][l];
              intSumG += pixel.g * kernel[k][l];
              intSumB += pixel.b * kernel[k][l];
            }
          }
          intSumR = Tools.limitColor((intSumR / kernelSum) + this.bias);
          intSumG = Tools.limitColor((intSumG / kernelSum) + this.bias);
          intSumB = Tools.limitColor((intSumB / kernelSum) + this.bias);

          if (this.transparency == 0) {
            img.setRGB(j, i, intSumR, intSumG, intSumB);
          }
          else {
            pixel.setARGBValue(srcImg.getARGBValue(j, i));
            int rval = Tools.limitColor(((pixel.r * m1 + intSumR * m2) / 100));
            int gval = Tools.limitColor(((pixel.g * m1 + intSumG * m2) / 100));
            int bval = Tools.limitColor(((pixel.b * m1 + intSumB * m2) / 100));
            img.setRGB(j, i, rval, gval, bval);
          }
        }
      }
    }
  }

  @Override
  public void initDefaultParams(WFImage pImg) {
    edgeMode = EdgeMode.MIRROR;
    colorMode = ColorMode.COLOR;
    transparency = 0;
    kernelDirection = KernelDirection.NORTH;
    bias = 0;
    kernelType = KernelType.EMBOSS_3x3;
  }

  // 1
  private static final int[][] KERNEL_EMPTY = { { 1 } };
  // -1 -1 -1
  // -1  8 -1
  // -1 -1 -1
  private static final int[][] KERNEL_EDGE_DETECT_3x3 = { { -1, -1, -1 }, { -1, 8, -1 },
      { -1, -1, -1 } };
  // -2  0  0
  //  0  1  0
  //  0  0  2
  private static final int[][] KERNEL_EMBOSS_3x3 = { { -2, 0, 0 }, { 0, 1, 0 }, { 0, 0, 2 } };
  //  0 -1  0
  // -1  4 -1
  //  0 -1  0
  private static final int[][] KERNEL_LAPLACE_3x3 = { { 0, -1, 0 }, { -1, 4, -1 }, { 0, -1, 0 } };
  // -1 -1 -1
  // -1  9 -1
  // -1 -1 -1
  private static final int[][] KERNEL_SHARPEN_3x3 = { { -1, -1, -1 }, { -1, 9, -1 }, { -1, -1, -1 } };
  // -1 -1 -1
  // -1  17 -1
  // -1 -1 -1
  private static final int[][] KERNEL_SHARPEN_LESS_3x3 = { { -1, -1, -1 }, { -1, 17, -1 },
      { -1, -1, -1 } };
  // -1  0  1
  // -2  0  2
  // -1  0  1
  private static final int[][] KERNEL_SOBEL_3x3 = { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } };
  //  2  4  5  4  2
  //  4  9 12  9  4
  //  5 12 15 12  5
  //  4  9 12  9  4
  //  2  4  5  4  2
  private static final int[][] KERNEL_GAUSSIAN_BLUR_5x5 = { { 2, 4, 5, 4, 2 }, { 4, 9, 12, 9, 4 },
      { 5, 12, 15, 12, 5 }, { 4, 9, 12, 9, 4 }, { 2, 4, 5, 4, 2 } };
  // 1  2  1
  // 2  4  2
  // 1  2  1
  private static final int[][] KERNEL_GAUSSIAN_BLUR_3x3 = { { 1, 2, 1 }, { 2, 4, 2 }, { 1, 2, 1 } };

  private int[][] getKernel() {
    int res[][];
    switch (kernelType) {
      case EDGE_DETECT_3x3:
        res = KERNEL_EDGE_DETECT_3x3;
        break;
      case EMBOSS_3x3:
        res = KERNEL_EMBOSS_3x3;
        break;
      case LAPLACE_3x3:
        res = KERNEL_LAPLACE_3x3;
        break;
      case SHARPEN_3x3:
        res = KERNEL_SHARPEN_3x3;
        break;
      case SHARPEN_LESS_3x3:
        res = KERNEL_SHARPEN_LESS_3x3;
        break;
      case SOBEL_3X3:
        res = KERNEL_SOBEL_3x3;
        break;
      case GAUSSIAN_BLUR_3x3:
        res = KERNEL_GAUSSIAN_BLUR_3x3;
        break;
      case GAUSSIAN_BLUR_5x5:
        res = KERNEL_GAUSSIAN_BLUR_5x5;
        break;
      default:
        res = KERNEL_EMPTY;
        break;
    }
    final int size = res.length;
    switch (kernelDirection) {
      case EAST: {
        int[][] rotKernel = new int[size][size];
        for (int i = 0; i < size; i++) {
          for (int j = 0; j < size; j++) {
            rotKernel[j][i] = res[size - 1 - i][j];
          }
        }
        return rotKernel;
      }
      case WEST: {
        int[][] rotKernel = new int[size][size];
        for (int i = 0; i < size; i++) {
          for (int j = 0; j < size; j++) {
            rotKernel[j][i] = res[i][size - 1 - j];
          }
        }
        return rotKernel;
      }
      case SOUTH: {
        int[][] rotKernel = new int[size][size];
        for (int i = 0; i < size; i++) {
          for (int j = 0; j < size; j++) {
            rotKernel[j][i] = res[size - 1 - j][size - 1 - i];
          }
        }
        return rotKernel;
      }
      default:
        return res;
    }

  }

  public static class EdgeModeEditor extends ComboBoxPropertyEditor {
    public EdgeModeEditor() {
      super();
      setAvailableValues(new EdgeMode[] { EdgeMode.MIRROR, EdgeMode.WRAP, EdgeMode.BLACK });
    }
  }

  public static class ColorModeEditor extends ComboBoxPropertyEditor {
    public ColorModeEditor() {
      super();
      setAvailableValues(new ColorMode[] { ColorMode.COLOR, ColorMode.GREY });
    }
  }

  public static class KernelTypeEditor extends ComboBoxPropertyEditor {
    public KernelTypeEditor() {
      super();
      setAvailableValues(new KernelType[] { KernelType.EDGE_DETECT_3x3, KernelType.EMBOSS_3x3,
          KernelType.LAPLACE_3x3, KernelType.SHARPEN_3x3, KernelType.SHARPEN_LESS_3x3,
          KernelType.SOBEL_3X3, KernelType.GAUSSIAN_BLUR_3x3, KernelType.GAUSSIAN_BLUR_5x5 });
    }
  }

  public static class KernelDirectionEditor extends ComboBoxPropertyEditor {
    public KernelDirectionEditor() {
      super();
      setAvailableValues(new KernelDirection[] { KernelDirection.NORTH, KernelDirection.EAST,
          KernelDirection.SOUTH, KernelDirection.WEST });
    }
  }

  public int getTransparency() {
    return transparency;
  }

  public void setTransparency(int transparency) {
    this.transparency = transparency;
  }

  public int getBias() {
    return bias;
  }

  public void setBias(int bias) {
    this.bias = bias;
  }

  public EdgeMode getEdgeMode() {
    return edgeMode;
  }

  public void setEdgeMode(EdgeMode edgeMode) {
    this.edgeMode = edgeMode;
  }

  public KernelType getKernelType() {
    return kernelType;
  }

  public void setKernelType(KernelType kernelType) {
    this.kernelType = kernelType;
  }

  public ColorMode getColorMode() {
    return colorMode;
  }

  public void setColorMode(ColorMode colorMode) {
    this.colorMode = colorMode;
  }

  public KernelDirection getKernelDirection() {
    return kernelDirection;
  }

  public void setKernelDirection(KernelDirection kernelDirection) {
    this.kernelDirection = kernelDirection;
  }
}
TOP

Related Classes of org.jwildfire.transform.ConvolveTransformer$KernelTypeEditor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.