All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgrasstools.gears.modules.r.filter.OmsKernelFilter Maven / Gradle / Ivy

The newest version!
package org.jgrasstools.gears.modules.r.filter;
import static org.jgrasstools.gears.libs.modules.JGTConstants.isNovalue;
import static org.jgrasstools.gears.libs.modules.Variables.BINARY;
import static org.jgrasstools.gears.libs.modules.Variables.COSINE;
import static org.jgrasstools.gears.libs.modules.Variables.DISTANCE;
import static org.jgrasstools.gears.libs.modules.Variables.EPANECHNIKOV;
import static org.jgrasstools.gears.libs.modules.Variables.GAUSSIAN;
import static org.jgrasstools.gears.libs.modules.Variables.INVERSE_DISTANCE;
import static org.jgrasstools.gears.libs.modules.Variables.QUARTIC;
import static org.jgrasstools.gears.libs.modules.Variables.TRIANGULAR;
import static org.jgrasstools.gears.libs.modules.Variables.TRIWEIGHT;

import java.awt.image.RenderedImage;
import java.awt.image.WritableRaster;

import javax.media.jai.KernelJAI;
import javax.media.jai.iterator.RandomIter;
import javax.media.jai.iterator.RandomIterFactory;
import javax.media.jai.iterator.WritableRandomIter;

import oms3.annotations.Author;
import oms3.annotations.Description;
import oms3.annotations.In;
import oms3.annotations.Keywords;
import oms3.annotations.Label;
import oms3.annotations.License;
import oms3.annotations.Name;
import oms3.annotations.Out;
import oms3.annotations.Status;
import oms3.annotations.UI;

import org.geotools.coverage.grid.GridCoverage2D;
import org.jaitools.media.jai.kernel.KernelFactory;
import org.jaitools.media.jai.kernel.KernelFactory.ValueType;
import org.jgrasstools.gears.libs.exceptions.ModelsIllegalargumentException;
import org.jgrasstools.gears.libs.modules.JGTConstants;
import org.jgrasstools.gears.libs.modules.JGTModel;
import org.jgrasstools.gears.utils.RegionMap;
import org.jgrasstools.gears.utils.coverage.CoverageUtilities;

@Description("A Kernel based filter.")
@Author(name = "Andrea Antonello, Silvia Franceschi", contact = "www.hydrologis.com")
@Keywords("kernel, filter, raster")
@Label(JGTConstants.RASTERPROCESSING)
@Name("kernelfilter")
@Status(Status.EXPERIMENTAL)
@License(JGTConstants.GPL3_LICENSE)
public class OmsKernelFilter extends JGTModel {
    @Description("An input raster")
    @In
    public GridCoverage2D inRaster;

    @Description("The kernel to use.")
    @UI("combo:" + BINARY + "," + COSINE + "," + DISTANCE + "," //
            + EPANECHNIKOV + "," + GAUSSIAN + "," + INVERSE_DISTANCE + "," //
            + QUARTIC + "," + TRIANGULAR + "," + TRIWEIGHT)
    @In
    public String pKernel = EPANECHNIKOV;

    @Description("The kernel radius to use in cells (default = 10).")
    @In
    public int pRadius = 10;

    @Description("Filtered raster")
    @Out
    public GridCoverage2D outRaster;

    public void process() throws Exception {
        checkNull(inRaster);

        RegionMap regionMap = CoverageUtilities.getRegionParamsFromGridCoverage(inRaster);
        int cols = regionMap.getCols();
        int rows = regionMap.getRows();

        ValueType type = getKernelType(pKernel);

        KernelJAI kernel = KernelFactory.createCircle(pRadius, type);

        RenderedImage inImg = inRaster.getRenderedImage();
        RandomIter inIter = RandomIterFactory.create(inImg, null);

        WritableRaster outWR = CoverageUtilities.createDoubleWritableRaster(cols, rows, null, null, JGTConstants.doubleNovalue);
        WritableRandomIter outIter = RandomIterFactory.createWritable(outWR, null);

        float[] kernelData = kernel.getKernelData();
        pm.beginTask("Processing...", cols - 2 * pRadius);
        for( int c = pRadius; c < cols - pRadius; c++ ) {
            for( int r = pRadius; r < rows - pRadius; r++ ) {
                double kernelSum = 0.0;
                int k = 0;
                double outputValue = 0.0;
                for( int kc = -pRadius; kc <= pRadius; kc++ ) {
                    for( int kr = -pRadius; kr <= pRadius; kr++, k++ ) {
                        double value = inIter.getSampleDouble(c + kc, r + kr, 0);
                        if (!isNovalue(value)) {
                            outputValue = outputValue + value * kernelData[k];
                            kernelSum = kernelSum + kernelData[k];
                        }
                    }
                }
                outIter.setSample(c, r, 0, outputValue / kernelSum);
            }
            pm.worked(1);
        }
        pm.done();

        outRaster = CoverageUtilities.buildCoverage("filtered", outWR, regionMap, inRaster.getCoordinateReferenceSystem());
    }

    private static ValueType getKernelType( String pKernel2 ) {
        ValueType type = null;
        pKernel2 = pKernel2.trim();
        if (pKernel2.equals(BINARY)) {
            type = KernelFactory.ValueType.BINARY;
        } else if (pKernel2.equals(COSINE)) {
            type = KernelFactory.ValueType.COSINE;
        } else if (pKernel2.equals(DISTANCE)) {
            type = KernelFactory.ValueType.DISTANCE;
        } else if (pKernel2.equals(GAUSSIAN)) {
            type = KernelFactory.ValueType.GAUSSIAN;
        } else if (pKernel2.equals(INVERSE_DISTANCE)) {
            type = KernelFactory.ValueType.INVERSE_DISTANCE;
        } else if (pKernel2.equals(QUARTIC)) {
            type = KernelFactory.ValueType.QUARTIC;
        } else if (pKernel2.equals(TRIANGULAR)) {
            type = KernelFactory.ValueType.TRIANGULAR;
        } else if (pKernel2.equals(TRIWEIGHT)) {
            type = KernelFactory.ValueType.TRIWEIGHT;
        } else if (pKernel2.equals(EPANECHNIKOV)) {
            type = KernelFactory.ValueType.EPANECHNIKOV;
        } else {
            throw new ModelsIllegalargumentException("Kernel type not recognised: " + pKernel2, "OmsKernelFilter");
        }
        return type;
    }
    /**
     * Smooth an array of values with a gaussian blur.
     * 
     * @param values the values to smooth.
     * @param kernelRadius the radius of the kernel to use.
     * @return the smoothed values.
     * @throws Exception
     */
    public static double[] gaussianSmooth( double[] values, int kernelRadius ) throws Exception {
        int size = values.length;
        double[] newValues = new double[values.length];
        double[] kernelData2D = makeGaussianKernel(kernelRadius);
        for( int i = 0; i < kernelRadius; i++ ) {
            newValues[i] = values[i];
        }
        for( int r = kernelRadius; r < size - kernelRadius; r++ ) {
            double kernelSum = 0.0;
            double outputValue = 0.0;
            int k = 0;
            for( int kc = -kernelRadius; kc <= kernelRadius; kc++, k++ ) {
                double value = values[r + kc];
                if (!isNovalue(value)) {
                    outputValue = outputValue + value * kernelData2D[k];
                    kernelSum = kernelSum + kernelData2D[k];
                }
            }
            newValues[r] = outputValue / kernelSum;
        }
        for( int i = size - kernelRadius; i < size; i++ ) {
            newValues[i] = values[i];
        }
        return newValues;
    }

    /**
     * Smooth an array of values with an averaging moving window.
     * 
     * @param values the values to smooth.
     * @param lookAhead the size of half of the window. 
     * @return the smoothed values.
     * @throws Exception
     */
    public static double[] averageSmooth( double[] values, int lookAhead ) throws Exception {
        int size = values.length;
        double[] newValues = new double[values.length];
        for( int i = 0; i < lookAhead; i++ ) {
            newValues[i] = values[i];
        }
        for( int i = lookAhead; i < size - lookAhead; i++ ) {
            double sum = 0.0;
            int k = 0;
            for( int l = -lookAhead; l <= lookAhead; l++ ) {
                double value = values[i + l];
                if (!isNovalue(value)) {
                    sum = sum + value;
                    k++;
                }
            }
            newValues[i] = sum / k;
        }
        for( int i = size - lookAhead; i < size; i++ ) {
            newValues[i] = values[i];
        }
        return newValues;
    }

    /**
     * Make a Gaussian blur kernel.
     */
    public static double[] makeGaussianKernel( int radius ) {
        int rows = radius * 2 + 1;
        double r = (double) radius;
        double[] matrix = new double[rows];
        double sigma = r / 3;
        double sigma22 = 2 * sigma * sigma;
        double sigmaPi2 = 2 * Math.PI * sigma;
        double sqrtSigmaPi2 = Math.sqrt(sigmaPi2);
        double radius2 = r * r;
        double total = 0;
        int index = 0;
        for( int row = -radius; row <= radius; row++ ) {
            double distance = row * row;
            if (distance > radius2)
                matrix[index] = 0;
            else
                matrix[index] = (double) Math.exp(-(distance) / sigma22) / sqrtSigmaPi2;
            total += matrix[index];
            index++;
        }
        for( int i = 0; i < rows; i++ )
            matrix[i] /= total;

        return matrix;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy