Skip to content

Commit

Permalink
Updated contour scaling to preserve groups of objects across color
Browse files Browse the repository at this point in the history
  • Loading branch information
CellDynamics committed Jan 10, 2018
1 parent 8c7d4f4 commit 7f2ce93
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 23 deletions.
20 changes: 20 additions & 0 deletions src/main/java/com/github/celldynamics/quimp/geom/TrackOutline.java
Expand Up @@ -2,6 +2,7 @@

import java.awt.Color;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang3.tuple.ImmutablePair;
Expand Down Expand Up @@ -276,6 +277,25 @@ public Pair<List<Outline>, List<Color>> getOutlinesColors(double step, boolean s
return new ImmutablePair<List<Outline>, List<Color>>(outlines, colors);
}

/**
* Reformat collected outlines and Colors to list of pairs.
*
* @param step resolution step
* @param smooth true to use IJ polygon smoothing (running average).
* @return List of pairs, outlines and colors of pixels they were created from
*/
public List<Pair<Outline, Color>> getPairs(double step, boolean smooth) {
List<Outline> out = getOutlinesColors(step, smooth).getLeft();
List<Pair<Outline, Color>> ret = new ArrayList<>();
Iterator<Outline> ito = out.iterator();
Iterator<Color> itc = colors.iterator();
while (ito.hasNext() && itc.hasNext()) {
Pair<Outline, Color> p = new ImmutablePair<Outline, Color>(ito.next(), itc.next());
ret.add(p);
}
return ret;
}

/**
* Erase roi on image stored in object with color bckColor.
*
Expand Down
Expand Up @@ -3,9 +3,13 @@
import java.awt.Color;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang3.tuple.Pair;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -110,7 +114,7 @@ public PropagateSeeds(boolean storeSeeds, AutoThresholder.Method trueBackground)
/**
* Default resolution used during outlining objects.
*
* @see Contour#getOutline(ImageProcessor)
* @see Contour#getOutlineAndColors(ImageProcessor)
*/
public static final int STEPS = 4;
/**
Expand Down Expand Up @@ -522,6 +526,10 @@ public Contour(boolean storeSeeds, AutoThresholder.Method trueBackground, double
* <p>Setting <tt>shrinkPower</tt> or <tt>expandPower</tt> to zero prevents contour
* modifications.
*
* <p>Algorithm can utilise object colour to process them in groups within one colour. Objects
* in one group are processed separately, but then all are stored in the same {@link Seeds}
* {@link SeedTypes#FOREGROUNDS} map.
*
* @param previous Previous result of segmentation. BW mask with white object on black
* background.
* @param org original image that new seeds are computed for. Usually it is current image
Expand All @@ -538,29 +546,51 @@ public Contour(boolean storeSeeds, AutoThresholder.Method trueBackground, double
@Override
public Seeds propagateSeed(ImageProcessor previous, ImageProcessor org, double shrinkPower,
double expandPower) {
// FIXME if there are two separate objects in the same color they will be treated as
// separate objects. Binary seeds is not affected (due to SeedProcessor.getGrayscaleAsSeeds)
double stepsshrink = shrinkPower / stepSize; // total shrink/step size
double stepsexp = (expandPower) / stepSize; // total shrink/step size
Seeds ret = new Seeds(2);

List<Outline> outlines = getOutline(previous); // this supports grayscales
// this supports grayscales;
List<Pair<Outline, Color>> oc = getPairsOutlineAndColors(previous);
// sort according to colors, need to collect outlines with the same object color in the same
// map
Collections.sort(oc, new Comparator<Pair<Outline, Color>>() {

@Override
public int compare(Pair<Outline, Color> o1, Pair<Outline, Color> o2) {
Color c1 = o1.getRight();
Color c2 = o2.getRight();
Integer ci1 = new Integer(c1.getRed() + c1.getBlue() + c1.getGreen());
Integer ci2 = new Integer(c2.getRed() + c2.getBlue() + c2.getGreen());
return ci1.compareTo(ci2);
}
});

Iterator<Pair<Outline, Color>> oci = oc.iterator();

// save extra debug info if property set
if (QuimP.SUPER_DEBUG) {
String tmp = System.getProperty("java.io.tmpdir");
for (Outline o : outlines) {
for (Pair<Outline, Color> o : oc) {
long time = new Date().getTime();
RoiSaver.saveRoi(
tmp + File.separator + "propagateSeed_" + time + "_" + outlines.hashCode(),
o.asList());
RoiSaver.saveRoi(tmp + File.separator + "propagateSeed_" + time + "_" + oc.hashCode(),
o.getLeft().asList());
}
}
for (Outline o : outlines) {
int cprev = -1; // previous object color, IT CANT EXIST IN LIST
ByteProcessor small = null;
while (oci.hasNext()) {
Pair<Outline, Color> p = oci.next();
Outline o = p.getLeft();
Color c = p.getRight();
// restore int (see TrackOutline.getColors())
int color = c.getRed() + c.getBlue() + c.getGreen();
if (o.getNumPoints() < 4) {
continue;
}
ByteProcessor small = new ByteProcessor(previous.getWidth(), previous.getHeight());
if (color != cprev) { // if new color, create new processor (list is sorted)
small = new ByteProcessor(previous.getWidth(), previous.getHeight());
}
small.setColor(Color.WHITE); // for fill(Roi)
// shrink outline - copy as we want to expand it later
Outline copy = new Outline(o);
Expand All @@ -575,13 +605,17 @@ public Seeds propagateSeed(ImageProcessor previous, ImageProcessor org, double s
small.fill(fr);
small.drawRoi(fr);
// small.resetRoi();
ret.put(SeedTypes.FOREGROUNDS, small);
if (color != cprev) { // store only new, old will be updated by reference
ret.put(SeedTypes.FOREGROUNDS, small);
}
cprev = color; // for next iter
}

ByteProcessor big = new ByteProcessor(previous.getWidth(), previous.getHeight());
// big.setColor(Color.BLACK);
// big.fill();
for (Outline o : outlines) {
for (Pair<Outline, Color> p : oc) {
Outline o = p.getLeft();
if (o.getNumPoints() < 4) {
continue;
}
Expand Down Expand Up @@ -611,12 +645,26 @@ public Seeds propagateSeed(ImageProcessor previous, ImageProcessor org, double s
* Convert mask to outline.
*
* @param previous image to be converted outline. White object on black background.
* @return List of Outline for current frame
* @return List of Outline for current frame and colors
* @see TrackOutline
* @see #getOutlineAndColors(ImageProcessor)
*/
public static Pair<List<Outline>, List<Color>> getOutlineAndColors(ImageProcessor previous) {
TrackOutlineLocal track = new TrackOutlineLocal(previous, 0);
return track.getOutlinesColors(STEPS, false);
}

/**
* Convert mask to outline.
*
* @param previous image to be converted outline. White object on black background.
* @return List of Outline for current frame and colors enclosed in pairs
* @see TrackOutline
* @see #getOutlineAndColors(ImageProcessor)
*/
public static List<Outline> getOutline(ImageProcessor previous) {
public static List<Pair<Outline, Color>> getPairsOutlineAndColors(ImageProcessor previous) {
TrackOutlineLocal track = new TrackOutlineLocal(previous, 0);
return track.getOutlines(STEPS, false);
return track.getPairs(STEPS, false);
}

}
Expand Down
2 changes: 1 addition & 1 deletion src/test/Resources-static
Submodule Resources-static updated from 1b1963 to 005135
Expand Up @@ -2,6 +2,7 @@

import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.Assert.assertThat;

import java.awt.Color;
Expand Down Expand Up @@ -204,7 +205,7 @@ public void testGetOutlinesDoubleBoolean() throws Exception {
/**
* Test if color is handled correctly,
*
* @throws Exception
* @throws Exception Exception
*/
@Test
public void testGetOutlinesColors() throws Exception {
Expand All @@ -216,4 +217,15 @@ public void testGetOutlinesColors() throws Exception {
assertThat(ret.getRight(), is(obj.getColors()));
}

/**
* Test of {@link TrackOutline#getPairs(double, boolean)}
*
* @throws Exception Exception
*/
@Test
public void testGetPairs() throws Exception {
List<Pair<Outline, Color>> ret = obj.getPairs(2, false);
assertThat(ret, hasSize(3));
}

}
Expand Up @@ -129,9 +129,10 @@ public void tearDown() throws Exception {
*/
@SuppressWarnings("unchecked")
@Test
public void testGetOutline() throws Exception {
public void testGetOutlineAndColors() throws Exception {
PropagateSeeds.Contour cc = new PropagateSeeds.Contour();
List<Outline> ret = PropagateSeeds.Contour.getOutline(testImage2.getProcessor());
List<Outline> ret =
PropagateSeeds.Contour.getOutlineAndColors(testImage2.getProcessor()).getLeft();

int i = 0;
for (Outline o : ret) {
Expand Down Expand Up @@ -192,7 +193,7 @@ public void testGetCompositeSeed_Contour1() throws Exception {
Seeds ret = cc.propagateSeed(ip.getProcessor(), ip.getProcessor(), 2, 10);
assertThat(ret.size(), is(2));
assertThat(ret.get(SeedTypes.BACKGROUND).size(), is(1));
assertThat(ret.get(SeedTypes.FOREGROUNDS).size(), is(5));
assertThat(ret.get(SeedTypes.FOREGROUNDS).size(), is(3)); // 3 groups of objects (colors)
ImageStack is = ret.convertToStack(SeedTypes.BACKGROUND);
IJ.saveAsTiff(new ImagePlus("", is), tmpdir + "testGetCompositeSeed_Contour1_B_QuimP.tif");
is = ret.convertToStack(SeedTypes.FOREGROUNDS);
Expand Down Expand Up @@ -247,13 +248,14 @@ public void testPropagateSeedsNonlinear_Example() throws Exception {
ImagePlus ip = IJ.openImage("src/test/Resources-static/239/shape1.tif");
PropagateSeeds.Contour cc = new PropagateSeeds.Contour(false, null, 0.35, 5, 1, 6);

Outline outlineOrg = Contour.getOutline(ip.getProcessor()).get(0);
Outline outlineOrg = Contour.getOutlineAndColors(ip.getProcessor()).getLeft().get(0);
new OutlineProcessor<Outline>(outlineOrg).averageCurvature(1).sumCurvature(1);
Seeds ret = cc.propagateSeed(ip.getProcessor(), ip.getProcessor(), 5, 10);
Outline outlineSh = Contour.getOutline(ret.get(SeedTypes.FOREGROUNDS, 1)).get(0);
Outline outlineSh =
Contour.getOutlineAndColors(ret.get(SeedTypes.FOREGROUNDS, 1)).getLeft().get(0);
ImageProcessor bck = ret.get(SeedTypes.BACKGROUND, 1);
bck.invert();
Outline outlineEx = Contour.getOutline(bck).get(0);
Outline outlineEx = Contour.getOutlineAndColors(bck).getLeft().get(0);

RoiSaver.saveRois(tmpdir + "reo.tif", 512, 512, outlineOrg.asList(), Color.GREEN,
outlineSh.asList(), Color.RED, outlineEx.asList(), Color.BLUE);
Expand Down

0 comments on commit 7f2ce93

Please sign in to comment.