From 9af830893bd787be35ede485e8389320ab97ad21 Mon Sep 17 00:00:00 2001 From: kmdouglass Date: Tue, 15 May 2018 14:30:25 +0200 Subject: [PATCH 1/2] Added automatic cropping of images modulo 4 to the DefaultPredictor. --- CHANGELOG.md | 8 ++++++ docs/conf.py | 4 +-- pom.xml | 2 +- .../predictors/internal/DefaultPredictor.java | 28 +++++++++++++++++-- .../internal/DefaultPredictorIT.java | 23 +++++++++++++++ 5 files changed, 60 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2291d9e..1fac519 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # Change Log All notable changes to this project will be documented in this file. +## Unreleased + +### Added + +- The `DefaultPredictor` class now automatically crops the input image + to dimensions that are a multiple of four. + ## [v0.0.1] ### Changed @@ -14,5 +21,6 @@ All notable changes to this project will be documented in this file. - Initial project files. +[v0.0.2]: https://github.com/LEB-EPFL/DEFCoN-ImageJ/releases/tag/0.0.2 [v0.0.1]: https://github.com/LEB-EPFL/DEFCoN-ImageJ/releases/tag/0.0.1 [v0.0.0]: https://github.com/LEB-EPFL/DEFCoN-ImageJ/releases/tag/0.0.0 diff --git a/docs/conf.py b/docs/conf.py index b948548..0bd778d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,9 +26,9 @@ author = 'Baptiste Ottino, Kyle M. Douglass' # The short X.Y version -version = '0.0.1' +version = '0.0.2-SNAPSHOT' # The full version, including alpha/beta/rc tags -release = '0.0.1' +release = '0.0.2-SNAPSHOT' # -- General configuration --------------------------------------------------- diff --git a/pom.xml b/pom.xml index 04ed4bf..c89afd6 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ ch.epfl.leb DEFCoN_ - 0.0.1 + 0.0.2-SNAPSHOT DEFCoN-ImageJ ImageJ plugin for DEFCoN, a fluorescence spot counter using fully convolutional neural networks. diff --git a/src/main/java/ch/epfl/leb/defcon/predictors/internal/DefaultPredictor.java b/src/main/java/ch/epfl/leb/defcon/predictors/internal/DefaultPredictor.java index dc19833..6170b09 100644 --- a/src/main/java/ch/epfl/leb/defcon/predictors/internal/DefaultPredictor.java +++ b/src/main/java/ch/epfl/leb/defcon/predictors/internal/DefaultPredictor.java @@ -19,13 +19,18 @@ package ch.epfl.leb.defcon.predictors.internal; import ch.epfl.leb.defcon.predictors.Predictor; + +import ij.gui.Roi; import ij.ImagePlus; import ij.process.ByteProcessor; import ij.process.FloatProcessor; import ij.process.ShortProcessor; import ij.process.ImageProcessor; +import java.awt.Rectangle; + import java.util.logging.Level; import java.util.logging.Logger; + import org.tensorflow.Tensor; /** @@ -49,6 +54,22 @@ public class DefaultPredictor extends AbstractPredictor implements Predictor { */ private FloatProcessor densityMap; + /** + * Checks that an image's dimensions are divisible by four and crops it if not. + * + * This restriction on the size of an image is a requirement of DEFCoN. + * + * @return The input image, possibly cropped. + */ + private ImageProcessor checkDimensions(ImageProcessor ip) { + + Rectangle currRoi = ip.getRoi(); + ip.setRoi(new Roi(currRoi.x, currRoi.y, + currRoi.width - currRoi.width % 4, + currRoi.height - currRoi.height % 4)); + return ip.crop(); + } + /** * Returns the most recent count. * @@ -93,6 +114,9 @@ private void predict(final ByteProcessor bp) { /** * Makes a density map prediction from a 2D image. * + * If either of the image's width or height is not divisible by 4, they will + * be cropped to the next largest multiple of four. + * * @param ip The image to perform a prediction on. */ @Override @@ -109,10 +133,10 @@ public void predict(final ImageProcessor ip) throws ImageBitDepthException, int bitDepth = ip.getBitDepth(); switch (bitDepth) { case 16: - predict(ip.convertToShortProcessor()); + predict(checkDimensions(ip).convertToShortProcessor()); break; case 8: - predict(ip.convertToByteProcessor()); + predict(checkDimensions(ip).convertToByteProcessor()); break; default: String msg = "The predictor only works on 8 and 16-bit images."; diff --git a/src/test/java/ch/epfl/leb/defcon/predictors/internal/DefaultPredictorIT.java b/src/test/java/ch/epfl/leb/defcon/predictors/internal/DefaultPredictorIT.java index 363873b..13f7e5a 100644 --- a/src/test/java/ch/epfl/leb/defcon/predictors/internal/DefaultPredictorIT.java +++ b/src/test/java/ch/epfl/leb/defcon/predictors/internal/DefaultPredictorIT.java @@ -20,6 +20,7 @@ import ij.IJ; import ij.ImagePlus; +import ij.process.ImageProcessor; import ij.process.FloatProcessor; import java.io.File; @@ -101,6 +102,28 @@ public void testGetDensityMap() throws Exception { assertEquals(imp.getHeight(), fp.getHeight()); assertEquals(imp.getWidth(), fp.getWidth()); } + + /** + * Test of getDensityMap method, of class DefaultPredictor. + * + * This test verifies that images whose dimensions are not multiples of four + * are automatically cropped before computing the density map. + */ + @Test + public void testGetDensityMapResized() throws Exception { + System.out.println("testGetDensityMapResized"); + ImageProcessor ip = imp.getProcessor(); + + // Reduce the size of the test data to a non-multiple of four. + ip.setRoi(0, 0, ip.getWidth() - 1, ip.getHeight() - 1); + + predictor.predict(ip.crop()); + FloatProcessor fp = predictor.getDensityMap(); + predictor.close(); + + assertEquals(imp.getWidth() - 4, fp.getWidth()); + assertEquals(imp.getHeight() - 4, fp.getHeight()); + } /** * Test of predict method, of class DefaultPredictor. From 8c2f6a88f7422179b1693cd395a72456a8ea8902 Mon Sep 17 00:00:00 2001 From: kmdouglass Date: Tue, 15 May 2018 14:55:25 +0200 Subject: [PATCH 2/2] Minor updates and increment patch version number. --- CHANGELOG.md | 6 +++++- docs/conf.py | 4 ++-- pom.xml | 2 +- src/main/java/ch/epfl/leb/defcon/ij/DensityCount.java | 6 +++--- .../predictors/{internal => }/ImageBitDepthException.java | 2 +- src/main/java/ch/epfl/leb/defcon/predictors/Predictor.java | 3 --- .../predictors/{internal => }/SessionClosedException.java | 2 +- .../{internal => }/UninitializedPredictorException.java | 2 +- .../leb/defcon/predictors/internal/DefaultPredictor.java | 3 +++ 9 files changed, 17 insertions(+), 13 deletions(-) rename src/main/java/ch/epfl/leb/defcon/predictors/{internal => }/ImageBitDepthException.java (95%) rename src/main/java/ch/epfl/leb/defcon/predictors/{internal => }/SessionClosedException.java (95%) rename src/main/java/ch/epfl/leb/defcon/predictors/{internal => }/UninitializedPredictorException.java (95%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1fac519..53ab90e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,12 +1,16 @@ # Change Log All notable changes to this project will be documented in this file. -## Unreleased +## [v0.0.2] ### Added - The `DefaultPredictor` class now automatically crops the input image to dimensions that are a multiple of four. + +### Changed +- Moved the exceptions associated with the `Predictor` interface into + the public `predictors` package. ## [v0.0.1] diff --git a/docs/conf.py b/docs/conf.py index 0bd778d..e1efd2d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,9 +26,9 @@ author = 'Baptiste Ottino, Kyle M. Douglass' # The short X.Y version -version = '0.0.2-SNAPSHOT' +version = '0.0.2' # The full version, including alpha/beta/rc tags -release = '0.0.2-SNAPSHOT' +release = '0.0.2' # -- General configuration --------------------------------------------------- diff --git a/pom.xml b/pom.xml index c89afd6..35c027a 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,7 @@ ch.epfl.leb DEFCoN_ - 0.0.2-SNAPSHOT + 0.0.2 DEFCoN-ImageJ ImageJ plugin for DEFCoN, a fluorescence spot counter using fully convolutional neural networks. diff --git a/src/main/java/ch/epfl/leb/defcon/ij/DensityCount.java b/src/main/java/ch/epfl/leb/defcon/ij/DensityCount.java index 97bb225..15c3fec 100644 --- a/src/main/java/ch/epfl/leb/defcon/ij/DensityCount.java +++ b/src/main/java/ch/epfl/leb/defcon/ij/DensityCount.java @@ -20,9 +20,9 @@ import ch.epfl.leb.defcon.predictors.Predictor; import ch.epfl.leb.defcon.predictors.internal.DefaultPredictor; -import ch.epfl.leb.defcon.predictors.internal.SessionClosedException; -import ch.epfl.leb.defcon.predictors.internal.ImageBitDepthException; -import ch.epfl.leb.defcon.predictors.internal.UninitializedPredictorException; +import ch.epfl.leb.defcon.predictors.SessionClosedException; +import ch.epfl.leb.defcon.predictors.ImageBitDepthException; +import ch.epfl.leb.defcon.predictors.UninitializedPredictorException; import ij.IJ; import ij.ImagePlus; diff --git a/src/main/java/ch/epfl/leb/defcon/predictors/internal/ImageBitDepthException.java b/src/main/java/ch/epfl/leb/defcon/predictors/ImageBitDepthException.java similarity index 95% rename from src/main/java/ch/epfl/leb/defcon/predictors/internal/ImageBitDepthException.java rename to src/main/java/ch/epfl/leb/defcon/predictors/ImageBitDepthException.java index c4d9788..4c0da7e 100644 --- a/src/main/java/ch/epfl/leb/defcon/predictors/internal/ImageBitDepthException.java +++ b/src/main/java/ch/epfl/leb/defcon/predictors/ImageBitDepthException.java @@ -16,7 +16,7 @@ * along with this program. If not, see * . */ -package ch.epfl.leb.defcon.predictors.internal; +package ch.epfl.leb.defcon.predictors; /** * Raised when an image with an invalid bit-depth is supplied to the predictor. diff --git a/src/main/java/ch/epfl/leb/defcon/predictors/Predictor.java b/src/main/java/ch/epfl/leb/defcon/predictors/Predictor.java index b5e8079..c525e41 100644 --- a/src/main/java/ch/epfl/leb/defcon/predictors/Predictor.java +++ b/src/main/java/ch/epfl/leb/defcon/predictors/Predictor.java @@ -18,9 +18,6 @@ */ package ch.epfl.leb.defcon.predictors; -import ch.epfl.leb.defcon.predictors.internal.SessionClosedException; -import ch.epfl.leb.defcon.predictors.internal.ImageBitDepthException; -import ch.epfl.leb.defcon.predictors.internal.UninitializedPredictorException; import ij.process.ImageProcessor; import ij.process.FloatProcessor; diff --git a/src/main/java/ch/epfl/leb/defcon/predictors/internal/SessionClosedException.java b/src/main/java/ch/epfl/leb/defcon/predictors/SessionClosedException.java similarity index 95% rename from src/main/java/ch/epfl/leb/defcon/predictors/internal/SessionClosedException.java rename to src/main/java/ch/epfl/leb/defcon/predictors/SessionClosedException.java index 3af6df8..569159f 100644 --- a/src/main/java/ch/epfl/leb/defcon/predictors/internal/SessionClosedException.java +++ b/src/main/java/ch/epfl/leb/defcon/predictors/SessionClosedException.java @@ -16,7 +16,7 @@ * along with this program. If not, see * . */ -package ch.epfl.leb.defcon.predictors.internal; +package ch.epfl.leb.defcon.predictors; /** * Raised when a prediction is requested but the TensorFlow session has already been closed. diff --git a/src/main/java/ch/epfl/leb/defcon/predictors/internal/UninitializedPredictorException.java b/src/main/java/ch/epfl/leb/defcon/predictors/UninitializedPredictorException.java similarity index 95% rename from src/main/java/ch/epfl/leb/defcon/predictors/internal/UninitializedPredictorException.java rename to src/main/java/ch/epfl/leb/defcon/predictors/UninitializedPredictorException.java index 352b409..9547f29 100644 --- a/src/main/java/ch/epfl/leb/defcon/predictors/internal/UninitializedPredictorException.java +++ b/src/main/java/ch/epfl/leb/defcon/predictors/UninitializedPredictorException.java @@ -16,7 +16,7 @@ * along with this program. If not, see * . */ -package ch.epfl.leb.defcon.predictors.internal; +package ch.epfl.leb.defcon.predictors; /** * Raised when a predictor has not yet been fully initialized. diff --git a/src/main/java/ch/epfl/leb/defcon/predictors/internal/DefaultPredictor.java b/src/main/java/ch/epfl/leb/defcon/predictors/internal/DefaultPredictor.java index 6170b09..3285d0f 100644 --- a/src/main/java/ch/epfl/leb/defcon/predictors/internal/DefaultPredictor.java +++ b/src/main/java/ch/epfl/leb/defcon/predictors/internal/DefaultPredictor.java @@ -18,6 +18,9 @@ */ package ch.epfl.leb.defcon.predictors.internal; +import ch.epfl.leb.defcon.predictors.ImageBitDepthException; +import ch.epfl.leb.defcon.predictors.SessionClosedException; +import ch.epfl.leb.defcon.predictors.UninitializedPredictorException; import ch.epfl.leb.defcon.predictors.Predictor; import ij.gui.Roi;