From 376f75c4f91c32744e484af6aefbd5d311609976 Mon Sep 17 00:00:00 2001 From: Benedikt Zoennchen Date: Tue, 24 Oct 2017 14:36:28 +0200 Subject: [PATCH] OpenCL bug-fix: memory leaks. --- .../utils/CLGaussianCalculator.java | 133 ++++---- .../components/view/SimulationRenderer.java | 317 +++++++++--------- .../models/density/CLGaussianFilter.java | 26 +- .../models/density/GaussianFilter.java | 219 ++++++------ .../models/density/IGaussianFilter.java | 231 ++++++------- .../models/density/JGaussianFilter.java | 3 + .../density/ObstacleGaussianFilter.java | 191 ++++++----- .../density/PedestrianGaussianFilter.java | 312 ++++++++--------- .../models/queuing/QueueDetector.java | 189 +++++------ VadereUtils/resources/Convolve.cl | 69 +++- .../org/vadere/util/opencl/CLConvolution.java | 294 +++++++++------- .../src/org/vadere/util/opencl/CLUtils.java | 3 + .../org/vadere/util/math/TestConvolution.java | 29 +- 13 files changed, 1086 insertions(+), 930 deletions(-) diff --git a/VadereGui/src/org/vadere/gui/components/utils/CLGaussianCalculator.java b/VadereGui/src/org/vadere/gui/components/utils/CLGaussianCalculator.java index b47e78b92..9080623a0 100644 --- a/VadereGui/src/org/vadere/gui/components/utils/CLGaussianCalculator.java +++ b/VadereGui/src/org/vadere/gui/components/utils/CLGaussianCalculator.java @@ -11,63 +11,64 @@ import org.vadere.state.attributes.scenario.AttributesAgent; public class CLGaussianCalculator { - private final double scale; - private final int scenarioWidth; - private final int scenarioHeight; - private SimulationModel model; + private final double scale; + private final int scenarioWidth; + private final int scenarioHeight; + private SimulationModel model; - private IGaussianFilter filterObstacles; + private IGaussianFilter filterObstacles; + private IGaussianFilter filterPedestrians; - public CLGaussianCalculator(final SimulationModel model, - final double scale, - final double measurementRadius, - final Color color, - final boolean visualisation, - final boolean scenarioBound) { + public CLGaussianCalculator(final SimulationModel model, + final double scale, + final double measurementRadius, + final Color color, + final boolean visualisation, + final boolean scenarioBound) { - this.scenarioWidth = (int) model.getTopographyBound().getWidth(); - this.scenarioHeight = (int) model.getTopographyBound().getHeight(); - this.scale = scale; - this.model = model; - this.filterObstacles = IGaussianFilter.create(model.getTopography(), scale, model.getTopography().isBounded(), - 0.7, IGaussianFilter.Type.OpenCL); - } + this.scenarioWidth = (int) model.getTopographyBound().getWidth(); + this.scenarioHeight = (int) model.getTopographyBound().getHeight(); + this.scale = scale; + this.model = model; + this.filterObstacles = IGaussianFilter.create(model.getTopography(), scale, model.getTopography().isBounded(), + 0.7, IGaussianFilter.Type.OpenCL); + } - public BufferedImage getDensityImage() { - IGaussianFilter filterPedestrians = IGaussianFilter.create( - model.getTopography().getBounds(), - model.getAgents(), - scale, - 0.7f, - new AttributesAgent(-1), - (ped) -> 1.0, - IGaussianFilter.Type.OpenCL); - filterPedestrians.filterImage(); - filterObstacles.filterImage(); + public BufferedImage getDensityImage() { + IGaussianFilter filterPedestrians = IGaussianFilter.create( + model.getTopography().getBounds(), + model.getAgents(), + scale, + 0.7f, + new AttributesAgent(-1), + (ped) -> 1.0, + IGaussianFilter.Type.OpenCL); + filterPedestrians.filterImage(); + filterObstacles.filterImage(); + filterPedestrians.destroy(); + return convertFilterToImage(filterPedestrians, filterObstacles); + } - return convertFilterToImage(filterPedestrians, filterObstacles); - } + private BufferedImage convertFilterToImage(final IGaussianFilter filterPedestrians, + final IGaussianFilter filterObstacles) { + int width = Math.max(filterObstacles.getMatrixWidth(), filterPedestrians.getMatrixWidth()); + int height = Math.max(filterObstacles.getMatrixHeight(), filterPedestrians.getMatrixHeight()); + BufferedImage image = createImage(width, height); + int maxColorValue = 255 * 255 * 255; + ColorHelper colorHelper = new ColorHelper(maxColorValue); - private BufferedImage convertFilterToImage(final IGaussianFilter filterPedestrians, - final IGaussianFilter filterObstacles) { - int width = Math.max(filterObstacles.getMatrixWidth(), filterPedestrians.getMatrixWidth()); - int height = Math.max(filterObstacles.getMatrixHeight(), filterPedestrians.getMatrixHeight()); - BufferedImage image = createImage(width, height); - int maxColorValue = 255 * 255 * 255; - ColorHelper colorHelper = new ColorHelper(maxColorValue); + // double bound = filter.getMaxFilteredValue(); + double max = 1.00; + double factor = maxColorValue / max; + System.out.println(filterPedestrians.getMaxFilteredValue()); // 0.1259 - // double max = filter.getMaxFilteredValue(); - double max = 1.00; - double factor = maxColorValue / max; - System.out.println(filterPedestrians.getMaxFilteredValue()); // 0.1259 - - for (int x = 0; x < filterPedestrians.getMatrixWidth(); x++) { - for (int y = 0; y < filterPedestrians.getMatrixHeight(); y++) { - double pedValue = filterPedestrians.getFilteredValue(x, y); - double obsValue = filterObstacles.getFilteredValue(x, y); - double value = pedValue + obsValue; - // value = pedValue; - image.setRGB(x, y, colorHelper.numberToColor(value * factor).getRGB()); + for (int x = 0; x < filterPedestrians.getMatrixWidth(); x++) { + for (int y = 0; y < filterPedestrians.getMatrixHeight(); y++) { + double pedValue = filterPedestrians.getFilteredValue(x, y); + double obsValue = filterObstacles.getFilteredValue(x, y); + double value = pedValue + obsValue; + // value = pedValue; + image.setRGB(x, y, colorHelper.numberToColor(value * factor).getRGB()); /* * if(value <= 0.0) { * image.setRGB(x, y, Color.WHITE.getRGB()); @@ -75,20 +76,24 @@ public class CLGaussianCalculator { * image.setRGB(x, y, colorHelper.numberToColor(value * factor).getRGB()); * } */ - } - } - return image; - } + } + } + return image; + } + + public void destroy() { + this.filterObstacles.destroy(); + } - /** - * Helper method which create a new standard BufferedImage with the needed - * configurations. - * - * @return the image which is prepared for additional drawing - */ - private BufferedImage createImage(final int width, final int height) { - BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - return image; - } + /** + * Helper method which create a new standard BufferedImage with the needed + * configurations. + * + * @return the image which is prepared for additional drawing + */ + private BufferedImage createImage(final int width, final int height) { + BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + return image; + } } diff --git a/VadereGui/src/org/vadere/gui/components/view/SimulationRenderer.java b/VadereGui/src/org/vadere/gui/components/view/SimulationRenderer.java index 14086c6b7..054158064 100644 --- a/VadereGui/src/org/vadere/gui/components/view/SimulationRenderer.java +++ b/VadereGui/src/org/vadere/gui/components/view/SimulationRenderer.java @@ -7,6 +7,7 @@ import java.awt.Stroke; import java.awt.geom.Path2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; +import java.util.Collection; import java.util.stream.Stream; import org.apache.log4j.LogManager; @@ -17,126 +18,133 @@ import org.vadere.gui.components.utils.ColorHelper; import org.vadere.gui.components.utils.Resources; import org.vadere.state.scenario.Agent; import org.vadere.util.geometry.shapes.VPoint; +import org.vadere.util.geometry.shapes.VTriangle; public abstract class SimulationRenderer extends DefaultRenderer { - private static Logger logger = LogManager.getLogger(SimulationRenderer.class); - private static Resources resources = Resources.getInstance("postvisualization"); - - private static double MAX_POTENTIAL = 1000.0; - private static double CONTOUR_STEP = 2.0; - private static double CONTOUR_THINKNESS = 0.2; - - private SimulationModel model; - private BufferedImage obstacleDensity = null; - private BufferedImage potentialFieldImage = null; - private ColorHelper colorHelper; - private Color lastDensityColor = null; - private int topographyId; - - public SimulationRenderer(final SimulationModel model) { - super(model); - this.model = model; - this.topographyId = -1; - this.colorHelper = new ColorHelper(40); - } - - @Override - protected void renderPreTransformation(Graphics2D graphics2D, int width, int height) { - if (model.isFloorFieldAvailable() && model.config.isShowPotentialField()) { - synchronized (model) { - renderPotentialField(graphics2D, - (int)(Math.min(model.getTopographyBound().width, model.getViewportBound().width) * model.getScaleFactor()), - (int)(Math.min(model.getTopographyBound().height, model.getViewportBound().height) * model.getScaleFactor())); - } - } - super.renderPreTransformation(graphics2D, width, height); - } - - @Override - public void renderPostTransformation(final Graphics2D graphics, final int width, final int height) { - graphics.setColor(Color.BLACK); - - // if there is no potential field than draw the default background (white) - // otherwise do not overdraw the potential field!!! - if (!model.isFloorFieldAvailable() || !model.config.isShowPotentialField()) { - super.renderPostTransformation(graphics, width, height); - } - - if (model.config.isShowDensity()) { - renderDensity(graphics); - } - - if (model.config.isShowGrid()) { - renderGrid(graphics); - } - - if (model.config.isShowObstacles()) { - renderScenarioElement(model.getTopography().getObstacles(), graphics, model.config.getObstacleColor()); - } - - if (model.config.isShowStairs()) { - renderScenarioElement(model.getTopography().getStairs(), graphics, model.config.getStairColor()); - } - - if (model.config.isShowTargets()) { - renderScenarioElement(model.getTopography().getTargets(), graphics, model.config.getTargetColor()); - } - - if (model.config.isShowSources()) { - renderScenarioElement(model.getTopography().getSources(), graphics, model.config.getSourceColor()); - } - - if (model.isVoronoiDiagramAvailable() && model.isVoronoiDiagramVisible()) { - renderVoronoiDiagram(graphics, model.getVoronoiDiagram()); - } - - renderSimulationContent(graphics); - - if (model.isElementSelected()) { - renderSelectionBorder(graphics); - } - - if (model.isSelectionVisible()) { - renderSelectionShape(graphics); - } - - if (hasLogo() && model.config.isShowLogo()) { - renderLogo(graphics, model.getScaleFactor(), height); - } - - graphics.dispose(); - } - - protected void renderTrajectory(final Graphics2D g, final java.util.List points, final Agent pedestrain) { - renderTrajectory(g, points.stream(), pedestrain); - } - - protected void renderTrajectory(final Graphics2D g, final Stream points, final Agent pedestrain) { - Color color = g.getColor(); - Stroke stroke = g.getStroke(); - - if (model.isElementSelected() && model.getSelectedElement().equals(pedestrain)) { - g.setColor(Color.MAGENTA); - g.setStroke(new BasicStroke(getLineWidth() / 2.0f)); - } else { - g.setStroke(new BasicStroke(getLineWidth() / 4.0f)); - } - - Path2D.Double path = new Path2D.Double(); - path.moveTo(pedestrain.getPosition().getX(), pedestrain.getPosition().getY()); - points.forEachOrdered( - p -> path.lineTo(p.getX(), p.getY())); - - g.draw(path); - g.setColor(color); - // g.setStroke(stroke); - } - - private void renderDensity(final Graphics2D g) { - CLGaussianCalculator densityCalculator = new CLGaussianCalculator(model, model.config.getDensityScale(), - model.config.getDensityMeasurementRadius(), - model.config.getDensityColor(), true, true); + private static Logger logger = LogManager.getLogger(SimulationRenderer.class); + private static Resources resources = Resources.getInstance("postvisualization"); + + private static double MAX_POTENTIAL = 1000.0; + private static double CONTOUR_STEP = 2.0; + private static double CONTOUR_THINKNESS = 0.2; + + private SimulationModel model; + private BufferedImage obstacleDensity = null; + private BufferedImage potentialFieldImage = null; + private ColorHelper colorHelper; + private Color lastDensityColor = null; + private int topographyId; + + public SimulationRenderer(final SimulationModel model) { + super(model); + this.model = model; + this.topographyId = -1; + this.colorHelper = new ColorHelper(40); + } + + @Override + protected void renderPreTransformation(Graphics2D graphics2D, int width, int height) { + if (model.isFloorFieldAvailable() && model.config.isShowPotentialField()) { + synchronized (model) { + renderPotentialField(graphics2D, + (int)(Math.min(model.getTopographyBound().width, model.getViewportBound().width) * model.getScaleFactor()), + (int)(Math.min(model.getTopographyBound().height, model.getViewportBound().height) * model.getScaleFactor())); + } + } + super.renderPreTransformation(graphics2D, width, height); + } + + @Override + public void renderPostTransformation(final Graphics2D graphics, final int width, final int height) { + graphics.setColor(Color.BLACK); + + // if there is no potential field than draw the default background (white) + // otherwise do not overdraw the potential field!!! + if (!model.isFloorFieldAvailable() || !model.config.isShowPotentialField()) { + super.renderPostTransformation(graphics, width, height); + } + + if (model.config.isShowDensity()) { + renderDensity(graphics); + } + + if (model.config.isShowGrid()) { + renderGrid(graphics); + } + + if (model.config.isShowObstacles()) { + renderScenarioElement(model.getTopography().getObstacles(), graphics, model.config.getObstacleColor()); + } + + if (model.config.isShowStairs()) { + renderScenarioElement(model.getTopography().getStairs(), graphics, model.config.getStairColor()); + } + + if (model.config.isShowTargets()) { + renderScenarioElement(model.getTopography().getTargets(), graphics, model.config.getTargetColor()); + } + + if (model.config.isShowSources()) { + renderScenarioElement(model.getTopography().getSources(), graphics, model.config.getSourceColor()); + } + + if (model.isVoronoiDiagramAvailable() && model.isVoronoiDiagramVisible()) { + renderVoronoiDiagram(graphics, model.getVoronoiDiagram()); + } + + renderSimulationContent(graphics); + + if (model.isElementSelected()) { + renderSelectionBorder(graphics); + } + + if (model.isSelectionVisible()) { + renderSelectionShape(graphics); + } + + if (hasLogo() && model.config.isShowLogo()) { + renderLogo(graphics, model.getScaleFactor(), height); + } + + graphics.dispose(); + } + + protected void renderTrajectory(final Graphics2D g, final java.util.List points, final Agent pedestrain) { + renderTrajectory(g, points.stream(), pedestrain); + } + + protected void renderTrajectory(final Graphics2D g, final Stream points, final Agent pedestrain) { + Color color = g.getColor(); + Stroke stroke = g.getStroke(); + + if (model.isElementSelected() && model.getSelectedElement().equals(pedestrain)) { + g.setColor(Color.MAGENTA); + g.setStroke(new BasicStroke(getLineWidth() / 2.0f)); + } else { + g.setStroke(new BasicStroke(getLineWidth() / 4.0f)); + } + + Path2D.Double path = new Path2D.Double(); + path.moveTo(pedestrain.getPosition().getX(), pedestrain.getPosition().getY()); + points.forEachOrdered( + p -> path.lineTo(p.getX(), p.getY())); + + g.draw(path); + g.setColor(color); + // g.setStroke(stroke); + } + + protected void renderTriangulation(final Graphics2D g, final Collection triangleList) { + g.setColor(Color.GRAY); + g.setStroke(new BasicStroke(getGridLineWidth())); + triangleList.stream().forEach(triangle -> g.draw(triangle)); + } + + private void renderDensity(final Graphics2D g) { + CLGaussianCalculator densityCalculator = new CLGaussianCalculator(model, model.config.getDensityScale(), + model.config.getDensityMeasurementRadius(), + model.config.getDensityColor(), true, true); /* * if (obstacleDensity == null || !model.config.getDensityColor().equals(lastDensityColor) * || model.getTopographyId() != topographyId) { @@ -152,44 +160,49 @@ public abstract class SimulationRenderer extends DefaultRenderer { * model.config.getPedestrianTorso()); */ - BufferedImage densityImage = densityCalculator.getDensityImage(); + BufferedImage densityImage = densityCalculator.getDensityImage(); - g.scale(1.0 / model.config.getDensityScale(), 1.0 / model.config.getDensityScale()); - g.drawImage(densityImage, 0, 0, null); - // g.drawImage(pedestrianDensity, 0, 0, null); - g.scale(model.config.getDensityScale(), model.config.getDensityScale()); - } + g.scale(1.0 / model.config.getDensityScale(), 1.0 / model.config.getDensityScale()); + g.drawImage(densityImage, 0, 0, null); + // g.drawImage(pedestrianDensity, 0, 0, null); + g.scale(model.config.getDensityScale(), model.config.getDensityScale()); + densityCalculator.destroy(); + } - private void renderPotentialField(final Graphics2D g, final int width, final int height) { + private void renderPotentialField(final Graphics2D g, final int width, final int height) { /* * This calculation we need since the viewport.y = 0 if the user scrolls to the bottom */ - Rectangle2D.Double viewportBound = model.getViewportBound(); - double dy = model.getTopographyBound().getHeight() - viewportBound.getHeight(); - - int startX = (int) (viewportBound.getX() * model.getScaleFactor()); - int startY = (int) (Math.max((dy - viewportBound.getY()), 0) * model.getScaleFactor()); - potentialFieldImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - - - for (int x = 0; x < potentialFieldImage.getWidth(); x++) { - for (int y = 0; y < potentialFieldImage.getHeight(); y++) { - Color c; - double potential = model.getPotential(x + startX, y + startY); - - if (potential >= MAX_POTENTIAL) { - c = model.config.getObstacleColor(); - } else if (potential % CONTOUR_STEP <= CONTOUR_THINKNESS) { - c = Color.BLACK; - } else { - c = colorHelper.numberToColor(potential % 100); - } - potentialFieldImage.setRGB(x, y, c.getRGB()); - } - } - g.drawImage(potentialFieldImage, 0, 0, null); - } - - protected abstract void renderSimulationContent(final Graphics2D g); -} + Rectangle2D.Double viewportBound = model.getViewportBound(); + double dy = model.getTopographyBound().getHeight() - viewportBound.getHeight(); + + int startX = (int) (viewportBound.getX() * model.getScaleFactor()); + int startY = (int) (Math.max((dy - viewportBound.getY()), 0) * model.getScaleFactor()); + potentialFieldImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + + + for (int x = 0; x < potentialFieldImage.getWidth(); x++) { + for (int y = 0; y < potentialFieldImage.getHeight(); y++) { + Color c; + double potential = model.getPotential(x + startX, y + startY); + + if (potential >= MAX_POTENTIAL) { + c = model.config.getObstacleColor(); + } else if (potential % CONTOUR_STEP <= CONTOUR_THINKNESS) { + c = Color.BLACK; + } else { + c = colorHelper.numberToColor(potential % 100); + } + potentialFieldImage.setRGB(x, y, c.getRGB()); + } + } + g.drawImage(potentialFieldImage, 0, 0, null); + } + + protected abstract void renderSimulationContent(final Graphics2D g); + + private float getGridLineWidth() { + return (float) (0.5 / model.getScaleFactor()); + } +} \ No newline at end of file diff --git a/VadereSimulator/src/org/vadere/simulator/models/density/CLGaussianFilter.java b/VadereSimulator/src/org/vadere/simulator/models/density/CLGaussianFilter.java index f3d72715c..17683ab29 100644 --- a/VadereSimulator/src/org/vadere/simulator/models/density/CLGaussianFilter.java +++ b/VadereSimulator/src/org/vadere/simulator/models/density/CLGaussianFilter.java @@ -8,16 +8,22 @@ import org.vadere.util.opencl.CLConvolution; class CLGaussianFilter extends GaussianFilter { - private final CLConvolution convolution; + private final CLConvolution convolution; - CLGaussianFilter(final Rectangle2D scenarioBounds, final double scale, final BiFunction f, - final boolean normalize) throws IOException { - super(scenarioBounds, scale, f, normalize); - this.convolution = new CLConvolution(); - } + CLGaussianFilter(final Rectangle2D scenarioBounds, final double scale, final BiFunction f, + final boolean normalize) throws IOException { + super(scenarioBounds, scale, f, normalize); + this.convolution = new CLConvolution(matrixWidth, matrixHeight, kernelWidth, kernel); + this.convolution.init(); + } - @Override - public void filterImage() { - outputMatrix = this.convolution.convolveSeparate(inputMatrix, matrixWidth, matrixHeight, kernel, kernelWidth); - } + @Override + public void filterImage() { + outputMatrix = this.convolution.convolve(inputMatrix); + } + + @Override + public void destroy() { + this.convolution.clearCL(); + } } diff --git a/VadereSimulator/src/org/vadere/simulator/models/density/GaussianFilter.java b/VadereSimulator/src/org/vadere/simulator/models/density/GaussianFilter.java index 41699cc20..f5dd42dbb 100644 --- a/VadereSimulator/src/org/vadere/simulator/models/density/GaussianFilter.java +++ b/VadereSimulator/src/org/vadere/simulator/models/density/GaussianFilter.java @@ -10,118 +10,119 @@ import java.util.stream.IntStream; abstract class GaussianFilter implements IGaussianFilter { - /** - * the scale of the images respect to the scenario width and heigt and based on the - * gridresolution of the potential field grid. - */ - protected final double scale; - - /** the width of the scenario. */ - protected final int scenarioWidth; - - /** the height of the scenario. */ - protected final int scenarioHeight; - - protected float[] inputMatrix; - - protected float[] outputMatrix; - - protected float[] kernel; - - protected int kernelWidth; - protected int kernelHeight; - - protected int matrixWidth; - protected int matrixHeight; - - private static Logger logger = LogManager.getLogger(GaussianFilter.class); - - GaussianFilter(final Rectangle2D scenarioBounds, final double scale, final BiFunction f, - final boolean noramized) { - this.scale = scale; - this.scenarioWidth = (int) (Math.ceil(scenarioBounds.getWidth())) + 1; - this.scenarioHeight = (int) (Math.ceil(scenarioBounds.getHeight())) + 1; - this.matrixWidth = (int) (Math.ceil(scenarioWidth * scale)); - this.matrixHeight = (int) (Math.ceil(scenarioHeight * scale)); - this.inputMatrix = new float[matrixWidth * matrixHeight]; - - kernelWidth = (int) (9 * scale) + 1; - // kernelWidth = 31; - kernelWidth = kernelWidth % 2 == 0 ? kernelWidth + 1 : kernelWidth; - kernelHeight = kernelWidth; - this.kernel = Convolution.floatGaussian1DKernel(kernelWidth, f, noramized); - } - - @Override - public void clear() { - this.inputMatrix = new float[matrixWidth * matrixHeight]; - } - - @Override - public double getFilteredValue(final double x, final double y) { - if (x < 0 || y < 0) { - throw new IllegalArgumentException("x(" + x + ") or y(" + y + ") < 0."); - } - - return getFilteredValue((int) Math.round(x * scale), (int) Math.round(y * scale)); - } - - public double getFilteredValue(final int x, final int y) { - if (x < 0 || y < 0) { - throw new IllegalArgumentException("x(" + x + ") or y(" + y + ") < 0."); - } - - int index = matrixWidth * y + x; - if (index >= outputMatrix.length) { - logger.warn("index(" + index + ") is out matrix range"); - return 0.0; - // throw new IllegalArgumentException("index("+index+") is out matrix range"); - } + /** + * the scale of the images respect to the scenario width and heigt and based on the + * gridresolution of the potential field grid. + */ + protected final double scale; + + /** the width of the scenario. */ + protected final int scenarioWidth; + + /** the height of the scenario. */ + protected final int scenarioHeight; + + protected float[] inputMatrix; + + protected float[] outputMatrix; + + protected float[] kernel; + + protected int kernelWidth; + protected int kernelHeight; + + protected int matrixWidth; + protected int matrixHeight; + + private static Logger logger = LogManager.getLogger(GaussianFilter.class); + + GaussianFilter(final Rectangle2D scenarioBounds, final double scale, final BiFunction f, + final boolean noramized) { + this.scale = scale; + this.scenarioWidth = (int) (Math.ceil(scenarioBounds.getWidth())) + 1; + this.scenarioHeight = (int) (Math.ceil(scenarioBounds.getHeight())) + 1; + this.matrixWidth = (int) (Math.ceil(scenarioWidth * scale)); + this.matrixHeight = (int) (Math.ceil(scenarioHeight * scale)); + this.inputMatrix = new float[matrixWidth * matrixHeight]; + + kernelWidth = (int) (9 * scale) + 1; + // kernelWidth = 31; + kernelWidth = kernelWidth % 2 == 0 ? kernelWidth + 1 : kernelWidth; + kernelHeight = kernelWidth; + this.kernel = Convolution.floatGaussian1DKernel(kernelWidth, f, noramized); + //this.kernel = Convolution.generateFloatGaussianKernel(kernelWidth, 0.1f); + } + + @Override + public void clear() { + this.inputMatrix = new float[matrixWidth * matrixHeight]; + } + + @Override + public double getFilteredValue(final double x, final double y) { + if (x < 0 || y < 0) { + throw new IllegalArgumentException("x(" + x + ") or y(" + y + ") < 0."); + } + + return getFilteredValue((int) Math.round(x * scale), (int) Math.round(y * scale)); + } + + public double getFilteredValue(final int x, final int y) { + if (x < 0 || y < 0) { + throw new IllegalArgumentException("x(" + x + ") or y(" + y + ") < 0."); + } + + int index = matrixWidth * y + x; + if (index >= outputMatrix.length) { + logger.warn("index(" + index + ") is out matrix range"); + return 0.0; + // throw new IllegalArgumentException("index("+index+") is out matrix range"); + } /* * if(outputMatrix[index] > 0) { * logger.info("index(" + index + "): " + outputMatrix[index]); * } */ - return outputMatrix[index]; - } - - @Override - public void setInputValue(final int x, final int y, double value) { - inputMatrix[matrixWidth * y + x] = (float) value; - } - - @Override - public void setInputValue(final double x, final double y, double value) { - inputMatrix[matrixWidth * (int) Math.round(y * scale) + (int) Math.round(x * scale)] = (float) value; - } - - @Override - public double getScale() { - return scale; - } - - @Override - public int getMatrixWidth() { - return matrixWidth; - } - - @Override - public int getMatrixHeight() { - return matrixHeight; - } - - @Override - public double getMaxFilteredValue() { - return IntStream.range(0, outputMatrix.length).mapToDouble(i -> outputMatrix[i]).max().orElse(0.0); - } - - @Override - public double getMinFilteredValue() { - return IntStream.range(0, outputMatrix.length).mapToDouble(i -> outputMatrix[i]).min().orElse(0.0); - } - - @Override - public double getInputValue(int x, int y) { - return inputMatrix[matrixWidth * y + x]; - } + return outputMatrix[index]; + } + + @Override + public void setInputValue(final int x, final int y, double value) { + inputMatrix[matrixWidth * y + x] = (float) value; + } + + @Override + public void setInputValue(final double x, final double y, double value) { + inputMatrix[matrixWidth * (int) Math.round(y * scale) + (int) Math.round(x * scale)] = (float) value; + } + + @Override + public double getScale() { + return scale; + } + + @Override + public int getMatrixWidth() { + return matrixWidth; + } + + @Override + public int getMatrixHeight() { + return matrixHeight; + } + + @Override + public double getMaxFilteredValue() { + return IntStream.range(0, outputMatrix.length).mapToDouble(i -> outputMatrix[i]).max().orElse(0.0); + } + + @Override + public double getMinFilteredValue() { + return IntStream.range(0, outputMatrix.length).mapToDouble(i -> outputMatrix[i]).min().orElse(0.0); + } + + @Override + public double getInputValue(int x, int y) { + return inputMatrix[matrixWidth * y + x]; + } } diff --git a/VadereSimulator/src/org/vadere/simulator/models/density/IGaussianFilter.java b/VadereSimulator/src/org/vadere/simulator/models/density/IGaussianFilter.java index 50fbcfc6e..320623c48 100644 --- a/VadereSimulator/src/org/vadere/simulator/models/density/IGaussianFilter.java +++ b/VadereSimulator/src/org/vadere/simulator/models/density/IGaussianFilter.java @@ -14,133 +14,138 @@ import org.vadere.state.scenario.Topography; * IGaussianFilter is a refershable image processing calculator that can be used * to solve a discrete convolution or other calculations that can be done by a * image processing filter. - * - * + * + * */ public interface IGaussianFilter { - enum Type { - OpenCL, // default - NativeJava // not jet implemented - } - - /** - * Returns the value of a specified coordinate. This coordinate will be - * converted to natural numbers of the image. - * - * @param x - * the x-coordinate (for example the x-coordinate of a place on - * the floor) - * @param y - * the y-coordinate (for example the y-coordinate of a place on - * the floor) - * @return the value of a specified coordinate - */ - double getFilteredValue(final double x, final double y); - - double getFilteredValue(int x, int y); - - double getInputValue(int x, int y); - - void setInputValue(final double x, final double y, final double value); - - void setInputValue(final int x, final int y, final double value); - - /** refresh or update the values of the image that contains all values. */ - void filterImage(); - - void clear(); - - int getMatrixWidth(); - - int getMatrixHeight(); - - double getScale(); - - double getMaxFilteredValue(); - - double getMinFilteredValue(); - - static IGaussianFilter create(final Rectangle2D scenarioBounds, - Collection pedestrians, final double scale, - final double standardDerivation, - final AttributesAgent attributesPedestrian, - final IPedestrianLoadingStrategy loadingStrategy) { - return create(scenarioBounds, pedestrians, scale, standardDerivation, attributesPedestrian, loadingStrategy, - Type.OpenCL); - } - - /* - * Factory-methods - */ - static IGaussianFilter create(final Rectangle2D scenarioBounds, - Collection pedestrians, final double scale, - final double standardDerivation, - final AttributesAgent attributesPedestrian, - final IPedestrianLoadingStrategy loadingStrategy, final Type type) { - - double scaleFactor = attributesPedestrian.getRadius() * 2 - * attributesPedestrian.getRadius() * 2 - * Math.sqrt(3) - * 0.5 - / (2 * Math.PI * standardDerivation * standardDerivation); - - switch (type) { - case OpenCL: { - try { - BiFunction f = - (centerI, i) -> (float) (Math.sqrt(scaleFactor) * Math.exp(-((centerI - i) / scale) - * ((centerI - i) / scale) / (2 * standardDerivation * standardDerivation))); - IGaussianFilter clFilter = new CLGaussianFilter(scenarioBounds, scale, f, false); - return new PedestrianGaussianFilter(pedestrians, clFilter, loadingStrategy); - } catch (IOException e) { - // cannot go on, this should never happen! - throw new RuntimeException(e); - } - } - default: + enum Type { + OpenCL, // default + NativeJava // not jet implemented + } + + /** + * Returns the value of a specified coordinate. This coordinate will be + * converted to natural numbers of the image. + * + * @param x + * the x-coordinate (for example the x-coordinate of a place on + * the floor) + * @param y + * the y-coordinate (for example the y-coordinate of a place on + * the floor) + * @return the value of a specified coordinate + */ + double getFilteredValue(final double x, final double y); + + double getFilteredValue(int x, int y); + + double getInputValue(int x, int y); + + void setInputValue(final double x, final double y, final double value); + + void setInputValue(final int x, final int y, final double value); + + /** refresh or update the values of the image that triangleContains all values. */ + void filterImage(); + + void clear(); + + int getMatrixWidth(); + + int getMatrixHeight(); + + double getScale(); + + double getMaxFilteredValue(); + + double getMinFilteredValue(); + + /** + * This method has to be called if the Filter will no longer called! + */ + void destroy(); + + static IGaussianFilter create(final Rectangle2D scenarioBounds, + Collection pedestrians, final double scale, + final double standardDerivation, + final AttributesAgent attributesPedestrian, + final IPedestrianLoadingStrategy loadingStrategy) { + return create(scenarioBounds, pedestrians, scale, standardDerivation, attributesPedestrian, loadingStrategy, + Type.OpenCL); + } + + /* + * Factory-methods + */ + static IGaussianFilter create(final Rectangle2D scenarioBounds, + Collection pedestrians, final double scale, + final double standardDerivation, + final AttributesAgent attributesPedestrian, + final IPedestrianLoadingStrategy loadingStrategy, final Type type) { + + double scaleFactor = attributesPedestrian.getRadius() * 2 + * attributesPedestrian.getRadius() * 2 + * Math.sqrt(3) + * 0.5 + / (2 * Math.PI * standardDerivation * standardDerivation); + + switch (type) { + case OpenCL: { + try { + BiFunction f = + (centerI, i) -> (float) (Math.sqrt(scaleFactor) * Math.exp(-((centerI - i) / scale) + * ((centerI - i) / scale) / (2 * standardDerivation * standardDerivation))); + IGaussianFilter clFilter = new CLGaussianFilter(scenarioBounds, scale, f, false); + return new PedestrianGaussianFilter(pedestrians, clFilter, loadingStrategy); + } catch (IOException e) { + // cannot go on, this should never happen! + throw new RuntimeException(e); + } + } + default: BiFunction f = (centerI, i) -> (float) (Math.sqrt(scaleFactor) * Math.exp(-((centerI - i) / scale) * ((centerI - i) / scale) / (2 * standardDerivation * standardDerivation))); IGaussianFilter clFilter = new JGaussianFilter(scenarioBounds, scale, f, false); return new PedestrianGaussianFilter(pedestrians, clFilter, loadingStrategy); } - } - - static IGaussianFilter create( - final Topography scenario, final double scale, - final boolean scenarioHasBoundary, final double standardDerivation) { - return create(scenario, scale, scenarioHasBoundary, standardDerivation, Type.OpenCL); - } - - static IGaussianFilter create( - final Topography scenario, final double scale, - final boolean scenarioHasBoundary, final double standardDerivation, final Type type) { - switch (type) { - case OpenCL: { - try { - double varianz = standardDerivation * standardDerivation; - BiFunction f = (centerI, i) -> (float) ((1.0 / (2 * Math.PI * varianz)) - * Math.exp(-((centerI - i) / scale) * ((centerI - i) / scale) / (2 * varianz))); - IGaussianFilter clFilter = new CLGaussianFilter(scenario.getBounds(), scale, f, true); - return new ObstacleGaussianFilter(scenario, clFilter); - } catch (IOException e) { - // cannot go on, this should never happen! - throw new RuntimeException(e); - } - } - default: + } + + static IGaussianFilter create( + final Topography scenario, final double scale, + final boolean scenarioHasBoundary, final double standardDerivation) { + return create(scenario, scale, scenarioHasBoundary, standardDerivation, Type.OpenCL); + } + + static IGaussianFilter create( + final Topography scenario, final double scale, + final boolean scenarioHasBoundary, final double standardDerivation, final Type type) { + switch (type) { + case OpenCL: { + try { + double varianz = standardDerivation * standardDerivation; + BiFunction f = (centerI, i) -> (float) ((1.0 / (2 * Math.PI * varianz)) + * Math.exp(-((centerI - i) / scale) * ((centerI - i) / scale) / (2 * varianz))); + IGaussianFilter clFilter = new CLGaussianFilter(scenario.getBounds(), scale, f, true); + return new ObstacleGaussianFilter(scenario, clFilter); + } catch (IOException e) { + // cannot go on, this should never happen! + throw new RuntimeException(e); + } + } + default: double varianz = standardDerivation * standardDerivation; BiFunction f = (centerI, i) -> (float) ((1.0 / (2 * Math.PI * varianz)) * Math.exp(-((centerI - i) / scale) * ((centerI - i) / scale) / (2 * varianz))); IGaussianFilter clFilter = new JGaussianFilter(scenario.getBounds(), scale, f, true); return new ObstacleGaussianFilter(scenario, clFilter); } - } + } - static IGaussianFilter create( - final Topography scenario, final double scale, - final double standardDerivation) { - return create(scenario, scale, true, standardDerivation); - } + static IGaussianFilter create( + final Topography scenario, final double scale, + final double standardDerivation) { + return create(scenario, scale, true, standardDerivation); + } } diff --git a/VadereSimulator/src/org/vadere/simulator/models/density/JGaussianFilter.java b/VadereSimulator/src/org/vadere/simulator/models/density/JGaussianFilter.java index 92e3c725c..ae5e03e47 100644 --- a/VadereSimulator/src/org/vadere/simulator/models/density/JGaussianFilter.java +++ b/VadereSimulator/src/org/vadere/simulator/models/density/JGaussianFilter.java @@ -16,4 +16,7 @@ public class JGaussianFilter extends GaussianFilter { public void filterImage() { outputMatrix = Convolution.convolveSeperate(inputMatrix, kernel, kernel, matrixWidth, matrixHeight, kernelWidth); } + + @Override + public void destroy() {} } diff --git a/VadereSimulator/src/org/vadere/simulator/models/density/ObstacleGaussianFilter.java b/VadereSimulator/src/org/vadere/simulator/models/density/ObstacleGaussianFilter.java index ea3c7f2c8..ed6bba388 100644 --- a/VadereSimulator/src/org/vadere/simulator/models/density/ObstacleGaussianFilter.java +++ b/VadereSimulator/src/org/vadere/simulator/models/density/ObstacleGaussianFilter.java @@ -4,97 +4,102 @@ import org.vadere.state.scenario.Topography; public class ObstacleGaussianFilter implements IGaussianFilter { - private final IGaussianFilter filter; - private final Topography topography; - private boolean filtered; - - public ObstacleGaussianFilter(final Topography topography, final IGaussianFilter filter) { - this.filter = filter; - this.topography = topography; - this.filtered = false; - } - - @Override - public double getFilteredValue(double x, double y) { - return filter.getFilteredValue(x, y); - } - - @Override - public double getFilteredValue(int x, int y) { - return filter.getFilteredValue(x, y); - } - - @Override - public void setInputValue(double x, double y, double value) { - filter.setInputValue(x, y, value); - } - - @Override - public void setInputValue(int x, int y, double value) { - filter.setInputValue(x, y, value); - } - - @Override - public void filterImage() { - if (!filtered) { - setValues(); - filter.filterImage(); - filtered = true; - } - } - - @Override - public int getMatrixWidth() { - return filter.getMatrixWidth(); - } - - @Override - public int getMatrixHeight() { - return filter.getMatrixHeight(); - } - - @Override - public double getScale() { - return filter.getScale(); - } - - @Override - public double getMaxFilteredValue() { - return filter.getMaxFilteredValue(); - } - - @Override - public double getMinFilteredValue() { - return filter.getMinFilteredValue(); - } - - private void setValues() { - for (int x = 0; x < getMatrixWidth(); x++) { - for (int y = 0; y < getMatrixHeight(); y++) { - double dx = x / getScale(); - double dy = y / getScale(); - - if (topography.getObstacles().stream().map(obs -> obs.getShape()).anyMatch(s -> s.contains(dx, dy))) { - setInputValue(x, y, 1.0f); - } else if (topography.isBounded() && - (dx <= topography.getBoundingBoxWidth() || dy <= topography.getBoundingBoxWidth() - || dx >= topography.getBounds().getWidth() - topography.getBoundingBoxWidth() - || dy >= topography.getBounds().getHeight() - topography.getBoundingBoxWidth())) { - setInputValue(x, y, 1.0f); - } else { - setInputValue(x, y, 0.0f); - } - } - } - } - - @Override - public void clear() { - filter.clear(); - } - - @Override - public double getInputValue(int x, int y) { - return filter.getInputValue(x, y); - } + private final IGaussianFilter filter; + private final Topography topography; + private boolean filtered; + + public ObstacleGaussianFilter(final Topography topography, final IGaussianFilter filter) { + this.filter = filter; + this.topography = topography; + this.filtered = false; + } + + @Override + public double getFilteredValue(double x, double y) { + return filter.getFilteredValue(x, y); + } + + @Override + public double getFilteredValue(int x, int y) { + return filter.getFilteredValue(x, y); + } + + @Override + public void setInputValue(double x, double y, double value) { + filter.setInputValue(x, y, value); + } + + @Override + public void setInputValue(int x, int y, double value) { + filter.setInputValue(x, y, value); + } + + @Override + public void filterImage() { + if (!filtered) { + setValues(); + filter.filterImage(); + filtered = true; + } + } + + @Override + public int getMatrixWidth() { + return filter.getMatrixWidth(); + } + + @Override + public int getMatrixHeight() { + return filter.getMatrixHeight(); + } + + @Override + public double getScale() { + return filter.getScale(); + } + + @Override + public double getMaxFilteredValue() { + return filter.getMaxFilteredValue(); + } + + @Override + public double getMinFilteredValue() { + return filter.getMinFilteredValue(); + } + + @Override + public void destroy() { + this.filter.destroy(); + } + + private void setValues() { + for (int x = 0; x < getMatrixWidth(); x++) { + for (int y = 0; y < getMatrixHeight(); y++) { + double dx = x / getScale(); + double dy = y / getScale(); + + if (topography.getObstacles().stream().map(obs -> obs.getShape()).anyMatch(s -> s.contains(dx, dy))) { + setInputValue(x, y, 1.0f); + } else if (topography.isBounded() && + (dx <= topography.getBoundingBoxWidth() || dy <= topography.getBoundingBoxWidth() + || dx >= topography.getBounds().getWidth() - topography.getBoundingBoxWidth() + || dy >= topography.getBounds().getHeight() - topography.getBoundingBoxWidth())) { + setInputValue(x, y, 1.0f); + } else { + setInputValue(x, y, 0.0f); + } + } + } + } + + @Override + public void clear() { + filter.clear(); + } + + @Override + public double getInputValue(int x, int y) { + return filter.getInputValue(x, y); + } } diff --git a/VadereSimulator/src/org/vadere/simulator/models/density/PedestrianGaussianFilter.java b/VadereSimulator/src/org/vadere/simulator/models/density/PedestrianGaussianFilter.java index e697d2b35..6a72bf94b 100644 --- a/VadereSimulator/src/org/vadere/simulator/models/density/PedestrianGaussianFilter.java +++ b/VadereSimulator/src/org/vadere/simulator/models/density/PedestrianGaussianFilter.java @@ -11,170 +11,174 @@ import java.util.function.Predicate; public class PedestrianGaussianFilter implements IGaussianFilter { - private final IGaussianFilter filter; - private final Collection pedestrians; - private final Predicate pedestrianPredicate; - private final IPedestrianLoadingStrategy pedestrianLoadingStrategy; - private static Logger logger = LogManager.getLogger(PedestrianGaussianFilter.class); - - public PedestrianGaussianFilter(final Collection pedestrians, final IGaussianFilter filter, - final IPedestrianLoadingStrategy pedestrianLoadingStrategy) { - this(pedestrians, filter, pedestrianLoadingStrategy, p -> true); - } - - public PedestrianGaussianFilter(final Collection pedestrians, final IGaussianFilter filter, - final IPedestrianLoadingStrategy pedestrianLoadingStrategy, final Predicate pedestrianPredicate) { - this.filter = filter; - this.pedestrians = pedestrians; - this.pedestrianPredicate = pedestrianPredicate; - this.pedestrianLoadingStrategy = pedestrianLoadingStrategy; - } - - @Override - public double getFilteredValue(int x, int y) { - - double value = filter.getFilteredValue(x, y); + private final IGaussianFilter filter; + private final Collection pedestrians; + private final Predicate pedestrianPredicate; + private final IPedestrianLoadingStrategy pedestrianLoadingStrategy; + private static Logger logger = LogManager.getLogger(PedestrianGaussianFilter.class); + + public PedestrianGaussianFilter(final Collection pedestrians, final IGaussianFilter filter, + final IPedestrianLoadingStrategy pedestrianLoadingStrategy) { + this(pedestrians, filter, pedestrianLoadingStrategy, p -> true); + } + + public PedestrianGaussianFilter(final Collection pedestrians, final IGaussianFilter filter, + final IPedestrianLoadingStrategy pedestrianLoadingStrategy, final Predicate pedestrianPredicate) { + this.filter = filter; + this.pedestrians = pedestrians; + this.pedestrianPredicate = pedestrianPredicate; + this.pedestrianLoadingStrategy = pedestrianLoadingStrategy; + } + + @Override + public double getFilteredValue(int x, int y) { + + double value = filter.getFilteredValue(x, y); /* * if(value > 0) { * logger.info("pedVal: " + value); * } */ - // return value < 1.0f ? 0 : value; - return value; - } + // return value < 1.0f ? 0 : value; + return value; + } - @Override - public double getFilteredValue(double x, double y) { + @Override + public double getFilteredValue(double x, double y) { - double value = filter.getFilteredValue(x, y); + double value = filter.getFilteredValue(x, y); /* * if(value > 0) { * logger.info("pedVal: " + value); * } */ - // return value < 1.0f ? 0 : value; - return value; - } - - @Override - public void setInputValue(double x, double y, double value) { - filter.setInputValue(x, y, value); - } - - @Override - public void setInputValue(int x, int y, double value) { - filter.setInputValue(x, y, value); - } - - @Override - public void filterImage() { - - setValues(); - filter.filterImage(); - } - - @Override - public int getMatrixWidth() { - return filter.getMatrixWidth(); - } - - @Override - public int getMatrixHeight() { - return filter.getMatrixHeight(); - } - - @Override - public double getScale() { - return filter.getScale(); - } - - @Override - public double getMaxFilteredValue() { - return filter.getMaxFilteredValue(); - } - - @Override - public double getMinFilteredValue() { - return filter.getMinFilteredValue(); - } - - private void setValue(E pedestrian) { - VPoint position = pedestrian.getPosition(); - VPoint filteredPosition = new VPoint(Math.max(0, position.x), Math.max(0, position.y)); - - // better approximation - double indexX = filteredPosition.x * getScale(); - double indexY = filteredPosition.y * getScale(); - - if (indexX == ((int) indexX) && indexY == ((int) indexY)) { - setInputValue(filteredPosition.x, filteredPosition.y, - getInputValue((int) indexX, (int) indexY) + pedestrianLoadingStrategy.calculateLoading(pedestrian)); - } else if (indexX == ((int) indexX) && indexY != ((int) indexY)) { - splitY(filteredPosition, (int) indexX, (int) Math.floor(indexY), pedestrian); - splitY(filteredPosition, (int) indexX, (int) Math.ceil(indexY), pedestrian); - } else if (indexX != ((int) indexX) && indexY == ((int) indexY)) { - splitX(filteredPosition, (int) Math.floor(indexX), (int) indexY, pedestrian); - splitX(filteredPosition, (int) Math.ceil(indexX), (int) indexY, pedestrian); - } else { - splitXY(filteredPosition, (int) Math.floor(indexX), (int) Math.floor(indexY), pedestrian); - splitXY(filteredPosition, (int) Math.floor(indexX), (int) Math.ceil(indexY), pedestrian); - splitXY(filteredPosition, (int) Math.ceil(indexX), (int) Math.floor(indexY), pedestrian); - splitXY(filteredPosition, (int) Math.ceil(indexX), (int) Math.ceil(indexY), pedestrian); - } - - // setInputValue(filteredPosition.x, filteredPosition.y, - // pedestrianLoadingStrategy.calculateLoading(pedestrian)); - } - - private void splitXY(final VPoint filteredPosition, final int indexX, final int indexY, Pedestrian pedestrian) { - if (checkIndices(indexX, indexY)) { - double dx = Math.abs(filteredPosition.x * getScale() - indexX); - double dy = Math.abs(filteredPosition.y * getScale() - indexY); - - double weight = ((1.0 - dx) + (1.0 - dy)) / 4.0; - // double weight = Math.exp(-(dx * dx + dy * dy) / (2 * 0.7 * 0.7)); - setInputValue(indexX, indexY, - getInputValue(indexX, indexY) + pedestrianLoadingStrategy.calculateLoading(pedestrian) * weight); - } - } - - private void splitX(final VPoint filteredPosition, final int indexX, final int indexY, Pedestrian pedestrian) { - if (checkIndices(indexX, indexY)) { - double dx = Math.abs(filteredPosition.x * getScale() - indexX); - double weight = (1.0 - dx); - // double weight = Math.exp(-(dx * dx + dy * dy) / (2 * 0.7 * 0.7)); - setInputValue(indexX, indexY, - getInputValue(indexX, indexY) + pedestrianLoadingStrategy.calculateLoading(pedestrian) * weight); - } - } - - private void splitY(final VPoint filteredPosition, final int indexX, final int indexY, Pedestrian pedestrian) { - if (checkIndices(indexX, indexY)) { - double dy = Math.abs(filteredPosition.y * getScale() - indexY); - - double weight = (1.0 - dy); - // double weight = Math.exp(-(dx * dx + dy * dy) / (2 * 0.7 * 0.7)); - setInputValue(indexX, indexY, - getInputValue(indexX, indexY) + pedestrianLoadingStrategy.calculateLoading(pedestrian) * weight); - } - } - - private boolean checkIndices(int x, int y) { - return x >= 0 && y >= 0 && x < filter.getMatrixWidth() && y < filter.getMatrixHeight(); - } - - private void setValues() { - clear(); - pedestrians.stream().filter(pedestrianPredicate).forEach(p -> setValue(p)); - } - - @Override - public void clear() { - filter.clear(); - } - - @Override - public double getInputValue(int x, int y) { - return filter.getInputValue(x, y); - } + // return value < 1.0f ? 0 : value; + return value; + } + + @Override + public void setInputValue(double x, double y, double value) { + filter.setInputValue(x, y, value); + } + + @Override + public void setInputValue(int x, int y, double value) { + filter.setInputValue(x, y, value); + } + + @Override + public void filterImage() { + setValues(); + filter.filterImage(); + } + + @Override + public int getMatrixWidth() { + return filter.getMatrixWidth(); + } + + @Override + public int getMatrixHeight() { + return filter.getMatrixHeight(); + } + + @Override + public double getScale() { + return filter.getScale(); + } + + @Override + public double getMaxFilteredValue() { + return filter.getMaxFilteredValue(); + } + + @Override + public double getMinFilteredValue() { + return filter.getMinFilteredValue(); + } + + @Override + public void destroy() { + this.filter.destroy(); + } + + private void setValue(E pedestrian) { + VPoint position = pedestrian.getPosition(); + VPoint filteredPosition = new VPoint(Math.max(0, position.x), Math.max(0, position.y)); + + // better approximation + double indexX = filteredPosition.x * getScale(); + double indexY = filteredPosition.y * getScale(); + + if (indexX == ((int) indexX) && indexY == ((int) indexY)) { + setInputValue(filteredPosition.x, filteredPosition.y, + getInputValue((int) indexX, (int) indexY) + pedestrianLoadingStrategy.calculateLoading(pedestrian)); + } else if (indexX == ((int) indexX) && indexY != ((int) indexY)) { + splitY(filteredPosition, (int) indexX, (int) Math.floor(indexY), pedestrian); + splitY(filteredPosition, (int) indexX, (int) Math.ceil(indexY), pedestrian); + } else if (indexX != ((int) indexX) && indexY == ((int) indexY)) { + splitX(filteredPosition, (int) Math.floor(indexX), (int) indexY, pedestrian); + splitX(filteredPosition, (int) Math.ceil(indexX), (int) indexY, pedestrian); + } else { + splitXY(filteredPosition, (int) Math.floor(indexX), (int) Math.floor(indexY), pedestrian); + splitXY(filteredPosition, (int) Math.floor(indexX), (int) Math.ceil(indexY), pedestrian); + splitXY(filteredPosition, (int) Math.ceil(indexX), (int) Math.floor(indexY), pedestrian); + splitXY(filteredPosition, (int) Math.ceil(indexX), (int) Math.ceil(indexY), pedestrian); + } + + // setInputValue(filteredPosition.x, filteredPosition.y, + // pedestrianLoadingStrategy.calculateLoading(pedestrian)); + } + + private void splitXY(final VPoint filteredPosition, final int indexX, final int indexY, Pedestrian pedestrian) { + if (checkIndices(indexX, indexY)) { + double dx = Math.abs(filteredPosition.x * getScale() - indexX); + double dy = Math.abs(filteredPosition.y * getScale() - indexY); + + double weight = ((1.0 - dx) + (1.0 - dy)) / 4.0; + // double weight = Math.exp(-(dx * dx + dy * dy) / (2 * 0.7 * 0.7)); + setInputValue(indexX, indexY, + getInputValue(indexX, indexY) + pedestrianLoadingStrategy.calculateLoading(pedestrian) * weight); + } + } + + private void splitX(final VPoint filteredPosition, final int indexX, final int indexY, Pedestrian pedestrian) { + if (checkIndices(indexX, indexY)) { + double dx = Math.abs(filteredPosition.x * getScale() - indexX); + double weight = (1.0 - dx); + // double weight = Math.exp(-(dx * dx + dy * dy) / (2 * 0.7 * 0.7)); + setInputValue(indexX, indexY, + getInputValue(indexX, indexY) + pedestrianLoadingStrategy.calculateLoading(pedestrian) * weight); + } + } + + private void splitY(final VPoint filteredPosition, final int indexX, final int indexY, Pedestrian pedestrian) { + if (checkIndices(indexX, indexY)) { + double dy = Math.abs(filteredPosition.y * getScale() - indexY); + + double weight = (1.0 - dy); + // double weight = Math.exp(-(dx * dx + dy * dy) / (2 * 0.7 * 0.7)); + setInputValue(indexX, indexY, + getInputValue(indexX, indexY) + pedestrianLoadingStrategy.calculateLoading(pedestrian) * weight); + } + } + + private boolean checkIndices(int x, int y) { + return x >= 0 && y >= 0 && x < filter.getMatrixWidth() && y < filter.getMatrixHeight(); + } + + private void setValues() { + clear(); + pedestrians.stream().filter(pedestrianPredicate).forEach(p -> setValue(p)); + } + + @Override + public void clear() { + filter.clear(); + } + + @Override + public double getInputValue(int x, int y) { + return filter.getInputValue(x, y); + } } diff --git a/VadereSimulator/src/org/vadere/simulator/models/queuing/QueueDetector.java b/VadereSimulator/src/org/vadere/simulator/models/queuing/QueueDetector.java index 4d6c9c6e8..affc34fac 100644 --- a/VadereSimulator/src/org/vadere/simulator/models/queuing/QueueDetector.java +++ b/VadereSimulator/src/org/vadere/simulator/models/queuing/QueueDetector.java @@ -25,100 +25,101 @@ import org.vadere.util.potential.timecost.ITimeCostFunction; public class QueueDetector extends EikonalSolverFMM { - private AttributesAgent attributesPedestrian; - private Topography topography; - private final PriorityQueue targetPoints; - private VPolygon polytope; - private static double QUEUE_DENSITY = 0.03; - private static double radius = 2.0; - protected LinkedList orderedPoints; - - /** - * Initializes the FM potential calculator with a time cost function F > 0. - * - * @param potentialField - * @param targetShapes - * @param isHighAccuracy - * @param timeCostFunction - */ - public QueueDetector(CellGrid potentialField, List targetShapes, boolean isHighAccuracy, - ITimeCostFunction timeCostFunction, AttributesAgent attributesPedestrian, Topography topography) { - super(potentialField, targetShapes, isHighAccuracy, timeCostFunction); - this.orderedPoints = new LinkedList<>(); - this.attributesPedestrian = attributesPedestrian; - this.topography = topography; - this.targetPoints = new PriorityQueue<>(); - this.polytope = null; - - for (VShape shape : targetShapes) { - FloorDiscretizer.setGridValuesForShapeCentered(cellGrid, shape, - new CellState(0.0, PathFindingTag.Target)); - } - - for (Obstacle obstacle : topography.getObstacles()) { - FloorDiscretizer.setGridValuesForShapeCentered( - cellGrid, obstacle.getShape(), - new CellState(Double.MAX_VALUE, PathFindingTag.Obstacle)); - } - - } - - public double getResolution() { - return cellGrid.getResolution(); - } - - @Override - public void initialize() { - IPedestrianLoadingStrategy loadingStrategy = IPedestrianLoadingStrategy.create(); - IGaussianFilter filter = IGaussianFilter.create( - topography.getBounds(), - topography.getElements(Pedestrian.class), - 1.0 / cellGrid.getResolution(), - new AttributesTimeCost().getStandardDerivation(), - attributesPedestrian, - loadingStrategy, IGaussianFilter.Type.OpenCL); - - filter.filterImage(); - cellGrid.pointStream().forEach(p -> { - int x = p.x; - int y = p.y; - - VPoint point = cellGrid.pointToCoord(x, y); - if (cellGrid.getValue(x, y).tag != PathFindingTag.Target - && filter.getFilteredValue(point.x, point.y) <= QUEUE_DENSITY) { - cellGrid.getValue(x, y).tag = PathFindingTag.Obstacle; - } else if (cellGrid.getValue(x, y).tag != PathFindingTag.Target) { - // System.out.println("found:" + point); - cellGrid.getValue(x, y).tag = PathFindingTag.Undefined; - } - }); - orderedPoints.clear(); - super.initialize(); - } - - @Override - protected void setNeighborDistances(Point point) { - super.setNeighborDistances(point); - VPoint worldCoord = cellGrid.pointToCoord(point); - orderedPoints = orderedPoints.stream().filter(p -> p.distance(worldCoord) > radius) - .collect(Collectors.toCollection(LinkedList::new)); - if (targetShapes.stream().noneMatch(shape -> shape.distance(worldCoord) <= radius)) { - orderedPoints.addFirst(cellGrid.pointToCoord(point)); - } - } - - public void setPolytope(VPolygon polytope) { - this.polytope = polytope; - } - - @Override - public boolean needsUpdate() { - return true; - } - - public List getTargetPoints() { - return orderedPoints; - } + private AttributesAgent attributesPedestrian; + private Topography topography; + private final PriorityQueue targetPoints; + private VPolygon polytope; + private static double QUEUE_DENSITY = 0.03; + private static double radius = 2.0; + protected LinkedList orderedPoints; + + /** + * Initializes the FM potential calculator with a time cost function F > 0. + * + * @param potentialField + * @param targetShapes + * @param isHighAccuracy + * @param timeCostFunction + */ + public QueueDetector(CellGrid potentialField, List targetShapes, boolean isHighAccuracy, + ITimeCostFunction timeCostFunction, AttributesAgent attributesPedestrian, Topography topography) { + super(potentialField, targetShapes, isHighAccuracy, timeCostFunction); + this.orderedPoints = new LinkedList<>(); + this.attributesPedestrian = attributesPedestrian; + this.topography = topography; + this.targetPoints = new PriorityQueue<>(); + this.polytope = null; + + for (VShape shape : targetShapes) { + FloorDiscretizer.setGridValuesForShapeCentered(cellGrid, shape, + new CellState(0.0, PathFindingTag.Target)); + } + + for (Obstacle obstacle : topography.getObstacles()) { + FloorDiscretizer.setGridValuesForShapeCentered( + cellGrid, obstacle.getShape(), + new CellState(Double.MAX_VALUE, PathFindingTag.Obstacle)); + } + + } + + public double getResolution() { + return cellGrid.getResolution(); + } + + @Override + public void initialize() { + IPedestrianLoadingStrategy loadingStrategy = IPedestrianLoadingStrategy.create(); + IGaussianFilter filter = IGaussianFilter.create( + topography.getBounds(), + topography.getElements(Pedestrian.class), + 1.0 / cellGrid.getResolution(), + new AttributesTimeCost().getStandardDerivation(), + attributesPedestrian, + loadingStrategy, IGaussianFilter.Type.OpenCL); + + filter.filterImage(); + cellGrid.pointStream().forEach(p -> { + int x = p.x; + int y = p.y; + + VPoint point = cellGrid.pointToCoord(x, y); + if (cellGrid.getValue(x, y).tag != PathFindingTag.Target + && filter.getFilteredValue(point.x, point.y) <= QUEUE_DENSITY) { + cellGrid.getValue(x, y).tag = PathFindingTag.Obstacle; + } else if (cellGrid.getValue(x, y).tag != PathFindingTag.Target) { + // System.out.println("found:" + point); + cellGrid.getValue(x, y).tag = PathFindingTag.Undefined; + } + }); + orderedPoints.clear(); + filter.destroy(); + super.initialize(); + } + + @Override + protected void setNeighborDistances(Point point) { + super.setNeighborDistances(point); + VPoint worldCoord = cellGrid.pointToCoord(point); + orderedPoints = orderedPoints.stream().filter(p -> p.distance(worldCoord) > radius) + .collect(Collectors.toCollection(LinkedList::new)); + if (targetShapes.stream().noneMatch(shape -> shape.distance(worldCoord) <= radius)) { + orderedPoints.addFirst(cellGrid.pointToCoord(point)); + } + } + + public void setPolytope(VPolygon polytope) { + this.polytope = polytope; + } + + @Override + public boolean needsUpdate() { + return true; + } + + public List getTargetPoints() { + return orderedPoints; + } diff --git a/VadereUtils/resources/Convolve.cl b/VadereUtils/resources/Convolve.cl index 60ba756ac..456c42448 100644 --- a/VadereUtils/resources/Convolve.cl +++ b/VadereUtils/resources/Convolve.cl @@ -1,4 +1,49 @@ //KERNEL_SIMPLE with crop strategy +/*__kernel void convolve(const __global float * pInput, + __constant float * pFilter, + __global float * pOutput, + const int nInWidth, + const int nInHeight, + const int nFilterWidth) +{ + int nWidth = get_global_size(0); + + int xOut = get_global_id(0); + int yOut = get_global_id(1); + + if(xOut < nInWidth && yOut < nInHeight) { + int bottomBorder = yOut + nFilterWidth / 2; + bottomBorder = bottomBorder < nInHeight ? bottomBorder : nInHeight-1; + + int topBorder = yOut - (nFilterWidth / 2); + topBorder = topBorder > 0 ? topBorder : 0; + + int rightBorder = xOut + nFilterWidth / 2; + rightBorder = rightBorder < nInWidth ? rightBorder : nInWidth - 1; + + int leftBorder = xOut - (nFilterWidth / 2) > 0; + leftBorder = leftBorder > 0 ? leftBorder : 0; + + float sum = 0; + int kernelX = 0; + int kernelY = 0; + for(int y = topBorder; y <= bottomBorder; y++) { + for(int x = leftBorder; x <= rightBorder; x++) { + int inputIndex = y * nInWidth + x; + int kernelIndex = kernelY * nFilterWidth + kernelX; + + sum += pFilter[kernelIndex] * pInput[inputIndex]; + + kernelX++; + } + kernelX = 0; + kernelY++; + } + int idxOut = yOut * nInWidth + xOut; + pOutput[idxOut] = sum; + } +}*/ + __kernel void convolve(const __global float * pInput, __constant float * pFilter, __global float * pOutput, @@ -68,10 +113,14 @@ __kernel void convolveRow(const __global float * pInput, int idxF = (r + nFilterWidth / 2); int yIn = yInTopLeft * nInWidth; int idxIn = yIn + xInTopLeft + r * nInWidth; - sum += pFilter[idxF] * pInput[idxIn]; + if(idxF >= 0 && idxF < nFilterWidth && idxIn >= 0 && idxIn < nInWidth * nInHeight) { + sum += pFilter[idxF] * pInput[idxIn]; + } } int idxOut = yOut * nWidth + xOut; - pOutput[idxOut] = sum; + if(idxOut >= 0 && idxOut < nInWidth * nInHeight) { + pOutput[idxOut] = sum; + } } __kernel void convolveCol(const __global float * pInput, @@ -97,11 +146,17 @@ __kernel void convolveCol(const __global float * pInput, float sum = 0; for (int r = -nFilterWidth / 2 - leftBorder; r <= nFilterWidth / 2 - rightBorder; r++) { - int idxF = (r + nFilterWidth / 2); - int yIn = yInTopLeft * nInWidth; - int idxIn = yIn + xInTopLeft + r; - sum += pFilter[idxF] * pInput[idxIn]; + int idxF = (r + nFilterWidth / 2); + int yIn = yInTopLeft * nInWidth; + int idxIn = yIn + xInTopLeft + r; + if(idxF >= 0 && idxF < nFilterWidth && idxIn >= 0 && idxIn < nInWidth * nInHeight) { + sum += pFilter[idxF] * pInput[idxIn]; + } + } + int idxOut = yOut * nWidth + xOut; - pOutput[idxOut] = sum; + if(idxOut >= 0 && idxOut < nInWidth * nInHeight) { + pOutput[idxOut] = sum; + } } \ No newline at end of file diff --git a/VadereUtils/src/org/vadere/util/opencl/CLConvolution.java b/VadereUtils/src/org/vadere/util/opencl/CLConvolution.java index 5fad1616f..d11e4b83a 100644 --- a/VadereUtils/src/org/vadere/util/opencl/CLConvolution.java +++ b/VadereUtils/src/org/vadere/util/opencl/CLConvolution.java @@ -2,11 +2,15 @@ package org.vadere.util.opencl; import org.apache.log4j.LogManager; import org.apache.log4j.Logger; +import org.jetbrains.annotations.NotNull; import org.lwjgl.BufferUtils; import org.lwjgl.PointerBuffer; import org.lwjgl.opencl.CLContextCallback; import org.lwjgl.opencl.CLProgramCallback; +import org.lwjgl.system.Configuration; import org.lwjgl.system.MemoryStack; +import org.lwjgl.system.MemoryUtil; +import org.vadere.util.math.Convolution; import java.io.IOException; import java.nio.ByteBuffer; @@ -14,19 +18,19 @@ import java.nio.FloatBuffer; import java.nio.IntBuffer; import static org.lwjgl.opencl.CL10.*; +import static org.lwjgl.system.MemoryStack.stackPush; import static org.lwjgl.system.MemoryUtil.NULL; import static org.lwjgl.system.MemoryUtil.memUTF8; /** - * Class to compute the (separate) convolutions on the GPU. - * * @author Benedikt Zoennchen */ public class CLConvolution { private static Logger log = LogManager.getLogger(CLConvolution.class); + private Convolution gaussianFilter; + // CL ids - private MemoryStack stack; private long clPlatform; private long clDevice; private long clContext; @@ -47,6 +51,9 @@ public class CLConvolution { private FloatBuffer hostGaussKernel; private FloatBuffer output; + private PointerBuffer strings; + private PointerBuffer lengths; + // CL callbacks private CLContextCallback contextCB; private CLProgramCallback programCB; @@ -56,102 +63,111 @@ public class CLConvolution { private long clKernelConvolveRow; private long clKernelConvolveCol; - public CLConvolution() { - this.stack = MemoryStack.stackPush(); - } + private long clKernel; - public void init() { - initCallbacks(); - initCL(); - buildProgram(); - } + private int matrixWidth; + private int matrixHeight; + private int kernelWidth; + private float[] kernel; + private KernelType type; - public float[] convolve(final float[] input, - final int matrixWidth, - final int matrixHeight, - final float[] kernel, - final int kernelWidth) { - init(); - float[] result = convolve(input, matrixWidth, matrixHeight, kernel, kernelWidth, clKernelConvolve); - clearCL(); - clReleaseKernel(clKernelConvolve); - return result; + public enum KernelType { + Separate, + Col, + Row, + NonSeparate } - public float[] convolveRow(final float[] input, final int matrixWidth, final int matrixHeight, final float[] kernel, - final int kernelWidth) { - init(); - float[] result = convolve(input, matrixWidth, matrixHeight, kernel, kernelWidth, clKernelConvolveRow); - clearCL(); - clReleaseKernel(clKernelConvolveRow); - return result; + public CLConvolution( + final int matrixWidth, + final int matrixHeight, + final int kernelWidth, @NotNull final float[] kernel) { + this(KernelType.Separate, matrixWidth, matrixHeight, kernelWidth, kernel); } - public float[] convolveCol(final float[] input, final int matrixWidth, final int matrixHeight, final float[] kernel, - final int kernelWidth) { + public CLConvolution( + @NotNull final KernelType type, + final int matrixWidth, + final int matrixHeight, + final int kernelWidth, @NotNull final float[] kernel) { + this.type = type; + this.matrixHeight = matrixHeight; + this.matrixWidth = matrixWidth; + this.kernelWidth = kernelWidth; + this.kernel = kernel; + init(); - float[] result = convolve(input, matrixWidth, matrixHeight, kernel, kernelWidth, clKernelConvolveCol); - clearCL(); - clReleaseKernel(clKernelConvolveCol); - return result; + Configuration.DEBUG.set(true); + Configuration.DEBUG_MEMORY_ALLOCATOR.set(true); + Configuration.DEBUG_STACK.set(true); } - public float[] convolveSeparate(final float[] input, final int matrixWidth, final int matrixHeight, final float[] kernel, - final int kernelWidth) { - assert matrixWidth * matrixHeight == input.length; - init(); - hostScenario = CLUtils.toFloatBuffer(input); - output = CLUtils.toFloatBuffer(input); - hostGaussKernel = CLUtils.toFloatBuffer(kernel); + public void init() { + initCallbacks(); + initCL(); + buildProgram(); - // host memory to gpu memory - clInput = clCreateBuffer(clContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, hostScenario, errcode_ret); - clTmp = clCreateBuffer(clContext, CL_MEM_READ_WRITE, 4 * input.length, errcode_ret); - clOutput = clCreateBuffer(clContext, CL_MEM_WRITE_ONLY, 4 * input.length, errcode_ret); - clGaussianKernel = clCreateBuffer(clContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, hostGaussKernel, errcode_ret); + hostScenario = MemoryUtil.memAllocFloat(matrixWidth * matrixHeight); + output = MemoryUtil.memAllocFloat(matrixWidth * matrixHeight); - clSetKernelArg1p(clKernelConvolveCol, 0, clInput); - clSetKernelArg1p(clKernelConvolveCol, 1, clGaussianKernel); - clSetKernelArg1p(clKernelConvolveCol, 2, clTmp); - clSetKernelArg1i(clKernelConvolveCol, 3, matrixWidth); - clSetKernelArg1i(clKernelConvolveCol, 4, matrixHeight); - clSetKernelArg1i(clKernelConvolveCol, 5, kernelWidth); + switch (type) { + case NonSeparate: clKernel = clKernelConvolve; break; + case Col: clKernel = clKernelConvolveCol; break; + case Row: clKernel = clKernelConvolveRow; break; + case Separate: clKernel = -1; break; + default: throw new IllegalArgumentException("unsupported kernel type = " + type); + } - clSetKernelArg1p(clKernelConvolveRow, 0, clTmp); - clSetKernelArg1p(clKernelConvolveRow, 1, clGaussianKernel); - clSetKernelArg1p(clKernelConvolveRow, 2, clOutput); - clSetKernelArg1i(clKernelConvolveRow, 3, matrixWidth); - clSetKernelArg1i(clKernelConvolveRow, 4, matrixHeight); - clSetKernelArg1i(clKernelConvolveRow, 5, kernelWidth); + if(type != KernelType.Separate) { + setArguments(clKernel); + } + else { + setArguments(clKernelConvolveCol, clKernelConvolveRow); + } + } - PointerBuffer clGlobalWorkSizeEdges = BufferUtils.createPointerBuffer(2); - clGlobalWorkSizeEdges.put(0, matrixWidth); - clGlobalWorkSizeEdges.put(1, matrixHeight); + public float[] convolve(final float[] input) { + // 1. write input to native-c-like-memory + CLUtils.toFloatBuffer(input, hostScenario); - // run the kernel and read the result - clEnqueueNDRangeKernel(clQueue, clKernelConvolveCol, 2, null, clGlobalWorkSizeEdges, null, null, null); - clEnqueueNDRangeKernel(clQueue, clKernelConvolveRow, 2, null, clGlobalWorkSizeEdges, null, null, null); - clFinish(clQueue); + // 2. write this memory to the GPU + clEnqueueWriteBuffer(clQueue, clInput, true, 0, hostScenario, null, null); + + // 2. convolve + switch (type) { + case NonSeparate: convolve(clKernelConvolve); break; + case Col: convolve(clKernelConvolveCol); break; + case Row: convolve(clKernelConvolveRow); break; + case Separate: convolveSeparate(); break; + default: throw new IllegalArgumentException("unsupported kernel type = " + type); + } + + // 4. read result from the GPU to a native-c-like-memory clEnqueueReadBuffer(clQueue, clOutput, true, 0, output, null, null); - float[] foutput = CLUtils.toFloatArray(output, input.length); - clearCL(); - clReleaseKernel(clTmp); - clReleaseKernel(clKernelConvolve); - clReleaseKernel(clKernelConvolveRow); - clReleaseKernel(clKernelConvolveCol); + // 5. read this memory and transform it back into a java array. + float[] foutput = CLUtils.toFloatArray(output, matrixWidth * matrixHeight); return foutput; } - private float[] convolve(final float[] input, - final int matrixWidth, - final int matrixHeight, - final float[] kernel, - final int kernelWidth, final long clKernel) { - assert matrixWidth * matrixHeight == input.length; - setArguments(input, matrixWidth, matrixHeight, kernel, kernelWidth, clKernel); + private void convolveSeparate() { + //init(); + try (MemoryStack stack = stackPush()) { + + PointerBuffer clGlobalWorkSizeEdges = BufferUtils.createPointerBuffer(2); + clGlobalWorkSizeEdges.put(0, matrixWidth); + clGlobalWorkSizeEdges.put(1, matrixHeight); + + PointerBuffer ev = stack.callocPointer(1); + // run the kernel and read the result + clEnqueueNDRangeKernel(clQueue, clKernelConvolveCol, 2, null, clGlobalWorkSizeEdges, null, null, null); + clEnqueueNDRangeKernel(clQueue, clKernelConvolveRow, 2, null, clGlobalWorkSizeEdges, null, null, null); + clFinish(clQueue); + } + } + private void convolve(final long clKernel) { PointerBuffer clGlobalWorkSizeEdges = BufferUtils.createPointerBuffer(2); clGlobalWorkSizeEdges.put(0, matrixWidth); clGlobalWorkSizeEdges.put(1, matrixHeight); @@ -159,21 +175,13 @@ public class CLConvolution { // run the kernel and read the result clEnqueueNDRangeKernel(clQueue, clKernel, 2, null, clGlobalWorkSizeEdges, null, null, null); clFinish(clQueue); - clEnqueueReadBuffer(clQueue, clOutput, true, 0, output, null, null); - - float[] foutput = CLUtils.toFloatArray(output, input.length); - return foutput; } - private void setArguments(final float[] input, final int matrixWidth, final int matrixHeight, final float[] kernel, final int kernelWidth, final long clKernel) { - hostScenario = CLUtils.toFloatBuffer(input); - output = CLUtils.toFloatBuffer(input); - hostGaussKernel = CLUtils.toFloatBuffer(kernel); - + private void setArguments(final long clKernel) { // host memory to gpu memory - clInput = clCreateBuffer(clContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, hostScenario, errcode_ret); - clOutput = clCreateBuffer(clContext, CL_MEM_WRITE_ONLY, 4 * input.length, errcode_ret); - clGaussianKernel = clCreateBuffer(clContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, hostGaussKernel, errcode_ret); + clInput = clCreateBuffer(clContext, CL_MEM_READ_WRITE, 4 * matrixWidth * matrixHeight, errcode_ret); + clOutput = clCreateBuffer(clContext, CL_MEM_WRITE_ONLY, 4 * matrixWidth * matrixHeight, errcode_ret); + clGaussianKernel = clCreateBuffer(clContext, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR, hostGaussKernel, errcode_ret); clSetKernelArg1p(clKernel, 0, clInput); clSetKernelArg1p(clKernel, 1, clGaussianKernel); @@ -183,17 +191,57 @@ public class CLConvolution { clSetKernelArg1i(clKernel, 5, kernelWidth); } - private void clearCL() { + private void setArguments(final long clKernelConvolveCol, final long clKernelConvolveRow) { + clTmp = clCreateBuffer(clContext, CL_MEM_READ_WRITE, 4 * matrixWidth * matrixHeight, errcode_ret); + clInput = clCreateBuffer(clContext, CL_MEM_READ_WRITE, 4 * matrixWidth * matrixHeight, errcode_ret); + clOutput = clCreateBuffer(clContext, CL_MEM_WRITE_ONLY, 4 * matrixWidth * matrixHeight, errcode_ret); + clGaussianKernel = clCreateBuffer(clContext, CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR, hostGaussKernel, errcode_ret); + + clSetKernelArg1p(clKernelConvolveCol, 0, clInput); + clSetKernelArg1p(clKernelConvolveCol, 1, clGaussianKernel); + clSetKernelArg1p(clKernelConvolveCol, 2, clTmp); + clSetKernelArg1i(clKernelConvolveCol, 3, matrixWidth); + clSetKernelArg1i(clKernelConvolveCol, 4, matrixHeight); + clSetKernelArg1i(clKernelConvolveCol, 5, kernelWidth); + + clSetKernelArg1p(clKernelConvolveRow, 0, clTmp); + clSetKernelArg1p(clKernelConvolveRow, 1, clGaussianKernel); + clSetKernelArg1p(clKernelConvolveRow, 2, clOutput); + clSetKernelArg1i(clKernelConvolveRow, 3, matrixWidth); + clSetKernelArg1i(clKernelConvolveRow, 4, matrixHeight); + clSetKernelArg1i(clKernelConvolveRow, 5, kernelWidth); + } + + private void clearMemory() { // release memory and devices - contextCB.free(); - programCB.free(); + clReleaseMemObject(clInput); clReleaseMemObject(clOutput); clReleaseMemObject(clGaussianKernel); - clReleaseCommandQueue(clQueue); - clReleaseProgram(clProgram); - clReleaseContext(clContext); + if(type == KernelType.Separate) { + clReleaseMemObject(clTmp); + } + + clReleaseKernel(clKernelConvolve); + clReleaseKernel(clKernelConvolveRow); + clReleaseKernel(clKernelConvolveCol); + + MemoryUtil.memFree(hostScenario); + MemoryUtil.memFree(output); + MemoryUtil.memFree(hostGaussKernel); + //CL.destroy(); +// strings.free(); +// lengths.free(); + } + + public void clearCL() { + clearMemory(); + contextCB.free(); + programCB.free(); + log.info("release command queue: " + (clReleaseCommandQueue(clQueue) == CL_SUCCESS)); + log.info("release program: " + (clReleaseProgram(clProgram) == CL_SUCCESS)); + log.info("release context: " + (clReleaseContext(clContext) == CL_SUCCESS)); } // private helpers @@ -211,41 +259,44 @@ public class CLConvolution { } private void initCL() { - // helper for the memory allocation in java - //stack = MemoryStack.stackPush(); - errcode_ret = stack.callocInt(1); + try (MemoryStack stack = stackPush()) { + // helper for the memory allocation in java + //stack = MemoryStack.stackPush(); + errcode_ret = stack.callocInt(1); - IntBuffer numberOfPlatforms = stack.mallocInt(1); - clGetPlatformIDs(null, numberOfPlatforms); - PointerBuffer platformIDs = stack.mallocPointer(numberOfPlatforms.get(0)); - clGetPlatformIDs(platformIDs, numberOfPlatforms); + IntBuffer numberOfPlatforms = stack.mallocInt(1); + clGetPlatformIDs(null, numberOfPlatforms); + PointerBuffer platformIDs = stack.mallocPointer(numberOfPlatforms.get(0)); + clGetPlatformIDs(platformIDs, numberOfPlatforms); - clPlatform = platformIDs.get(0); + clPlatform = platformIDs.get(0); - IntBuffer numberOfDevices = stack.mallocInt(1); - clGetDeviceIDs(clPlatform, CL_DEVICE_TYPE_GPU, null, numberOfDevices); - PointerBuffer deviceIDs = stack.mallocPointer(numberOfDevices.get(0)); - clGetDeviceIDs(clPlatform, CL_DEVICE_TYPE_GPU, deviceIDs, numberOfDevices); + IntBuffer numberOfDevices = stack.mallocInt(1); + clGetDeviceIDs(clPlatform, CL_DEVICE_TYPE_GPU, null, numberOfDevices); + PointerBuffer deviceIDs = stack.mallocPointer(numberOfDevices.get(0)); + clGetDeviceIDs(clPlatform, CL_DEVICE_TYPE_GPU, deviceIDs, numberOfDevices); - clDevice = deviceIDs.get(0); + clDevice = deviceIDs.get(0); - printDeviceInfo(clDevice, "CL_DEVICE_NAME", CL_DEVICE_NAME); + printDeviceInfo(clDevice, "CL_DEVICE_NAME", CL_DEVICE_NAME); - PointerBuffer ctxProps = stack.mallocPointer(3); - ctxProps.put(CL_CONTEXT_PLATFORM) - .put(clPlatform) - .put(NULL) - .flip(); + PointerBuffer ctxProps = stack.mallocPointer(3); + ctxProps.put(CL_CONTEXT_PLATFORM) + .put(clPlatform) + .put(NULL) + .flip(); - clContext = clCreateContext(ctxProps, clDevice, contextCB, NULL, errcode_ret); - CLInfo.checkCLError(errcode_ret); + clContext = clCreateContext(ctxProps, clDevice, contextCB, NULL, errcode_ret); + CLInfo.checkCLError(errcode_ret); - clQueue = clCreateCommandQueue(clContext, clDevice, 0, errcode_ret); + clQueue = clCreateCommandQueue(clContext, clDevice, 0, errcode_ret); + CLInfo.checkCLError(errcode_ret); + } } private void buildProgram() { - PointerBuffer strings = BufferUtils.createPointerBuffer(1); - PointerBuffer lengths = BufferUtils.createPointerBuffer(1); + strings = BufferUtils.createPointerBuffer(1); + lengths = BufferUtils.createPointerBuffer(1); ByteBuffer source; try { @@ -263,8 +314,11 @@ public class CLConvolution { int errcode = clBuildProgram(clProgram, clDevice, "", programCB, NULL); CLInfo.checkCLError(errcode); clKernelConvolve = clCreateKernel(clProgram, "convolve", errcode_ret); + CLInfo.checkCLError(errcode_ret); clKernelConvolveRow = clCreateKernel(clProgram, "convolveRow", errcode_ret); + CLInfo.checkCLError(errcode_ret); clKernelConvolveCol = clCreateKernel(clProgram, "convolveCol", errcode_ret); + CLInfo.checkCLError(errcode_ret); } private static void printPlatformInfo(long platform, String param_name, int param) { diff --git a/VadereUtils/src/org/vadere/util/opencl/CLUtils.java b/VadereUtils/src/org/vadere/util/opencl/CLUtils.java index 6bf3ceabe..82775482f 100644 --- a/VadereUtils/src/org/vadere/util/opencl/CLUtils.java +++ b/VadereUtils/src/org/vadere/util/opencl/CLUtils.java @@ -69,7 +69,10 @@ public class CLUtils { public static FloatBuffer toFloatBuffer(@NotNull final float[] floats) { FloatBuffer floatBuffer = MemoryUtil.memAllocFloat(floats.length); + return toFloatBuffer(floats, floatBuffer); + } + public static FloatBuffer toFloatBuffer(@NotNull final float[] floats, @NotNull final FloatBuffer floatBuffer) { for(int i = 0; i < floats.length; i++) { floatBuffer.put(i, floats[i]); } diff --git a/VadereUtils/tests/org/vadere/util/math/TestConvolution.java b/VadereUtils/tests/org/vadere/util/math/TestConvolution.java index 80ebceaa6..28ad1ce80 100644 --- a/VadereUtils/tests/org/vadere/util/math/TestConvolution.java +++ b/VadereUtils/tests/org/vadere/util/math/TestConvolution.java @@ -48,9 +48,9 @@ public class TestConvolution { float[] input = Convolution.generdateInputMatrix(inputWidth * inputHeight); float[] javaOutput = Convolution.convolve(input, kernel, inputWidth, inputHeight, kernelWidth); - CLConvolution clConvolution = new CLConvolution(); - float[] clOutput = clConvolution.convolve(input, inputWidth, inputHeight, kernel, kernelWidth); - + CLConvolution clConvolution = new CLConvolution(inputWidth, inputHeight, kernelWidth, kernel); + float[] clOutput = clConvolution.convolve(input); + clConvolution.clearCL(); equalsMatrixValues(javaOutput, clOutput, 0.00001f); } @@ -66,8 +66,9 @@ public class TestConvolution { float[] output = Convolution.convolveCol(input, rowVector, inputWidth, inputHeight, kernelWidth); - CLConvolution clConvolution = new CLConvolution(); - float[] clOutput = clConvolution.convolveCol(input, inputWidth, inputHeight, rowVector, kernelWidth); + CLConvolution clConvolution = new CLConvolution(inputWidth, inputHeight, kernelWidth, rowVector); + float[] clOutput = clConvolution.convolve(input); + clConvolution.clearCL(); equalsMatrixValues(result, output, 0f); equalsMatrixValues(result, clOutput, 0f); @@ -85,8 +86,9 @@ public class TestConvolution { float[] output = Convolution.convolveRow(input, rowVector, inputWidth, inputHeight, kernelWidth); - CLConvolution clConvolution = new CLConvolution(); - float[] clOutput = clConvolution.convolveRow(input, inputWidth, inputHeight, rowVector, kernelWidth); + CLConvolution clConvolution = new CLConvolution(CLConvolution.KernelType.Row, inputWidth, inputHeight, kernelWidth, rowVector); + float[] clOutput = clConvolution.convolve(input); + clConvolution.clearCL(); equalsMatrixValues(result, output, 0f); equalsMatrixValues(result, clOutput, 0f); @@ -102,15 +104,15 @@ public class TestConvolution { float[] output = Convolution.convolveRow(input, rowVector, inputWidth, inputHeight, kernelWidth); - CLConvolution clConvolution = new CLConvolution(); - float[] clOutput = clConvolution.convolveRow(input, inputWidth, inputHeight, rowVector, kernelWidth); - + CLConvolution clConvolution = new CLConvolution(CLConvolution.KernelType.Row, inputWidth, inputHeight, kernelWidth, rowVector); + float[] clOutput = clConvolution.convolve(input); + clConvolution.clearCL(); equalsMatrixValues(output, clOutput, 0.00001f); } @Test - public void testConvolutionSeperate() throws IOException { + public void testConvolutionSeparate() throws IOException { int inputWidth = 500; int inputHeight = 300; int kernelWidth = 31; @@ -122,9 +124,8 @@ public class TestConvolution { float[] seperate = Convolution.convolveSeperate(input, seperateKernel, seperateKernel, inputWidth, inputHeight, kernelWidth); - CLConvolution clGPUConvolution = new CLConvolution(); - float[] clCPUOutput = - clGPUConvolution.convolveSeparate(input, inputWidth, inputHeight, seperateKernel, kernelWidth); + CLConvolution clGPUConvolution = new CLConvolution(CLConvolution.KernelType.Separate, inputWidth, inputHeight, kernelWidth, seperateKernel); + float[] clCPUOutput = clGPUConvolution.convolve(input); equalsMatrixValues(seperate, nonSeperate, 0.00001f); equalsMatrixValues(clCPUOutput, nonSeperate, 0.00001f); -- GitLab