@Override
  public void applyInPlace(FastBitmap fastBitmap) {

    if (fastBitmap.isRGB()) {
      int size = fastBitmap.getWidth() * fastBitmap.getHeight();
      for (int i = 0; i < size; i++) {
        int r = fastBitmap.getRed(i);
        int g = fastBitmap.getGreen(i);
        int b = fastBitmap.getBlue(i);

        float[] color = ColorConverter.RGBtoHLS(r, g, b);
        int[] newColor = ColorConverter.HSLtoRGB(degree, color[1], color[2]);

        newColor[0] = newColor[0] > 255 ? 255 : newColor[0];
        newColor[0] = newColor[0] < 0 ? 0 : newColor[0];

        newColor[1] = newColor[1] > 255 ? 255 : newColor[1];
        newColor[1] = newColor[1] < 0 ? 0 : newColor[1];

        newColor[2] = newColor[2] > 255 ? 255 : newColor[2];
        newColor[2] = newColor[2] < 0 ? 0 : newColor[2];

        fastBitmap.setRGB(i, newColor);
      }
    } else {
      throw new IllegalArgumentException("Hue modifier only works in RGB images.");
    }
  }
  /**
   * Extract blob.
   *
   * @param id ID.
   * @param fastBitmap Image to be processed.
   * @return Image with the extracted blob.
   */
  public FastBitmap Extract(int id, FastBitmap fastBitmap) {

    // Check if blobs list is null.
    if (this.blobs == null) this.blobs = new BlobDetection().ProcessImage(fastBitmap);

    FastBitmap image;

    if (fastBitmap.isGrayscale()) {
      image =
          new FastBitmap(
              fastBitmap.getWidth(), fastBitmap.getHeight(), FastBitmap.ColorSpace.Grayscale);
      for (IntPoint p : blobs.get(id).getPoints()) {
        image.setGray(p.x, p.y, fastBitmap.getGray(p.x, p.y));
      }
    } else {
      image =
          new FastBitmap(fastBitmap.getWidth(), fastBitmap.getHeight(), FastBitmap.ColorSpace.RGB);
      for (IntPoint p : blobs.get(id).getPoints()) {
        image.setRed(p.x, p.y, fastBitmap.getRed(p.x, p.y));
        image.setGreen(p.x, p.y, fastBitmap.getGreen(p.x, p.y));
        image.setBlue(p.x, p.y, fastBitmap.getBlue(p.x, p.y));
      }
    }
    return image;
  }
  @Override
  public void applyInPlace(FastBitmap fastBitmap) {

    int size = fastBitmap.getSize();

    if (fastBitmap.isGrayscale()) {

      CalculateMap(inGray, outGray, mapGray);

      for (int x = 0; x < size; x++) {
        fastBitmap.setGray(x, mapGray[fastBitmap.getGray(x)]);
      }
    } else {

      CalculateMap(inRed, outRed, mapRed);
      CalculateMap(inGreen, outGreen, mapGreen);
      CalculateMap(inBlue, outBlue, mapBlue);

      for (int x = 0; x < size; x++) {
        int r = mapRed[fastBitmap.getRed(x)];
        int g = mapGreen[fastBitmap.getGreen(x)];
        int b = mapBlue[fastBitmap.getBlue(x)];

        fastBitmap.setRGB(x, r, g, b);
      }
    }
  }
  /**
   * Computes histograms.
   *
   * @param fastBitmap Image.
   */
  private void ProcessImage(FastBitmap fastBitmap) {

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

    if (fastBitmap.isGrayscale()) {
      int[] g = new int[width];
      for (int x = 0; x < height; x++) {
        for (int y = 0; y < width; y++) {
          g[y] += fastBitmap.getGray(x, y);
        }
      }
      gray = new Histogram(g);
    }
    if (fastBitmap.isRGB()) {
      int[] r = new int[width];
      int[] g = new int[width];
      int[] b = new int[width];
      for (int x = 0; x < height; x++) {
        for (int y = 0; y < width; y++) {
          r[y] += fastBitmap.getRed(x, y);
          g[y] += fastBitmap.getGreen(x, y);
          b[y] += fastBitmap.getBlue(x, y);
        }
      }
      red = new Histogram(r);
      green = new Histogram(g);
      blue = new Histogram(b);
    }
  }
  @Override
  public void applyInPlace(FastBitmap fastBitmap) {

    if (fastBitmap.isRGB() && overlay.isRGB()) {

      int w = fastBitmap.getWidth();
      int h = fastBitmap.getHeight();

      switch (algorithm) {
        case Lighten:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
              if (overlay.getRed(i, j) > fastBitmap.getRed(i, j)) {
                fastBitmap.setRed(i, j, overlay.getRed(i, j));
              }
              if (overlay.getGreen(i, j) > fastBitmap.getGreen(i, j)) {
                fastBitmap.setGreen(i, j, overlay.getGreen(i, j));
              }
              if (overlay.getBlue(i, j) > fastBitmap.getBlue(i, j)) {
                fastBitmap.setBlue(i, j, overlay.getBlue(i, j));
              }
            }
          }
          break;
        case Darken:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
              if (overlay.getRed(i, j) < fastBitmap.getRed(i, j)) {
                fastBitmap.setRed(i, j, overlay.getRed(i, j));
              }
              if (overlay.getGreen(i, j) < fastBitmap.getGreen(i, j)) {
                fastBitmap.setGreen(i, j, overlay.getGreen(i, j));
              }
              if (overlay.getBlue(i, j) < fastBitmap.getBlue(i, j)) {
                fastBitmap.setBlue(i, j, overlay.getBlue(i, j));
              }
            }
          }
          break;
        case Multiply:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
              int r = fastBitmap.getRed(i, j) * overlay.getRed(i, j) / 255;
              int g = fastBitmap.getGreen(i, j) * overlay.getGreen(i, j) / 255;
              int b = fastBitmap.getBlue(i, j) * overlay.getBlue(i, j) / 255;
              fastBitmap.setRGB(i, j, r, g, b);
            }
          }
          break;
        case Average:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
              int r = fastBitmap.getRed(i, j) + overlay.getRed(i, j) / 2;
              int g = fastBitmap.getGreen(i, j) + overlay.getGreen(i, j) / 2;
              int b = fastBitmap.getBlue(i, j) + overlay.getBlue(i, j) / 2;
              fastBitmap.setRGB(i, j, r, g, b);
            }
          }
          break;
        case Add:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
              int r = Math.min(fastBitmap.getRed(i, j) + overlay.getRed(i, j), 255);
              int g = Math.min(fastBitmap.getGreen(i, j) + overlay.getGreen(i, j), 255);
              int b = Math.min(fastBitmap.getBlue(i, j) + overlay.getBlue(i, j), 255);
              fastBitmap.setRGB(i, j, r, g, b);
            }
          }
          break;
        case Subtract:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
              int temp = fastBitmap.getRed(i, j) + overlay.getRed(i, j);
              if (temp < 255) {
                fastBitmap.setRed(i, j, 0);
              } else {
                fastBitmap.setRed(i, j, temp - 255);
              }

              temp = fastBitmap.getGreen(i, j) + overlay.getGreen(i, j);
              if (temp < 255) {
                fastBitmap.setGreen(i, j, 0);
              } else {
                fastBitmap.setGreen(i, j, temp - 255);
              }

              temp = fastBitmap.getBlue(i, j) + overlay.getBlue(i, j);
              if (temp < 255) {
                fastBitmap.setBlue(i, j, 0);
              } else {
                fastBitmap.setBlue(i, j, temp - 255);
              }
            }
          }
          break;
        case Difference:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
              int r = Math.abs(fastBitmap.getRed(i, j) - overlay.getRed(i, j));
              int g = Math.abs(fastBitmap.getGreen(i, j) - overlay.getGreen(i, j));
              int b = Math.abs(fastBitmap.getBlue(i, j) - overlay.getBlue(i, j));
              fastBitmap.setRGB(i, j, r, g, b);
            }
          }
          break;
        case Negation:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
              int r = 255 - Math.abs(255 - fastBitmap.getRed(i, j) - overlay.getRed(i, j));
              int g = 255 - Math.abs(255 - fastBitmap.getGreen(i, j) - overlay.getGreen(i, j));
              int b = 255 - Math.abs(255 - fastBitmap.getBlue(i, j) - overlay.getBlue(i, j));
              fastBitmap.setRGB(i, j, r, g, b);
            }
          }
          break;
        case Screen:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
              int r =
                  ((255 - (((255 - fastBitmap.getRed(i, j)) * (255 - overlay.getRed(i, j))) >> 8)));
              int g =
                  ((255
                      - (((255 - fastBitmap.getGreen(i, j)) * (255 - overlay.getGreen(i, j)))
                          >> 8)));
              int b =
                  ((255
                      - (((255 - fastBitmap.getBlue(i, j)) * (255 - overlay.getBlue(i, j))) >> 8)));
              fastBitmap.setRGB(i, j, r, g, b);
            }
          }
          break;
        case Exclusion:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
              int r =
                  ((fastBitmap.getRed(i, j)
                      + overlay.getRed(i, j)
                      - 2 * fastBitmap.getRed(i, j) * overlay.getRed(i, j) / 255));
              int g =
                  ((fastBitmap.getGreen(i, j)
                      + overlay.getGreen(i, j)
                      - 2 * fastBitmap.getGreen(i, j) * overlay.getGreen(i, j) / 255));
              int b =
                  ((fastBitmap.getBlue(i, j)
                      + overlay.getBlue(i, j)
                      - 2 * fastBitmap.getBlue(i, j) * overlay.getBlue(i, j) / 255));
              fastBitmap.setRGB(i, j, r, g, b);
            }
          }
          break;
        case Overlay:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {

              int temp;
              if (overlay.getRed(i, j) < 128) {
                temp = (2 * fastBitmap.getRed(i, j) * overlay.getRed(i, j) / 255);
                temp = Math.min(255, temp);
                fastBitmap.setRed(i, j, temp);
              } else {
                temp =
                    (255
                        - 2 * (255 - fastBitmap.getRed(i, j)) * (255 - overlay.getRed(i, j)) / 255);
                temp = Math.min(255, temp);
                fastBitmap.setRed(i, j, temp);
              }

              if (overlay.getGreen(i, j) < 128) {
                temp = (2 * fastBitmap.getGreen(i, j) * overlay.getGreen(i, j) / 255);
                temp = Math.min(255, temp);
                fastBitmap.setGreen(i, j, temp);
              } else {
                temp =
                    (255
                        - 2
                            * (255 - fastBitmap.getGreen(i, j))
                            * (255 - overlay.getGreen(i, j))
                            / 255);
                temp = Math.min(255, temp);
                fastBitmap.setGreen(i, j, temp);
              }

              if (overlay.getBlue(i, j) < 128) {
                temp = (2 * fastBitmap.getBlue(i, j) * overlay.getBlue(i, j) / 255);
                temp = Math.min(255, temp);
                fastBitmap.setBlue(i, j, temp);
              } else {
                temp =
                    (255
                        - 2
                            * (255 - fastBitmap.getBlue(i, j))
                            * (255 - overlay.getBlue(i, j))
                            / 255);
                temp = Math.min(255, temp);
                fastBitmap.setBlue(i, j, temp);
              }
            }
          }
          break;
        case SoftLight:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {

              int temp;
              if (fastBitmap.getRed(i, j) < 128) {
                temp = (2 * overlay.getRed(i, j) * fastBitmap.getRed(i, j) / 255);
                temp = Math.min(255, temp);
                fastBitmap.setRed(i, j, temp);
              } else {
                temp =
                    (255
                        - 2 * (255 - overlay.getRed(i, j)) * (255 - fastBitmap.getRed(i, j)) / 255);
                temp = Math.min(255, temp);
                overlay.setRed(i, j, temp);
              }

              if (fastBitmap.getGreen(i, j) < 128) {
                temp = (2 * overlay.getGreen(i, j) * fastBitmap.getGreen(i, j) / 255);
                temp = Math.min(255, temp);
                fastBitmap.setGreen(i, j, temp);
              } else {
                temp =
                    (255
                        - 2
                            * (255 - overlay.getGreen(i, j))
                            * (255 - fastBitmap.getGreen(i, j))
                            / 255);
                temp = Math.min(255, temp);
                fastBitmap.setGreen(i, j, temp);
              }

              if (fastBitmap.getBlue(i, j) < 128) {
                temp = (2 * overlay.getBlue(i, j) * fastBitmap.getBlue(i, j) / 255);
                temp = Math.min(255, temp);
                fastBitmap.setBlue(i, j, temp);
              } else {
                temp =
                    (255
                        - 2
                            * (255 - overlay.getBlue(i, j))
                            * (255 - fastBitmap.getBlue(i, j))
                            / 255);
                temp = Math.min(255, temp);
                fastBitmap.setBlue(i, j, temp);
              }
            }
          }
          break;
        case HardLight:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {

              float temp;
              if (overlay.getRed(i, j) < 128) {
                temp =
                    (2 * ((fastBitmap.getRed(i, j) >> 1) + 64))
                        * ((float) overlay.getRed(i, j) / 255);
                fastBitmap.setRed(i, j, (int) temp);
              } else {
                temp =
                    (255
                        - (2
                            * (255 - ((fastBitmap.getRed(i, j) >> 1) + 64))
                            * (float) (255 - overlay.getRed(i, j))
                            / 255));
                fastBitmap.setRed(i, j, (int) temp);
              }

              if (overlay.getGreen(i, j) < 128) {
                temp =
                    (2 * ((fastBitmap.getGreen(i, j) >> 1) + 64))
                        * ((float) overlay.getGreen(i, j) / 255);
                fastBitmap.setGreen(i, j, (int) temp);
              } else {
                temp =
                    (255
                        - (2
                            * (255 - ((fastBitmap.getGreen(i, j) >> 1) + 64))
                            * (float) (255 - overlay.getGreen(i, j))
                            / 255));
                fastBitmap.setGreen(i, j, (int) temp);
              }

              if (overlay.getBlue(i, j) < 128) {
                temp =
                    (2 * ((fastBitmap.getBlue(i, j) >> 1) + 64))
                        * ((float) overlay.getBlue(i, j) / 255);
                fastBitmap.setBlue(i, j, (int) temp);
              } else {
                temp =
                    (255
                        - (2
                            * (255 - ((fastBitmap.getBlue(i, j) >> 1) + 64))
                            * (float) (255 - overlay.getBlue(i, j))
                            / 255));
                fastBitmap.setBlue(i, j, (int) temp);
              }
            }
          }
          break;
        case ColorDodge:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {

              if (overlay.getRed(i, j) == 255) {
                fastBitmap.setRed(i, j, 255);
              } else {
                int x =
                    Math.min(255, ((fastBitmap.getRed(i, j) << 8) / (255 - overlay.getRed(i, j))));
                fastBitmap.setRed(i, j, x);
              }

              if (overlay.getGreen(i, j) == 255) {
                fastBitmap.setGreen(i, j, 255);
              } else {
                int x =
                    Math.min(
                        255, ((fastBitmap.getGreen(i, j) << 8) / (255 - overlay.getGreen(i, j))));
                fastBitmap.setGreen(i, j, x);
              }

              if (overlay.getBlue(i, j) == 255) {
                fastBitmap.setBlue(i, j, 255);
              } else {
                int x =
                    Math.min(
                        255, ((fastBitmap.getBlue(i, j) << 8) / (255 - overlay.getBlue(i, j))));
                fastBitmap.setBlue(i, j, x);
              }
            }
          }
          break;
        case ColorBurn:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {

              if (overlay.getRed(i, j) == 0) {
                fastBitmap.setRed(i, j, overlay.getRed(i, j));
              } else {
                int x =
                    Math.max(
                        0, (255 - ((255 - fastBitmap.getRed(i, j)) << 8) / overlay.getRed(i, j)));
                fastBitmap.setRed(i, j, x);
              }

              if (overlay.getGreen(i, j) == 0) {
                fastBitmap.setGreen(i, j, overlay.getGreen(i, j));
              } else {
                int x =
                    Math.max(
                        0,
                        (255 - ((255 - fastBitmap.getGreen(i, j)) << 8) / overlay.getGreen(i, j)));
                fastBitmap.setGreen(i, j, x);
              }

              if (overlay.getBlue(i, j) == 0) {
                fastBitmap.setBlue(i, j, overlay.getBlue(i, j));
              } else {
                int x =
                    Math.max(
                        0, (255 - ((255 - fastBitmap.getBlue(i, j)) << 8) / overlay.getBlue(i, j)));
                fastBitmap.setBlue(i, j, x);
              }
            }
          }
          break;
        case LinearLight:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
              int temp;

              if (overlay.getRed(i, j) < 128) {
                temp = fastBitmap.getRed(i, j) + (2 * overlay.getRed(i, j));
                if (temp < 255) {
                  fastBitmap.setRed(i, j, 0);
                } else {
                  fastBitmap.setRed(i, j, (temp - 255));
                }
              } else {
                int x = Math.min(fastBitmap.getRed(i, j) + (2 * (overlay.getRed(i, j) - 128)), 255);
                fastBitmap.setRed(i, j, x);
              }

              if (overlay.getGreen(i, j) < 128) {
                temp = fastBitmap.getGreen(i, j) + (2 * overlay.getGreen(i, j));
                if (temp < 255) {
                  fastBitmap.setGreen(i, j, 0);
                } else {
                  fastBitmap.setGreen(i, j, (temp - 255));
                }
              } else {
                int x =
                    Math.min(fastBitmap.getGreen(i, j) + (2 * (overlay.getGreen(i, j) - 128)), 255);
                fastBitmap.setGreen(i, j, x);
              }

              if (overlay.getBlue(i, j) < 128) {
                temp = fastBitmap.getBlue(i, j) + (2 * overlay.getBlue(i, j));
                if (temp < 255) {
                  fastBitmap.setBlue(i, j, 0);
                } else {
                  fastBitmap.setBlue(i, j, (temp - 255));
                }
              } else {
                int x =
                    Math.min(fastBitmap.getBlue(i, j) + (2 * (overlay.getBlue(i, j) - 128)), 255);
                fastBitmap.setBlue(i, j, x);
              }
            }
          }
          break;
        case VividLight:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {

              if (overlay.getRed(i, j) < 128) {
                // Color Burn
                int o = overlay.getRed(i, j) * 2;
                if (o == 0) {
                  fastBitmap.setRed(i, j, o);
                } else {
                  int x = Math.max(0, (255 - ((255 - fastBitmap.getRed(i, j)) << 8) / o));
                  fastBitmap.setRed(i, j, x);
                }
              } else {
                // Color Dodge
                int o = 2 * (overlay.getRed(i, j) - 128);
                if (o == 255) {
                  fastBitmap.setRed(i, j, 255);
                } else {
                  int x = Math.min(255, ((fastBitmap.getRed(i, j) << 8) / (255 - o)));
                  fastBitmap.setRed(i, j, x);
                }
              }

              if (overlay.getGreen(i, j) < 128) {
                // Color Burn
                int o = overlay.getGreen(i, j) * 2;
                if (o == 0) {
                  fastBitmap.setGreen(i, j, o);
                } else {
                  int x = Math.max(0, (255 - ((255 - fastBitmap.getGreen(i, j)) << 8) / o));
                  fastBitmap.setGreen(i, j, x);
                }
              } else {
                // Color Dodge
                int o = 2 * (overlay.getGreen(i, j) - 128);
                if (o == 255) {
                  fastBitmap.setGreen(i, j, 255);
                } else {
                  int x = Math.min(255, ((fastBitmap.getGreen(i, j) << 8) / (255 - o)));
                  fastBitmap.setGreen(i, j, x);
                }
              }

              if (overlay.getBlue(i, j) < 128) {
                // Color Burn
                int o = overlay.getBlue(i, j) * 2;
                if (o == 0) {
                  fastBitmap.setBlue(i, j, o);
                } else {
                  int x = Math.max(0, (255 - ((255 - fastBitmap.getBlue(i, j)) << 8) / o));
                  fastBitmap.setBlue(i, j, x);
                }
              } else {
                // Color Dodge
                int o = 2 * (overlay.getBlue(i, j) - 128);
                if (o == 255) {
                  fastBitmap.setGreen(i, j, 255);
                } else {
                  int x = Math.min(255, ((fastBitmap.getBlue(i, j) << 8) / (255 - o)));
                  fastBitmap.setBlue(i, j, x);
                }
              }
            }
          }

          break;
        case PinLight:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {

              int o = overlay.getRed(i, j) * 2;
              if (overlay.getRed(i, j) < 128) {
                // Darken
                if (o < fastBitmap.getRed(i, j)) {
                  fastBitmap.setRed(i, j, o);
                }
              } else {
                // Lighten
                if (o > fastBitmap.getRed(i, j)) {
                  fastBitmap.setRed(i, j, o);
                }
              }

              o = overlay.getGreen(i, j) * 2;
              if (overlay.getGreen(i, j) < 128) {
                // Darken
                if (o < fastBitmap.getGreen(i, j)) {
                  fastBitmap.setGreen(i, j, o);
                }
              } else {
                // Lighten
                if (o > fastBitmap.getGreen(i, j)) {
                  fastBitmap.setGreen(i, j, o);
                }
              }

              o = overlay.getBlue(i, j) * 2;
              if (overlay.getBlue(i, j) < 128) {
                // Darken
                if (o < fastBitmap.getBlue(i, j)) {
                  fastBitmap.setBlue(i, j, o);
                }
              } else {
                // Lighten
                if (o > fastBitmap.getBlue(i, j)) {
                  fastBitmap.setBlue(i, j, o);
                }
              }
            }
          }
          break;
        case Reflect:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {

              if (overlay.getRed(i, j) == 255) {
                fastBitmap.setRed(i, j, 255);
              } else {
                int x =
                    Math.min(
                        255,
                        (fastBitmap.getRed(i, j)
                            * fastBitmap.getRed(i, j)
                            / (255 - overlay.getRed(i, j))));
                fastBitmap.setRed(i, j, x);
              }

              if (overlay.getGreen(i, j) == 255) {
                fastBitmap.setGreen(i, j, 255);
              } else {
                int x =
                    Math.min(
                        255,
                        (fastBitmap.getGreen(i, j)
                            * fastBitmap.getGreen(i, j)
                            / (255 - overlay.getGreen(i, j))));
                fastBitmap.setGreen(i, j, x);
              }

              if (overlay.getBlue(i, j) == 255) {
                fastBitmap.setBlue(i, j, 255);
              } else {
                int x =
                    Math.min(
                        255,
                        (fastBitmap.getBlue(i, j)
                            * fastBitmap.getBlue(i, j)
                            / (255 - overlay.getBlue(i, j))));
                fastBitmap.setBlue(i, j, x);
              }
            }
          }
          break;
        case Phoenix:
          for (int i = 0; i < h; i++) {
            for (int j = 0; j < w; j++) {
              int r =
                  ((Math.min(fastBitmap.getRed(i, j), overlay.getRed(i, j))
                      - Math.max(fastBitmap.getRed(i, j), overlay.getRed(i, j))
                      + 255));
              int g =
                  ((Math.min(fastBitmap.getGreen(i, j), overlay.getGreen(i, j))
                      - Math.max(fastBitmap.getGreen(i, j), overlay.getGreen(i, j))
                      + 255));
              int b =
                  ((Math.min(fastBitmap.getBlue(i, j), overlay.getBlue(i, j))
                      - Math.max(fastBitmap.getBlue(i, j), overlay.getBlue(i, j))
                      + 255));

              fastBitmap.setRGB(i, j, r, g, b);
            }
          }
          break;
      }

    } else {
      throw new IllegalArgumentException("Blend only works in RGB images.");
    }
  }
  @Override
  public void applyInPlace(FastBitmap fastBitmap) {

    if (fastBitmap.isGrayscale()) {

      int width = fastBitmap.getWidth();
      int height = fastBitmap.getHeight();
      double oldIradius = (double) (height - 1) / 2;
      double oldJradius = (double) (width - 1) / 2;

      CalculateNewSize(fastBitmap);
      FastBitmap destinationData =
          new FastBitmap(newWidth, newHeight, FastBitmap.ColorSpace.Grayscale);

      // get destination image size
      double newIradius = (double) (newHeight - 1) / 2;
      double newJradius = (double) (newWidth - 1) / 2;

      // angle's sine and cosine
      double angleRad = -angle * Math.PI / 180;
      double angleCos = Math.cos(angleRad);
      double angleSin = Math.sin(angleRad);

      // destination pixel's coordinate relative to image center
      double ci, cj;

      // coordinates of source points and cooefficiens
      double oi, oj, di, dj, k1, k2;
      int oi1, oj1, oi2, oj2;

      // width and height decreased by 1
      int imax = height - 1;
      int jmax = width - 1;

      ci = -newIradius;
      for (int i = 0; i < newHeight; i++) {
        cj = -newJradius;
        for (int j = 0; j < newWidth; j++) {

          // coordinate of the nearest point
          oi = angleCos * ci + angleSin * cj + oldIradius;
          oj = -angleSin * ci + angleCos * cj + oldJradius;

          oi1 = (int) oi;
          oj1 = (int) oj;

          // validate source pixel's coordinates
          if ((oi1 < 0) || (oj1 < 0) || (oi1 >= height) || (oj1 >= width)) {
            // fill destination image with filler
            destinationData.setGray(i, j, fillGray);
          } else {

            di = oi - (double) oi1;
            dj = oj - (double) oj1;

            // initial pixel value
            int g = 0;

            for (int n = -1; n < 3; n++) {
              // get Y cooefficient
              k1 = Interpolation.BiCubicKernel(dj - (double) n);

              oj2 = oj1 + n;
              if (oj2 < 0) oj2 = 0;
              if (oj2 > jmax) oj2 = jmax;

              for (int m = -1; m < 3; m++) {
                // get X cooefficient
                k2 = k1 * Interpolation.BiCubicKernel((double) m - di);

                oi2 = oi1 + m;
                if (oi2 < 0) oi2 = 0;
                if (oi2 > imax) oi2 = imax;

                g += k2 * fastBitmap.getGray(oi2, oj2);
              }
            }

            destinationData.setGray(i, j, Math.max(0, Math.min(255, g)));
          }
          cj++;
        }
        ci++;
      }

      fastBitmap.setImage(destinationData);
      destinationData.recycle();

    } else if (fastBitmap.isRGB()) {
      int width = fastBitmap.getWidth();
      int height = fastBitmap.getHeight();
      double oldIradius = (double) (height - 1) / 2;
      double oldJradius = (double) (width - 1) / 2;

      CalculateNewSize(fastBitmap);
      FastBitmap destinationData = new FastBitmap(newWidth, newHeight, FastBitmap.ColorSpace.RGB);

      // get destination image size
      double newIradius = (double) (newHeight - 1) / 2;
      double newJradius = (double) (newWidth - 1) / 2;

      // angle's sine and cosine
      double angleRad = -angle * Math.PI / 180;
      double angleCos = Math.cos(angleRad);
      double angleSin = Math.sin(angleRad);

      // destination pixel's coordinate relative to image center
      double ci, cj;

      // coordinates of source points and cooefficiens
      double oi, oj, di, dj, k1, k2;
      int oi1, oj1, oi2, oj2;

      // width and height decreased by 1
      int imax = height - 1;
      int jmax = width - 1;

      ci = -newIradius;
      for (int i = 0; i < newHeight; i++) {
        cj = -newJradius;
        for (int j = 0; j < newWidth; j++) {

          // coordinate of the nearest point
          oi = angleCos * ci + angleSin * cj + oldIradius;
          oj = -angleSin * ci + angleCos * cj + oldJradius;

          oi1 = (int) oi;
          oj1 = (int) oj;

          // validate source pixel's coordinates
          if ((oi < 0) || (oj < 0) || (oi >= height) || (oj >= width)) {
            // fill destination image with filler
            destinationData.setRGB(i, j, fillRed, fillGreen, fillBlue);
          } else {

            di = oi - (double) oi1;
            dj = oj - (double) oj1;

            // initial pixel value
            int r = 0;
            int g = 0;
            int b = 0;

            for (int n = -1; n < 3; n++) {
              // get Y cooefficient
              k1 = Interpolation.BiCubicKernel(dj - (double) n);

              oj2 = oj1 + n;
              if (oj2 < 0) oj2 = 0;
              if (oj2 > jmax) oj2 = jmax;

              for (int m = -1; m < 3; m++) {
                // get X cooefficient
                k2 = k1 * Interpolation.BiCubicKernel((double) m - di);

                oi2 = oi1 + m;
                if (oi2 < 0) oi2 = 0;
                if (oi2 > imax) oi2 = imax;

                r += k2 * fastBitmap.getRed(oi2, oj2);
                g += k2 * fastBitmap.getGreen(oi2, oj2);
                b += k2 * fastBitmap.getBlue(oi2, oj2);
              }
            }

            r = Math.max(0, Math.min(255, r));
            g = Math.max(0, Math.min(255, g));
            b = Math.max(0, Math.min(255, b));
            destinationData.setRGB(i, j, r, g, b);
          }
          cj++;
        }
        ci++;
      }

      fastBitmap.setImage(destinationData);
      destinationData.recycle();
    }
  }
  @Override
  public void applyInPlace(FastBitmap fastBitmap) {

    int width = fastBitmap.getWidth();
    int height = fastBitmap.getHeight();
    int Xline, Yline;
    int lines = CalcLines(radius);
    int maxArray = lines * lines;
    int c;

    FastBitmap copy = new FastBitmap(fastBitmap);

    if (fastBitmap.isGrayscale()) {
      int[] avgL = new int[maxArray];
      for (int x = 0; x < height; x++) {
        for (int y = 0; y < width; y++) {
          c = 0;
          for (int i = 0; i < lines; i++) {
            Xline = x + (i - radius);
            for (int j = 0; j < lines; j++) {
              Yline = y + (j - radius);
              if ((Xline >= 0) && (Xline < height) && (Yline >= 0) && (Yline < width)) {
                avgL[c] = copy.getGray(Xline, Yline);
              } else {
                avgL[c] = copy.getGray(x, y);
              }
              c++;
            }
          }

          Arrays.sort(avgL);

          // alpha trimmed mean
          double mean = 0;
          for (int i = t; i < c - t; i++) {
            mean += avgL[i];
          }

          fastBitmap.setGray(x, y, (int) (mean / (avgL.length - 2 * t)));
        }
      }
    } else if (fastBitmap.isRGB()) {
      int[] avgR = new int[maxArray];
      int[] avgG = new int[maxArray];
      int[] avgB = new int[maxArray];

      for (int x = 0; x < height; x++) {
        for (int y = 0; y < width; y++) {
          c = 0;
          for (int i = 0; i < lines; i++) {
            Xline = x + (i - radius);
            for (int j = 0; j < lines; j++) {
              Yline = y + (j - radius);
              if ((Xline >= 0) && (Xline < height) && (Yline >= 0) && (Yline < width)) {
                avgR[c] = copy.getRed(Xline, Yline);
                avgG[c] = copy.getGreen(Xline, Yline);
                avgB[c] = copy.getBlue(Xline, Yline);
              } else {
                avgR[c] = copy.getRed(x, y);
                avgG[c] = copy.getGreen(x, y);
                avgB[c] = copy.getBlue(x, y);
              }
              c++;
            }
          }

          Arrays.sort(avgR);
          Arrays.sort(avgG);
          Arrays.sort(avgB);

          // alpha trimmed mean
          double meanR = 0, meanG = 0, meanB = 0;
          for (int i = t; i < c - t; i++) {
            meanR += avgR[i];
            meanG += avgG[i];
            meanB += avgB[i];
          }

          meanR /= (avgR.length - 2 * t);
          meanG /= (avgG.length - 2 * t);
          meanB /= (avgB.length - 2 * t);

          fastBitmap.setRGB(x, y, (int) meanR, (int) meanG, (int) meanB);
        }
      }
    }
  }
  @Override
  public void applyInPlace(FastBitmap fastBitmap) {

    int width = fastBitmap.getWidth();
    int height = fastBitmap.getHeight();
    int Xline, Yline;
    int radiusI = (weight.length - 1) / 2;
    int radiusJ = (weight[0].length - 1) / 2;
    int maxArray = calcMax(weight);
    int c;

    FastBitmap copy = new FastBitmap(fastBitmap);

    if (fastBitmap.isGrayscale()) {
      int[] avgL = new int[maxArray];
      int median;
      for (int x = 0; x < height; x++) {
        for (int y = 0; y < width; y++) {
          c = 0;
          for (int i = 0; i < weight.length; i++) {
            Xline = x + (i - radiusI);
            for (int j = 0; j < weight[0].length; j++) {
              Yline = y + (j - radiusJ);
              if ((Xline >= 0) && (Xline < height) && (Yline >= 0) && (Yline < width)) {
                if (weight[i][j] > 0) {
                  for (int k = 0; k < weight[i][j]; k++) {
                    avgL[c] = copy.getGray(Xline, Yline);
                    c++;
                  }
                }
              }
            }
          }
          Arrays.sort(avgL, 0, c);
          // median
          median = c / 2;
          fastBitmap.setGray(x, y, avgL[median]);
        }
      }
    } else if (fastBitmap.isRGB()) {
      int[] avgR = new int[maxArray];
      int[] avgG = new int[maxArray];
      int[] avgB = new int[maxArray];
      int median;

      for (int x = 0; x < height; x++) {
        for (int y = 0; y < width; y++) {
          c = 0;
          for (int i = 0; i < weight.length; i++) {
            Xline = x + (i - radiusI);
            for (int j = 0; j < weight[0].length; j++) {
              Yline = y + (j - radiusJ);
              if ((Xline >= 0) && (Xline < height) && (Yline >= 0) && (Yline < width)) {

                if (weight[i][j] > 0) {
                  for (int k = 0; k < weight[i][j]; k++) {
                    avgR[c] = copy.getRed(Xline, Yline);
                    avgG[c] = copy.getGreen(Xline, Yline);
                    avgB[c] = copy.getBlue(Xline, Yline);
                    c++;
                  }
                }
              }
            }
          }
          Arrays.sort(avgR, 0, c);
          Arrays.sort(avgG, 0, c);
          Arrays.sort(avgB, 0, c);
          // median
          median = c / 2;
          fastBitmap.setRGB(x, y, avgR[median], avgG[median], avgB[median]);
        }
      }
    }
  }
Exemple #9
0
  @Override
  public void applyInPlace(FastBitmap fastBitmap) {

    int width = fastBitmap.getWidth();
    int height = fastBitmap.getHeight();
    FastBitmap copy = new FastBitmap(fastBitmap);
    if (fastBitmap.isGrayscale()) {

      for (int x = 0; x < height; x++) {
        for (int y = 0; y < width; y++) {
          double mean = 0;
          double var = 0;
          int total = 0;
          for (int i = x - radius; i <= x + radius; i++) {
            for (int j = y - radius; j <= y + radius; j++) {
              if (i >= 0 && i < height && j >= 0 && j < width) {
                mean += copy.getGray(i, j);
                total++;
              }
            }
          }
          mean /= total;
          for (int i = x - radius; i <= x + radius; i++) {
            for (int j = y - radius; j <= y + radius; j++) {
              if (i >= 0 && i < height && j >= 0 && j < width)
                var += Math.pow(copy.getGray(i, j) - mean, 2);
            }
          }
          var /= total - 1;
          if (var < 0) var = 0;
          if (var > 255) var = 255;
          fastBitmap.setGray(x, y, (int) var);
        }
      }
    }
    if (fastBitmap.isRGB()) {

      for (int x = 0; x < height; x++) {
        for (int y = 0; y < width; y++) {
          double meanR = 0, meanG = 0, meanB = 0;
          double varR = 0, varG = 0, varB = 0;
          int total = 0;
          for (int i = x - radius; i <= x + radius; i++) {
            for (int j = y - radius; j <= y + radius; j++) {
              if (i >= 0 && i < height && j >= 0 && j < width) {
                meanR += copy.getRed(i, j);
                meanG += copy.getGreen(i, j);
                meanB += copy.getBlue(i, j);
                total++;
              }
            }
          }
          meanR /= total;
          meanG /= total;
          meanB /= total;
          for (int i = x - radius; i <= x + radius; i++) {
            for (int j = y - radius; j <= y + radius; j++) {
              if (i >= 0 && i < height && j >= 0 && j < width) {
                varR += Math.pow(copy.getRed(i, j) - meanR, 2);
                varG += Math.pow(copy.getGreen(i, j) - meanG, 2);
                varB += Math.pow(copy.getBlue(i, j) - meanB, 2);
              }
            }
          }
          varR /= total - 1;
          varG /= total - 1;
          varB /= total - 1;

          if (varR < 0) varR = 0;
          if (varG < 0) varG = 0;
          if (varB < 0) varB = 0;

          if (varR > 255) varR = 255;
          if (varG > 255) varG = 255;
          if (varB > 255) varB = 255;

          fastBitmap.setRGB(x, y, (int) varR, (int) varG, (int) varB);
        }
      }
    }
  }