Skip to content

Commit

Permalink
Merge pull request #7 from LEB-EPFL/ADD_MLC_routines
Browse files Browse the repository at this point in the history
Added max. local count methods to the predictor interface
  • Loading branch information
kmdouglass authored Jun 5, 2018
2 parents 18ca689 + fa81f2b commit b4ea5df
Show file tree
Hide file tree
Showing 7 changed files with 183 additions and 6 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
# Change Log
All notable changes to this project will be documented in this file.

## [v0.1.0]

### Added
- Two new methods were added to the `Predictor` interface:
`getLocalCountMap()` and `getMaximumLocalCount()`. These allow for a
more flexible means for computing maximum local counts than the
TensorFlow implementation.

## [v0.0.2]

### Added
Expand All @@ -25,6 +33,8 @@ All notable changes to this project will be documented in this file.

- Initial project files.

[Unreleased]: https://github.com/LEB-EPFL/DEFCoN-ImageJ/compare/v0.1.0...HEAD
[v0.1.0]: https://github.com/LEB-EPFL/DEFCoN-ImageJ/releases/tag/0.1.0
[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
4 changes: 2 additions & 2 deletions docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@
author = 'Baptiste Ottino, Kyle M. Douglass'

# The short X.Y version
version = '0.0.2'
version = '0.1.0'
# The full version, including alpha/beta/rc tags
release = '0.0.2'
release = '0.1.0'


# -- General configuration ---------------------------------------------------
Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
<parent>
<groupId>org.scijava</groupId>
<artifactId>pom-scijava</artifactId>
<version>19.2.0</version>
<version>22.3.0</version>
<relativePath />
</parent>

<groupId>ch.epfl.leb</groupId>
<artifactId>DEFCoN_</artifactId>
<version>0.0.2</version>
<version>0.1.0</version>

<name>DEFCoN-ImageJ</name>
<description>ImageJ plugin for DEFCoN, a fluorescence spot counter using fully convolutional neural networks.</description>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/**
* Copyright (C) 2018 Laboratory of Experimental Biophysics
* Ecole Polytechnique Federale de Lausanne (EPFL), Switzerland
*
* This program is free software: you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see
* <http://www.gnu.org/licenses/>.
*/
package ch.epfl.leb.defcon.predictors;

/**
* Raised when a predictor has not yet made a local count map estimation.
*
* @author Kyle M. Douglass
*/
public class NoLocalCountMapException extends Exception {

public NoLocalCountMapException(String msg) {
super(msg);
}

}
23 changes: 23 additions & 0 deletions src/main/java/ch/epfl/leb/defcon/predictors/Predictor.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,29 @@ public interface Predictor {
*/
public FloatProcessor getDensityMap() throws UninitializedPredictorException;

/**
* Returns the most recently-calculated local count map.
*
* @return The most recently calculated local count map.
* @throws ch.epfl.leb.defcon.predictors.NoLocalCountMapException
*/
public FloatProcessor getLocalCountMap() throws NoLocalCountMapException;

/**
* Returns the maximum local count value.
*
* This value is obtained by convolving the density map with a square kernel
* whose values are all 1 and then taking the maximum of the resulting map.
* It effectively produces the highest count value over length scales equal
* to the size of the kernel.
*
* @param boxSize The width of the square kernel.
* @return The maximum local count from the density map.
* @throws ch.epfl.leb.defcon.predictors.UninitializedPredictorException
*/
public double getMaximumLocalCount(int boxSize)
throws UninitializedPredictorException;

/**
* Makes a density map prediction from a 2D image.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import ch.epfl.leb.defcon.predictors.ImageBitDepthException;
import ch.epfl.leb.defcon.predictors.SessionClosedException;
import ch.epfl.leb.defcon.predictors.NoLocalCountMapException;
import ch.epfl.leb.defcon.predictors.UninitializedPredictorException;
import ch.epfl.leb.defcon.predictors.Predictor;

Expand All @@ -29,8 +30,10 @@
import ij.process.FloatProcessor;
import ij.process.ShortProcessor;
import ij.process.ImageProcessor;
import java.awt.Rectangle;
import ij.plugin.filter.Convolver;

import java.awt.Rectangle;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;

Expand All @@ -57,6 +60,11 @@ public class DefaultPredictor extends AbstractPredictor implements Predictor {
*/
private FloatProcessor densityMap;

/**
* The most-recently computer maximum local count map.
*/
private FloatProcessor localCountMap;

/**
* Checks that an image's dimensions are divisible by four and crops it if not.
*
Expand Down Expand Up @@ -98,12 +106,65 @@ public double getCount() throws UninitializedPredictorException {
public FloatProcessor getDensityMap() throws UninitializedPredictorException {
if (densityMap == null) {
String msg = "The Predictor has not yet performed any calcuations.";
LOGGER.log(Level.WARNING, msg);
LOGGER.log(Level.SEVERE, msg);
throw new UninitializedPredictorException(msg);
}
return densityMap;
}

/**
* Returns the most recently-calculated local count map.
*
* @return The most recently calculated local count map.
* @throws ch.epfl.leb.defcon.predictors.NoLocalCountMapException
*/
@Override
public FloatProcessor getLocalCountMap() throws NoLocalCountMapException {
if (localCountMap == null) {
String msg = "The Predictor has not yet performed any local " +
"count estimates.";
LOGGER.log(Level.SEVERE, msg);
throw new NoLocalCountMapException(msg);
}
return localCountMap;
}

/**
* Returns the maximum local count value.
*
* This value is obtained by convolving the density map with a square kernel
* whose values are all 1 and then taking the maximum of the resulting map.
* It effectively produces the highest count value over length scales equal
* to the size of the kernel.
*
* @param boxSize The width of the square kernel.
* @return The maximum local count from the density map.
* @throws ch.epfl.leb.defcon.predictors.UninitializedPredictorException
*/
@Override
public double getMaximumLocalCount(int boxSize)
throws UninitializedPredictorException {
if (densityMap == null) {
String msg = "The Predictor has not yet performed any calcuations.";
LOGGER.log(Level.WARNING, msg);
throw new UninitializedPredictorException(msg);
}
Convolver convolver = new Convolver();
convolver.setNormalize(false);
localCountMap = (FloatProcessor) densityMap.clone();
float kernel[] = new float[boxSize * boxSize];
Arrays.fill(kernel, 1.0f);

convolver.convolveFloat(localCountMap, kernel, boxSize, boxSize);
int halfBoxSize = boxSize / 2;
localCountMap.setRoi(new Roi(halfBoxSize, halfBoxSize,
localCountMap.getWidth() - boxSize + 1 ,
localCountMap.getHeight() - boxSize + 1));
localCountMap = localCountMap.crop().convertToFloatProcessor();
localCountMap.resetMinAndMax();
return localCountMap.getMax();
}

/**
* Makes a density map prediction from a 2D 8-bit image.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import ij.IJ;
import ij.ImagePlus;
import ij.plugin.SubstackMaker;
import ij.process.ImageProcessor;
import ij.process.FloatProcessor;

Expand Down Expand Up @@ -124,6 +125,56 @@ public void testGetDensityMapResized() throws Exception {
assertEquals(imp.getWidth() - 4, fp.getWidth());
assertEquals(imp.getHeight() - 4, fp.getHeight());
}

/**
* Test of getLocalCountMap, of class DefaultPredictor.
* @throws java.lang.Exception
*/
@Test
public void testGetLocalCountMap() throws Exception {
System.out.println("testGetLocalCountMap");
SubstackMaker sub = new SubstackMaker();
ImagePlus newImp = sub.makeSubstack(imp, "1");
ImageProcessor ip = newImp.getProcessor();

predictor.predict(ip);
int boxSize = 7;
double expectedResult = 1.018;
predictor.getMaximumLocalCount(boxSize);
predictor.close();

FloatProcessor fp = predictor.getLocalCountMap();
assertEquals(expectedResult, fp.getMax(), 0.001);
assertEquals(ip.getWidth() - boxSize + 1, fp.getWidth());
assertEquals(ip.getHeight() - boxSize + 1, fp.getHeight());
}

/**
* Test of getMaximumLocalCount, of class DefaultPredictor.
* @throws java.lang.Exception
*/
@Test
public void testGetMaximumLocalCount() throws Exception {
System.out.println("testGetMaximumLocalCount");
SubstackMaker sub = new SubstackMaker();
ImagePlus newImp = sub.makeSubstack(imp, "1");
ImageProcessor ip = newImp.getProcessor();

predictor.predict(ip);
int boxSize = 7;
double expectedResult = 1.018;
double result = predictor.getMaximumLocalCount(boxSize);
assertEquals(expectedResult, result, 0.001);

newImp = sub.makeSubstack(imp, "2");
ip = newImp.getProcessor();
predictor.predict(ip);
expectedResult = 1.023;
result = predictor.getMaximumLocalCount(boxSize);
assertEquals(expectedResult, result, 0.001);
predictor.close();

}

/**
* Test of predict method, of class DefaultPredictor.
Expand Down

0 comments on commit b4ea5df

Please sign in to comment.