private void calculateRaster() {
    amIActive = true;

    String inputHeader = null;
    String outputHeader = null;
    int col;
    int row;
    int numCols;
    int numRows;
    int a, i;
    float progress;
    int minValue, maxValue, range;
    boolean blnTextOutput = false;
    boolean zeroAsBackground = false;

    if (args.length <= 0) {
      showFeedback("Plugin parameters have not been set.");
      return;
    }

    inputHeader = args[0];
    outputHeader = args[1];
    blnTextOutput = Boolean.parseBoolean(args[2]);
    zeroAsBackground = Boolean.parseBoolean(args[3]);

    // check to see that the inputHeader and outputHeader are not null.
    if ((inputHeader == null) || (outputHeader == null)) {
      showFeedback("One or more of the input parameters have not been set properly.");
      return;
    }

    try {
      WhiteboxRaster image = new WhiteboxRaster(inputHeader, "r");

      numRows = image.getNumberRows();
      numCols = image.getNumberColumns();
      double noData = image.getNoDataValue();

      WhiteboxRaster output =
          new WhiteboxRaster(
              outputHeader, "rw", inputHeader, WhiteboxRaster.DataType.FLOAT, noData);
      output.setPreferredPalette("spectrum.pal");
      output.setDataScale(WhiteboxRaster.DataScale.CONTINUOUS);

      minValue = (int) (image.getMinimumValue());
      maxValue = (int) (image.getMaximumValue());
      range = maxValue - minValue;

      double[] data;
      // find the axis-aligned minimum bounding box.
      updateProgress("Loop 1 of 2:", 0);
      double[][] boundingBox = new double[6][range + 1];
      for (a = 0; a <= range; a++) {
        boundingBox[0][a] = Integer.MAX_VALUE; // west
        boundingBox[1][a] = Integer.MIN_VALUE; // east
        boundingBox[2][a] = Integer.MAX_VALUE; // north
        boundingBox[3][a] = Integer.MIN_VALUE; // south
      }

      for (row = 0; row < numRows; row++) {
        data = image.getRowValues(row);
        for (col = 0; col < numCols; col++) {
          if (data[col] != noData) {
            a = (int) (data[col] - minValue);
            if (col < boundingBox[0][a]) {
              boundingBox[0][a] = col;
            }
            if (col > boundingBox[1][a]) {
              boundingBox[1][a] = col;
            }
            if (row < boundingBox[2][a]) {
              boundingBox[2][a] = row;
            }
            if (row > boundingBox[3][a]) {
              boundingBox[3][a] = row;
            }
            boundingBox[5][a]++;
          }
        }
        if (cancelOp) {
          cancelOperation();
          return;
        }
        progress = (float) (100f * row / (numRows - 1));
        updateProgress("Loop 1 of 2:", (int) progress);
      }

      updateProgress("Loop 2 of 2:", 0);
      double radius;
      for (a = 0; a <= range; a++) {
        if ((boundingBox[1][a] - boundingBox[0][a] + 1)
            > (boundingBox[3][a] - boundingBox[2][a] + 1)) {
          radius = (boundingBox[1][a] - boundingBox[0][a] + 1) / 2;
        } else {
          radius = (boundingBox[3][a] - boundingBox[2][a] + 1) / 2;
        }
        boundingBox[4][a] = Math.PI * radius * radius;
      }

      if (zeroAsBackground) {
        boundingBox[0 - minValue][4] = 0d;
        // sum the column numbers and row numbers of each patch cell
        // along with the total number of cells.
        for (row = 0; row < numRows; row++) {
          data = image.getRowValues(row);
          for (col = 0; col < numCols; col++) {
            if (data[col] > 0) {
              a = (int) (data[col] - minValue);
              output.setValue(row, col, 1 - boundingBox[5][a] / boundingBox[4][a]);
            }
          }
          if (cancelOp) {
            cancelOperation();
            return;
          }
          progress = (float) (100f * row / (numRows - 1));
          updateProgress("Loop 2 of 2:", (int) progress);
        }
      } else {

        // sum the column numbers and row numbers of each patch cell
        // along with the total number of cells.
        for (row = 0; row < numRows; row++) {
          data = image.getRowValues(row);
          for (col = 0; col < numCols; col++) {
            if (data[col] != noData) {
              a = (int) (data[col] - minValue);
              output.setValue(row, col, 1 - boundingBox[5][a] / boundingBox[4][a]);
            }
          }
          if (cancelOp) {
            cancelOperation();
            return;
          }
          progress = (float) (100f * row / (numRows - 1));
          updateProgress("Loop 2 of 2:", (int) progress);
        }
      }

      output.addMetadataEntry("Created by the " + getDescriptiveName() + " tool.");
      output.addMetadataEntry("Created on " + new Date());

      image.close();
      output.close();

      if (blnTextOutput) {
        DecimalFormat df;
        df = new DecimalFormat("0.0000");

        String retstr = "Related Circumscribing Circle\nPatch ID\tValue";

        for (a = 0; a <= range; a++) {
          if (boundingBox[4][a] > 0) {
            retstr =
                retstr
                    + "\n"
                    + (a + minValue)
                    + "\t"
                    + df.format(1 - boundingBox[5][a] / boundingBox[4][a]);
          }
        }

        returnData(retstr);
      }

      // returning a header file string displays the image.
      returnData(outputHeader);

    } catch (OutOfMemoryError oe) {
      myHost.showFeedback("An out-of-memory error has occurred during operation.");
    } catch (Exception e) {
      myHost.showFeedback("An error has occurred during operation. See log file for details.");
      myHost.logException("Error in " + getDescriptiveName(), e);
    } finally {
      updateProgress("Progress: ", 0);
      // tells the main application that this process is completed.
      amIActive = false;
      myHost.pluginComplete();
    }
  }
  private void histogramMatching(String inputHeader1, String inputHeader2, String outputHeader) {

    // check to see that the inputHeader and outputHeader are not null.
    if (inputHeader1.isEmpty() || outputHeader.isEmpty() || inputHeader2.isEmpty()) {
      showFeedback("One or more of the input parameters have not been set properly.");
      return;
    }

    try {
      int row, col;
      double z;
      int progress = 0;
      int numCells1 = 0;
      int numCells2 = 0;
      int i = 0;

      WhiteboxRasterInfo inputFile1 = new WhiteboxRasterInfo(inputHeader1);
      int rows1 = inputFile1.getNumberRows();
      int cols1 = inputFile1.getNumberColumns();
      double noData1 = inputFile1.getNoDataValue();

      WhiteboxRasterInfo inputFile2 = new WhiteboxRasterInfo(inputHeader2);
      int rows2 = inputFile2.getNumberRows();
      int cols2 = inputFile2.getNumberColumns();
      double noData2 = inputFile2.getNoDataValue();

      WhiteboxRaster outputFile =
          new WhiteboxRaster(
              outputHeader, "rw", inputHeader1, WhiteboxRaster.DataType.FLOAT, noData1);
      outputFile.setPreferredPalette(inputFile1.getPreferredPalette());

      double minValue1 = inputFile1.getMinimumValue();
      double maxValue1 = inputFile1.getMaximumValue();
      int numBins1 =
          Math.max(
              2 * (int) Math.ceil(maxValue1 - minValue1 + 1),
              (int) Math.ceil(Math.pow(rows1 * cols1, 1.0 / 3)));
      double binSize = (maxValue1 - minValue1) / numBins1;
      long[] histogram = new long[numBins1];
      int binNum;
      int numBinsLessOne1 = numBins1 - 1;
      double[] data;

      updateProgress("Histogram matching: ", 0);
      for (row = 0; row < rows1; row++) {
        data = inputFile1.getRowValues(row);
        for (col = 0; col < cols1; col++) {
          z = data[col];
          if (z != noData1) {
            numCells1++;
            binNum = (int) ((z - minValue1) / binSize);
            if (binNum > numBinsLessOne1) {
              binNum = numBinsLessOne1;
            }
            histogram[binNum]++;
          }
        }
        if (cancelOp) {
          cancelOperation();
          return;
        }
        progress = (int) (100f * row / (rows1 - 1));
        updateProgress("Histogram matching: ", progress);
      }

      updateProgress("Histogram matching: ", 0);

      double[] cdf = new double[numBins1];
      cdf[0] = histogram[0];
      for (i = 1; i < numBins1; i++) {
        cdf[i] = cdf[i - 1] + histogram[i];
      }

      for (i = 0; i < numBins1; i++) {
        cdf[i] = cdf[i] / numCells1;
      }

      double minValue2 = inputFile2.getMinimumValue();
      double maxValue2 = inputFile2.getMaximumValue();

      int numBins2 =
          Math.max(
              2 * (int) Math.ceil(maxValue2 - minValue2 + 1),
              (int) Math.ceil(Math.pow(rows2 * cols2, 1.0 / 3)));
      int numBinsLessOne2 = numBins2 - 1;
      long[] histogram2 = new long[numBins2];
      double[][] referenceCDF = new double[numBins2][2];

      for (row = 0; row < rows2; row++) {
        data = inputFile2.getRowValues(row);
        for (col = 0; col < cols2; col++) {
          z = data[col];
          if (z != noData2) {
            numCells2++;
            binNum = (int) ((z - minValue2) / binSize);
            if (binNum > numBinsLessOne2) {
              binNum = numBinsLessOne2;
            }
            histogram2[binNum]++;
          }
        }
        if (cancelOp) {
          cancelOperation();
          return;
        }
        progress = (int) (100f * row / (rows1 - 1));
        updateProgress("Histogram matching: ", progress);
      }

      // convert the reference histogram to a cdf.
      referenceCDF[0][1] = histogram2[0];
      for (i = 1; i < numBins2; i++) {
        referenceCDF[i][1] = referenceCDF[i - 1][1] + histogram2[i];
      }

      for (i = 0; i < numBins2; i++) {
        referenceCDF[i][0] = minValue2 + (i / (float) numBins2) * (maxValue2 - minValue2);
        referenceCDF[i][1] = referenceCDF[i][1] / numCells2;
      }

      int[] startingVals = new int[11];
      double pVal = 0;
      for (i = 0; i < numBins2; i++) {
        pVal = referenceCDF[i][1];
        if (pVal < 0.1) {
          startingVals[1] = i;
        }
        if (pVal < 0.2) {
          startingVals[2] = i;
        }
        if (pVal < 0.3) {
          startingVals[3] = i;
        }
        if (pVal < 0.4) {
          startingVals[4] = i;
        }
        if (pVal < 0.5) {
          startingVals[5] = i;
        }
        if (pVal < 0.6) {
          startingVals[6] = i;
        }
        if (pVal < 0.7) {
          startingVals[7] = i;
        }
        if (pVal < 0.8) {
          startingVals[8] = i;
        }
        if (pVal < 0.9) {
          startingVals[9] = i;
        }
        if (pVal <= 1) {
          startingVals[10] = i;
        }
      }

      updateProgress("Histogram matching: ", 0);
      int j = 0;
      double xVal = 0;
      double x1, x2, p1, p2;
      for (row = 0; row < rows1; row++) {
        data = inputFile1.getRowValues(row);
        for (col = 0; col < cols1; col++) {
          z = data[col];
          if (z != noData1) {
            binNum = (int) ((z - minValue1) / binSize);
            if (binNum > numBinsLessOne1) {
              binNum = numBinsLessOne1;
            }
            pVal = cdf[binNum];
            j = (int) (Math.floor(pVal * 10));
            for (i = startingVals[j]; i < numBins2; i++) {
              if (referenceCDF[i][1] > pVal) {
                if (i > 0) {
                  x1 = referenceCDF[i - 1][0];
                  x2 = referenceCDF[i][0];
                  p1 = referenceCDF[i - 1][1];
                  p2 = referenceCDF[i][1];
                  if (p1 != p2) {
                    xVal = x1 + ((x2 - x1) * ((pVal - p1) / (p2 - p1)));
                  } else {
                    xVal = x1;
                  }
                } else {
                  xVal = referenceCDF[i][0];
                }
                break;
              }
            }

            outputFile.setValue(row, col, xVal);
          }
        }

        if (cancelOp) {
          cancelOperation();
          return;
        }
        progress = (int) (100f * row / (rows1 - 1));
        updateProgress("Histogram matching: ", progress);
      }

      inputFile1.close();
      outputFile.close();

    } catch (OutOfMemoryError oe) {
      myHost.showFeedback("An out-of-memory error has occurred during operation.");
    } catch (Exception e) {
      myHost.showFeedback("An error has occurred during operation. See log file for details.");
      myHost.logException("Error in " + getDescriptiveName(), e);
    } finally {
      updateProgress("Progress: ", 0);
    }
  }