Commit 8c59bde1 authored by mey's avatar mey
Browse files

added BasicMorphOp.java: with nested classes Erode and Dilate

added interface GridFilteringOp.java
added AbstractGridFilteringOp.java
    extracted basic workings from ConvolveOp
renamed ConvolvingPotentialMap to FilteringPotentialMap.java
    updated to accept less specific interface GridFilteringOp
        instead of ConvolveOp
    renamed test
ConvolveOp.java
    extends from AbstractFilteringOp
Kernel.java, de.zmt.pathfinding.filter.package-info.java
    improved doc
parent 92293bc4
package de.zmt.pathfinding;
import de.zmt.pathfinding.filter.ConvolveOp;
import de.zmt.pathfinding.filter.GridFilteringOp;
import sim.display.GUIState;
import sim.field.grid.DoubleGrid2D;
import sim.portrayal.Inspector;
......@@ -11,35 +11,33 @@ import sim.portrayal.portrayable.ProvidesPortrayable;
/**
* Implementation of a {@link AbstractDynamicMap} that will run a
* {@link ConvolveOp} when updated. For example, this can be used to create a
* blurred version of a changing map.
* {@link GridFilteringOp} when updated. For example, this can be used to create
* a blurred version of a changing map.
*
* @author mey
*
*/
public class ConvolvingPotentialMap extends AbstractDynamicMap implements GridBackedPotentialMap,
public class FilteringPotentialMap extends AbstractDynamicMap implements GridBackedPotentialMap,
EdgeHandledPotentialMap, ProvidesPortrayable<FieldPortrayable<DoubleGrid2D>>, ProvidesInspector {
private static final long serialVersionUID = 1L;
private final DoubleGrid2D mapGrid;
private final ConvolveOp convolveOp;
private final GridFilteringOp filteringOp;
private final DoubleGrid2D src;
/**
* Constructs a new {@link ConvolvingPotentialMap} with default
* {@link EdgeHandler}.
* Constructs a new {@link FilteringPotentialMap} with given filtering op.
*
* @param convolveOp
* the {@link ConvolveOp} to be used
* @param filteringOp
* the {@link GridFilteringOp} to be used
* @param src
* the source for the convolution
* the source for the filtering
*/
public ConvolvingPotentialMap(ConvolveOp convolveOp, DoubleGrid2D src) {
public FilteringPotentialMap(GridFilteringOp filteringOp, DoubleGrid2D src) {
// extends equal origin positions
super(src.getWidth(), src.getHeight(), convolveOp.getKernel().getxOrigin(),
convolveOp.getKernel().getyOrigin());
super(src.getWidth(), src.getHeight(), filteringOp.getxExtend(), filteringOp.getyExtend());
this.mapGrid = new DoubleGrid2D(src.getWidth(), src.getHeight());
this.convolveOp = convolveOp;
this.filteringOp = filteringOp;
this.src = src;
forceUpdateAll();
}
......@@ -56,16 +54,16 @@ public class ConvolvingPotentialMap extends AbstractDynamicMap implements GridBa
}
/**
* Updates given location by running the convolve operation on it.
* Updates given location by running the filtering operation on it.
*/
@Override
protected void update(int x, int y) {
mapGrid.set(x, y, convolveOp.filter(x, y, src));
mapGrid.set(x, y, filteringOp.filter(x, y, src));
}
@Override
public EdgeHandler getEdgeHandler() {
return convolveOp.getEdgeHandler();
return filteringOp.getEdgeHandler();
}
/**
......
package de.zmt.pathfinding.filter;
import de.zmt.pathfinding.EdgeHandler;
import sim.field.grid.BooleanGrid;
import sim.field.grid.DoubleGrid2D;
/**
* Skeletal implementation of a {@link GridFilteringOp}.
*
* @author mey
*
*/
abstract class AbstractGridFilteringOp implements GridFilteringOp {
private final EdgeHandler edgeHandler;
/**
* Constructs a new {@link AbstractGridFilteringOp} with
* {@link EdgeHandler#getDefault()}.
*/
public AbstractGridFilteringOp() {
this.edgeHandler = EdgeHandler.getDefault();
}
/**
* Constructs a new {@link AbstractGridFilteringOp}. For handling grid edges the
* given {@link EdgeHandler} is used.
*
* @param edgeHandler
* the edge handler to be used
*/
public AbstractGridFilteringOp(EdgeHandler edgeHandler) {
super();
this.edgeHandler = edgeHandler;
}
/**
* Performs a filtering operation on a DoubleGrid2D. Each cell of the source
* grid will be filtered. The results are written into a copy of {@code src}
* and returned .
*
* @param src
* the source grid
* @return the resulting grid
*/
public DoubleGrid2D filter(DoubleGrid2D src) {
return filter(src, null, null);
}
/**
* Performs a filtering operation on a DoubleGrid2D. Each cell of the source
* grid will be filtered. The results are written into a copy of {@code src}
* and returned.
*
* @param src
* the source grid
* @param dest
* the destination for filtered {@code src} or <code>null</code>
* @return the resulting grid {@code dest}
*/
public DoubleGrid2D filter(DoubleGrid2D src, DoubleGrid2D dest) {
return filter(src, dest, null);
}
/**
* Performs a filtering operation only on the cells that are marked with a
* flag. If the destination grid is <code>null</code> a copy of {@code src}
* will be created and used as destination.
*
* @param src
* the source grid
* @param selection
* the selection grid containing a flag for every cell if it is
* to be included in the filtering operation
* @return the resulting grid {@code dest}
*/
public DoubleGrid2D filter(DoubleGrid2D src, BooleanGrid selection) {
return filter(src, null, selection);
}
/**
* Performs a filtering operation only on the cells that are marked with a
* flag. If the destination grid is <code>null</code> a copy of {@code src}
* will be created and used as destination.
*
* @param src
* the source grid
* @param dest
* the destination for filtered {@code src} or <code>null</code>
* @param selection
* the selection grid containing a flag for every cell if it is
* to be included in the filtering operation
* @return the resulting grid {@code dest}
*/
public DoubleGrid2D filter(DoubleGrid2D src, DoubleGrid2D dest, BooleanGrid selection) {
if (src == dest) {
throw new IllegalArgumentException("Source and destination grids must not be different objects.");
}
int width = src.getWidth();
int height = src.getHeight();
if (dest == null) {
dest = new DoubleGrid2D(src);
}
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (selection == null || selection.get(x, y)) {
dest.set(x, y, filter(x, y, src));
}
// not selected, copy from source
else {
dest.set(x, y, src.get(x, y));
}
}
}
return dest;
}
@Override
public abstract double filter(int x, int y, DoubleGrid2D src);
@Override
public abstract int getxExtend();
@Override
public abstract int getyExtend();
@Override
public EdgeHandler getEdgeHandler() {
return edgeHandler;
}
}
\ No newline at end of file
package de.zmt.pathfinding.filter;
import de.zmt.pathfinding.EdgeHandler;
import sim.field.grid.DoubleGrid2D;
/**
* Abstract super class for the basic morph operations {@link Dilate} and
* {@link Erode}.
*
* @author mey
*
*/
public abstract class BasicMorphOp extends AbstractGridFilteringOp {
private static final Dilate DEFAULT_DILATE_INSTANCE = new Dilate();
private static final Erode DEFAULT_ERODE_INSTANCE = new Erode();
/**
* Constructs a new {@link BasicMorphOp} with
* {@link EdgeHandler#getDefault()}.
*/
private BasicMorphOp() {
super();
}
/**
* Constructs a new {@link BasicMorphOp}. For handling grid edges the given
* {@link EdgeHandler} is used.
*
* @param edgeHandler
* the edge handler to be used
*/
private BasicMorphOp(EdgeHandler edgeHandler) {
super(edgeHandler);
}
abstract double updateResult(double result, double value);
@Override
public double filter(int x, int y, DoubleGrid2D src) {
double result = src.get(x, y);
for (int i = x - 1; i <= x + 1; i++) {
for (int j = y - 1; j <= y + 1; j++) {
double value = getEdgeHandler().getValue(src, i, j);
result = updateResult(result, value);
}
}
return result;
}
@Override
public int getxExtend() {
return 1;
}
@Override
public int getyExtend() {
return 1;
}
/**
* Returns the default {@link Dilate} instance with
* {@link EdgeHandler#getDefault()}.
*
* @return the default {@link Dilate} instance
*/
public static Dilate getDefaultDilate() {
return DEFAULT_DILATE_INSTANCE;
}
/**
* Returns the default {@link Erode} instance with
* {@link EdgeHandler#getDefault()}.
*
* @return the default {@link Erode} instance
*/
public static Erode getDefaultErode() {
return DEFAULT_ERODE_INSTANCE;
}
/**
* A filtering operation that grows areas with higher values. It will set
* every grid cell to the value of its highest neighbor or keep its value if
* already highest.
*
* @author mey
*
*/
public static class Dilate extends BasicMorphOp {
/**
* Constructs a new {@link Dilate} object with
* {@link EdgeHandler#getDefault()}.
*/
private Dilate() {
super();
}
/**
* Constructs a new {@link Dilate} object. For handling grid edges the
* given {@link EdgeHandler} is used.
*
* @param edgeHandler
* the edge handler to be used
*/
public Dilate(EdgeHandler edgeHandler) {
super(edgeHandler);
}
@Override
double updateResult(double result, double value) {
return Math.max(value, result);
}
}
/**
* A filtering operation that shrinks areas with higher values. It will set
* every grid cell to the value of its lowest neighbor or keep its value if
* already lowest.
*
* @author mey
*
*/
public static class Erode extends BasicMorphOp {
/**
* Constructs a new {@link Erode} object with
* {@link EdgeHandler#getDefault()}.
*/
private Erode() {
super();
}
/**
* Constructs a new {@link Erode} object. For handling grid edges the
* given {@link EdgeHandler} is used.
*
* @param edgeHandler
* the edge handler to be used
*/
public Erode(EdgeHandler edgeHandler) {
super(edgeHandler);
}
@Override
double updateResult(double result, double value) {
return Math.min(value, result);
}
}
}
......@@ -3,12 +3,10 @@ package de.zmt.pathfinding.filter;
import java.io.Serializable;
import de.zmt.pathfinding.EdgeHandler;
import sim.field.grid.BooleanGrid;
import sim.field.grid.DoubleGrid2D;
/**
* A convolution from source to destination working with double grids. Values at
* the edges from the grid are extended if the kernel matrix is beyond borders.
* A convolution from source to destination working with double grids.
* <p>
* Unfortunately java's own ConvolveOp is only suitable for images and does not
* support floating point data, even when packed into a custom image. Apart from
......@@ -20,12 +18,10 @@ import sim.field.grid.DoubleGrid2D;
* @author mey
*
*/
public class ConvolveOp implements Serializable {
public class ConvolveOp extends AbstractGridFilteringOp implements Serializable {
private static final long serialVersionUID = 1L;
private final Kernel kernel;
private final EdgeHandler edgeHandler;
/**
* Constructs a new {@link ConvolveOp} with {@link EdgeHandler#getDefault()}
* .
......@@ -36,7 +32,6 @@ public class ConvolveOp implements Serializable {
public ConvolveOp(Kernel kernel) {
super();
this.kernel = kernel;
this.edgeHandler = EdgeHandler.getDefault();
}
/**
......@@ -46,129 +41,42 @@ public class ConvolveOp implements Serializable {
* @param kernel
* the kernel used for the convolve operation
* @param edgeHandler
* the edge hanlder to be used
* the edge handler to be used
*/
public ConvolveOp(Kernel kernel, EdgeHandler edgeHandler) {
super();
super(edgeHandler);
this.kernel = kernel;
this.edgeHandler = edgeHandler;
}
/**
* Performs a convolution on a DoubleGrid2D. Each cell of the source grid
* will be convolved. The results are written into a copy of {@code src} and
* returned .
*
* @param src
* the source grid
* @return the resulting grid
*/
public DoubleGrid2D filter(DoubleGrid2D src) {
return filter(src, null, null);
}
/**
* Performs a convolution on a DoubleGrid2D. Each cell of the source grid
* will be convolved. The results are written into a copy of {@code src} and
* returned.
*
* @param src
* the source grid
* @param dest
* the destination for filtered {@code src} or <code>null</code>
* @return the resulting grid {@code dest}
*/
public DoubleGrid2D filter(DoubleGrid2D src, DoubleGrid2D dest) {
return filter(src, dest, null);
}
/**
* Performs a convolution only on the cells that are marked with a flag. If
* the destination grid is <code>null</code> a copy of {@code src} will be
* created and used as destination.
*
* @param src
* the source grid
* @param include
* the include grid containing a flag for every cell if it is to
* be included in the convolution
* @return the resulting grid {@code dest}
*/
public DoubleGrid2D filter(DoubleGrid2D src, BooleanGrid include) {
return filter(src, null, include);
}
/**
* Performs a convolution only on the cells that are marked with a flag. If
* the destination grid is <code>null</code> a copy of {@code src} will be
* created and used as destination.
*
* @param src
* the source grid
* @param dest
* the destination for filtered {@code src} or <code>null</code>
* @param include
* the include grid containing a flag for every cell if it is to
* be included in the convolution
* @return the resulting grid {@code dest}
*/
public DoubleGrid2D filter(DoubleGrid2D src, DoubleGrid2D dest, BooleanGrid include) {
if (src == dest) {
throw new IllegalArgumentException("Source and destination grids must not be different objects.");
}
int width = src.getWidth();
int height = src.getHeight();
if (dest == null) {
dest = new DoubleGrid2D(src);
}
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
if (include == null || include.get(x, y)) {
dest.set(x, y, filter(x, y, src));
}
// not included, copy from source
else {
dest.set(x, y, src.get(x, y));
}
}
}
return dest;
public Kernel getKernel() {
return kernel;
}
/**
* Convolves a single cell on the grid.
*
* @param x
* @param y
* @param src
* @return the convoluted value for that cell
*/
@Override
public double filter(int x, int y, DoubleGrid2D src) {
double result = 0;
for (int i = 0; i < kernel.getWidth(); i++) {
for (int j = 0; j < kernel.getHeight(); j++) {
double weight = kernel.getWeight(i, j);
int fieldX = x + i - kernel.getxOrigin();
int fieldY = y + j - kernel.getyOrigin();
int gridX = x + i - kernel.getxOrigin();
int gridY = y + j - kernel.getyOrigin();
// extend the field on borders
double value = edgeHandler.getValue(src, fieldX, fieldY);
// handle edges according to edge handler
double value = getEdgeHandler().getValue(src, gridX, gridY);
result += value * weight;
}
}
return result;
}
public Kernel getKernel() {
return kernel;
@Override
public int getxExtend() {
return kernel.getxOrigin();
}
public EdgeHandler getEdgeHandler() {
return edgeHandler;
@Override
public int getyExtend() {
return kernel.getyOrigin();
}
@Override
......
package de.zmt.pathfinding.filter;
import de.zmt.pathfinding.EdgeHandler;
import sim.field.grid.DoubleGrid2D;
/**
* A filtering operation from source to destination {@link DoubleGrid2D}.
*
* @author mey
*
*/
public interface GridFilteringOp {
/**
* Performs a filtering operation on a single grid cell.
*
* @param x
* the x-coordinate of the cell
* @param y
* the y-coordinate of the cell
* @param src
* the source grid
* @return the filtered value for that cell
*/
double filter(int x, int y, DoubleGrid2D src);
/**
* Returns the x-extend of the filtering operation. For example, if the
* operation takes only the direct neighbors into account both extends are
* 1.
*
* @return the x-extend of the filtering operation
*/
int getxExtend();
/**
* Returns the y-extend of the filtering operation. For example, if the
* operation takes only the direct neighbors into account both extends are
* 1.
*
* @return the y-extend of the filtering operation
*/
int getyExtend();
/**
* Returns the {@link EdgeHandler} for this operation.
*
* @return the {@link EdgeHandler} for this operation
*/
EdgeHandler getEdgeHandler();
}
\ No newline at end of file
......@@ -126,8 +126,8 @@ public class Kernel implements Serializable {
}
/**
* Returns a neutral kernel to be used in convolve operations that does not
* change the grid. Can also be used for scaling operations with
* Returns the neutral kernel. If used in itself in a convolution it will
* not change the grid. Useful for scaling operations with
* {@link #multiply(double)}.