Skip to content
Snippets Groups Projects
Commit f931a1e3 authored by Jean-Yves Tinevez's avatar Jean-Yves Tinevez
Browse files

Region growing: tidy demo a little bit

parent 55caffd7
Branches
No related tags found
No related merge requests found
......@@ -14,27 +14,17 @@ import javax.xml.parsers.ParserConfigurationException;
import mpicbg.spim.data.SequenceDescription;
import net.imglib2.Interval;
import net.imglib2.RandomAccess;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.RealLocalizable;
import net.imglib2.RealPoint;
import net.imglib2.algorithm.region.localneighborhood.HyperSphereShape;
import net.imglib2.algorithm.region.localneighborhood.Neighborhood;
import net.imglib2.converter.TypeIdentity;
import net.imglib2.display.AbstractLinearRange;
import net.imglib2.display.RealARGBColorConverter;
import net.imglib2.histogram.DiscreteFrequencyDistribution;
import net.imglib2.histogram.Histogram1d;
import net.imglib2.histogram.Real1dBinMapper;
import net.imglib2.labeling.LabelingType;
import net.imglib2.position.transform.Round;
import net.imglib2.realtransform.AffineTransform3D;
import net.imglib2.type.numeric.ARGBType;
import net.imglib2.type.numeric.integer.UnsignedShortType;
import net.imglib2.ui.TransformEventHandler;
import net.imglib2.util.Intervals;
import net.imglib2.util.LinAlgHelpers;
import net.imglib2.view.IntervalView;
import net.imglib2.view.Views;
import org.jdom2.JDOMException;
......@@ -55,18 +45,15 @@ import viewer.util.Affine3DHelpers;
public class Demo {
private ArrayList<AbstractLinearRange> displayRanges;
private LabellingSource overlay;
private LabelingSource overlay;
private final SpimViewer viewer;
private int nTimepoints;
private ArrayList<SourceAndConverter<?>> sources;
private List<SourceAndConverter<?>> sources;
private SetupAssignments setupAssignments;
private final BrightnessDialog brightnessDialog;
private int nextCellId = 0;
private final int defaultRadius = 5;
private boolean editMode = false;
private TransformEventHandler<AffineTransform3D> transformEventHandler;
private final RegionGrowingAnnotationTool regionGrowingAnnotationTool;
private RegionGrowingAnnotationTool<?> regionGrowingAnnotationTool;
public Demo(final File file) throws ParserConfigurationException, SAXException, IOException, InstantiationException, IllegalAccessException, ClassNotFoundException, JDOMException {
......@@ -80,12 +67,6 @@ public class Demo {
initTransform(viewer, 800, 600);
initBrightness(viewer, 0, 1);
/*
* Region annotation listener
*/
regionGrowingAnnotationTool = new RegionGrowingAnnotationTool(viewer, sources.get(0).getSpimSource(), overlay, 0, 0);
/*
* Brightness
*/
......@@ -151,25 +132,13 @@ public class Demo {
setupAssignments.moveSetupToGroup(setup, group);
}
overlay = new LabellingSource(sources.get(0).getSpimSource());
overlay = new LabelingSource(sources.get(0).getSpimSource());
sources.add(new SourceAndConverter<ARGBType>(overlay, new TypeIdentity<ARGBType>()));
overlay.getSource(0, 0);
}
private SpimViewer newViewer() {
final SpimViewer viewer = new SpimViewer(800, 600, sources, nTimepoints);
viewer.addKeyAction(KeyStroke.getKeyStroke("A"), new AbstractAction("add cell") {
@Override
public void actionPerformed(final ActionEvent arg0) {
final RealPoint p = new RealPoint(3);
viewer.getGlobalMouseCoordinates(p);
addCellAt(p);
}
private static final long serialVersionUID = 1L;
});
viewer.addKeyAction(KeyStroke.getKeyStroke("ESCAPE"), new AbstractAction("toggle mode") {
@Override
public void actionPerformed(final ActionEvent arg0) {
......@@ -289,66 +258,7 @@ public class Demo {
viewer.setCurrentViewerTransform(viewerTransform);
}
synchronized void addCellAt(final RealLocalizable p) {
final int cellId = nextCellId;
++nextCellId;
final int radius = defaultRadius;
addLabelHyperSphere(p, radius, cellId);
overlay.updateColorTable();
viewer.requestRepaint();
}
synchronized void removeCellsAt(final RealLocalizable p) {
final RandomAccess<LabelingType<Integer>> a = overlay.getCurrentLabelling().randomAccess();
new Round<RandomAccess<LabelingType<Integer>>>(a).setPosition(p);
// TODO
overlay.updateColorTable();
viewer.requestRepaint();
}
synchronized void modifiyCellRadiusAt(final RealPoint p, final int diff) {
final RandomAccess<LabelingType<Integer>> a = overlay.getCurrentLabelling().randomAccess();
new Round<RandomAccess<LabelingType<Integer>>>(a).setPosition(p);
for (final Integer label : a.get().getLabeling()) {
// TODO
}
overlay.updateColorTable();
viewer.requestRepaint();
}
private void addLabelHyperSphere(final RealLocalizable centerGlobal, final int radius, final Integer label) {
final AffineTransform3D globalToSource = overlay.getSourceTransform(viewer.getState().getCurrentTimepoint(), 0).inverse();
final RealPoint centerLocal = new RealPoint(centerGlobal.numDimensions());
globalToSource.apply(centerGlobal, centerLocal);
final HyperSphereShape sphere = new HyperSphereShape(radius);
final IntervalView<LabelingType<Integer>> ext = Views.interval(Views.extendValue(overlay.getCurrentLabelling(), new LabelingType<Integer>()), Intervals.expand(overlay.getCurrentLabelling(), radius));
final RandomAccess<Neighborhood<LabelingType<Integer>>> na = sphere.neighborhoodsRandomAccessible(ext).randomAccess();
new Round<RandomAccess<Neighborhood<LabelingType<Integer>>>>(na).setPosition(centerLocal);
for (final LabelingType<Integer> t : na.get()) {
final List<Integer> l = t.getLabeling();
if (!l.contains(label)) {
final ArrayList<Integer> labels = new ArrayList<Integer>(t.getLabeling());
labels.add(label);
t.setLabeling(labels);
}
}
}
private void removeLabelHyperSphere(final RealLocalizable center, final int radius, final Integer label) {
final HyperSphereShape sphere = new HyperSphereShape(radius);
final IntervalView<LabelingType<Integer>> ext = Views.interval(Views.extendValue(overlay.getCurrentLabelling(), new LabelingType<Integer>()), Intervals.expand(overlay.getCurrentLabelling(), radius));
final RandomAccess<Neighborhood<LabelingType<Integer>>> na = sphere.neighborhoodsRandomAccessible(ext).randomAccess();
new Round<RandomAccess<Neighborhood<LabelingType<Integer>>>>(na).setPosition(center);
for (final LabelingType<Integer> t : na.get()) {
final List<Integer> l = t.getLabeling();
if (l.contains(label)) {
final ArrayList<Integer> labels = new ArrayList<Integer>(t.getLabeling());
labels.remove(label);
t.setLabeling(labels);
}
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
private void toggleMode() {
this.editMode = !editMode;
System.out.println(editMode);// DEBUG
......@@ -356,6 +266,10 @@ public class Demo {
if (editMode) {
transformEventHandler = viewer.getDisplay().getTransformEventHandler();
viewer.getDisplay().removeHandler(transformEventHandler);
final int currentSource = viewer.getState().getCurrentSource();
final int timePoint = viewer.getState().getCurrentTimepoint();
regionGrowingAnnotationTool = new RegionGrowingAnnotationTool(viewer, sources.get(currentSource).getSpimSource(), overlay, timePoint);
viewer.getDisplay().addHandler(regionGrowingAnnotationTool);
} else {
viewer.getDisplay().removeHandler(regionGrowingAnnotationTool);
......@@ -367,7 +281,7 @@ public class Demo {
ImageJ.main(args);
final File file = new File("/Users/tinevez/Desktop/Data/Mamut/parhyale-crop/parhyale-crop-2.xml");
final Demo plugin = new Demo(file);
new Demo(file);
}
}
......@@ -2,6 +2,7 @@ package viewer.render.labelling;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import net.imglib2.Dimensions;
......@@ -25,7 +26,16 @@ import viewer.display.LabelingTypeARGBConverter;
import viewer.render.Interpolation;
import viewer.render.Source;
public class LabellingSource implements Source<ARGBType> {
/**
* A {@link Source} that wraps a {@link NativeImgLabeling}, build from another
* source and copying its dimension and transform at the lowest level only (=0).
*
* @author Jean-Yves Tinevez <jeanyves.tinevez@gmail.com> 2013
* @author Tobias Pietzsch
* @author Stephan Preibisch
*
*/
public class LabelingSource implements Source<ARGBType> {
private int currentTimepoint;
private NativeImgLabeling<Integer, IntType> currentSource;
......@@ -34,7 +44,7 @@ public class LabellingSource implements Source<ARGBType> {
private final String name;
final LabelingTypeARGBConverter<Integer> converter;
private final LabelingTypeARGBConverter<Integer> converter;
final protected static int numInterpolationMethods = 2;
......@@ -44,20 +54,29 @@ public class LabellingSource implements Source<ARGBType> {
final protected InterpolatorFactory<ARGBType, RandomAccessible<ARGBType>>[] interpolatorFactories;
final AffineTransform3D sourceTransform = new AffineTransform3D();
private volatile int oldAlpha = -1;
private int currentAlpha;
/**
* The map that stores the labeling for each time point. Its values are all
* <code>null</code> until the target time-point is initialized.
*/
private final Map<Integer, NativeImgLabeling<Integer, IntType>> labelings;
private final AffineTransform3D currentTranform = new AffineTransform3D();
@SuppressWarnings("unchecked")
public LabellingSource(final Source<?> imgSource) {
public LabelingSource(final Source<?> imgSource) {
this.imgSource = imgSource;
name = imgSource.getName() + " annotations";
converter = new LabelingTypeARGBConverter<Integer>(new HashMap<List<Integer>, ARGBType>());
interpolatorFactories = new InterpolatorFactory[numInterpolationMethods];
interpolatorFactories[iNearestNeighborMethod] = new NearestNeighborInterpolatorFactory<ARGBType>();
interpolatorFactories[iNLinearMethod] = new NLinearInterpolatorFactory<ARGBType>();
labelings = new HashMap<Integer, NativeImgLabeling<Integer, IntType>>();
loadTimepoint(0);
}
......@@ -88,11 +107,15 @@ public class LabellingSource implements Source<ARGBType> {
private void loadTimepoint(final int timepoint) {
currentTimepoint = timepoint;
if (isPresent(timepoint)) {
sourceTransform.set(imgSource.getSourceTransform(timepoint, 0));
final Dimensions sourceDimensions = imgSource.getSource(timepoint, 0);
final NtreeImgFactory<IntType> factory = new NtreeImgFactory<IntType>();
final Img<IntType> img = factory.create(sourceDimensions, new IntType());
final NativeImgLabeling<Integer, IntType> labeling = new NativeImgLabeling<Integer, IntType>(img);
currentTranform.set(imgSource.getSourceTransform(timepoint, 0));
NativeImgLabeling<Integer, IntType> labeling = labelings.get(Integer.valueOf(timepoint));
if (null == labeling) {
final Dimensions sourceDimensions = imgSource.getSource(timepoint, 0);
labeling = newLabeling(sourceDimensions);
labelings.put(Integer.valueOf(timepoint), labeling);
}
currentSource = labeling;
updateColorTable();
} else
......@@ -101,9 +124,10 @@ public class LabellingSource implements Source<ARGBType> {
@Override
public AffineTransform3D getSourceTransform(final int t, final int level) {
if (t != currentTimepoint)
if (currentTimepoint != t) {
loadTimepoint(t);
return sourceTransform;
}
return currentTranform;
}
@Override
......@@ -116,8 +140,38 @@ public class LabellingSource implements Source<ARGBType> {
return name;
}
public NativeImgLabeling<Integer, IntType> getCurrentLabelling() {
return currentSource;
public NativeImgLabeling<Integer, IntType> getLabeling(final int t) {
NativeImgLabeling<Integer, IntType> target;
if (isPresent(t)) {
target = labelings.get(Integer.valueOf(t));
if (null == target) {
final Dimensions sourceDimensions = imgSource.getSource(t, 0);
target = newLabeling(sourceDimensions);
labelings.put(Integer.valueOf(t), target);
}
} else {
target = null;
}
return target;
}
/**
* Sets the transparency (alpha value) for this source.
*
* @param alpha
* an <code>int</code>, ranging from 0 to 255.
*/
public void setAlpha(final int alpha) {
this.currentAlpha = alpha;
}
/**
* Returns the current transparency (alpha value) for this source.
*
* @return an <code>int</code>, ranging from 0 to 255.
*/
public int getAlpha() {
return currentAlpha;
}
public void updateColorTable() {
......@@ -137,4 +191,12 @@ public class LabellingSource implements Source<ARGBType> {
converter.setColorTable(colorTable);
oldAlpha = a;
}
private static final NativeImgLabeling<Integer, IntType> newLabeling(final Dimensions dimensions) {
final NtreeImgFactory<IntType> factory = new NtreeImgFactory<IntType>();
final Img<IntType> img = factory.create(dimensions, new IntType());
final NativeImgLabeling<Integer, IntType> labeling = new NativeImgLabeling<Integer, IntType>(img);
return labeling;
}
}
......@@ -11,39 +11,54 @@ import java.util.Map;
import net.imglib2.IterableInterval;
import net.imglib2.Point;
import net.imglib2.RandomAccess;
import net.imglib2.RandomAccessibleInterval;
import net.imglib2.RealPoint;
import net.imglib2.algorithm.regiongrowing.RegionGrowingTools.GrowingMode;
import net.imglib2.algorithm.regiongrowing.ThresholdRegionGrowing;
import net.imglib2.labeling.LabelingType;
import net.imglib2.labeling.NativeImgLabeling;
import net.imglib2.ops.operation.randomaccessibleinterval.unary.regiongrowing.AbstractRegionGrowing;
import net.imglib2.position.transform.Round;
import net.imglib2.realtransform.AffineTransform3D;
import net.imglib2.roi.IterableRegionOfInterest;
import net.imglib2.type.numeric.RealType;
import net.imglib2.type.numeric.integer.IntType;
import viewer.SpimViewer;
import viewer.render.Source;
public class RegionGrowingAnnotationTool<T extends RealType<T>> implements MouseListener, MouseMotionListener {
private final int level;
private final SpimViewer viewer;
private Map<long[], Integer> seed;
private final LabellingSource labelingSource;
private int label = -1;
private final Source<T> source;
private final int t;
private final LabelingSource labelingSource;
private int label = 0;
private final long[][] structuringElement;
private final GrowingMode growingMode;
public RegionGrowingAnnotationTool(final SpimViewer viewer, final Source<T> source, final LabellingSource labellingSource, final int t, final int level) {
private final NativeImgLabeling<Integer, IntType> labeling;
/**
* A {@link RandomAccess} to the source image.
*/
private final RandomAccess<T> ra;
/**
* The transform that maps source coordinates to mouse coordinates.
*/
private final AffineTransform3D sourceToGlobal;
public RegionGrowingAnnotationTool(final SpimViewer viewer, final Source<T> source, final LabelingSource labellingSource, final int t) {
this.viewer = viewer;
this.source = source;
this.labelingSource = labellingSource;
this.t = t;
this.level = level;
this.labeling = labellingSource.getLabeling(t);
this.ra = source.getSource(t, 0).randomAccess();
this.sourceToGlobal = source.getSourceTransform(t, 0);
this.structuringElement = AbstractRegionGrowing.get8ConStructuringElement(3);
this.growingMode = GrowingMode.SEQUENTIAL;
int freeLabel = 0;
for (final Integer existingLabel : labeling.getLabels()) {
if (existingLabel.intValue() > freeLabel) {
freeLabel = existingLabel.intValue();
}
}
this.label = freeLabel;
}
@Override
......@@ -61,22 +76,20 @@ public class RegionGrowingAnnotationTool<T extends RealType<T>> implements Mouse
final long[] pos = new long[3];
point.localize(pos);
if (!labelingSource.getCurrentLabelling().getLabels().isEmpty()) {
if (!labeling.getLabels().isEmpty()) {
final RandomAccess<LabelingType<Integer>> randomAccess = labelingSource.getCurrentLabelling().randomAccess();
final RandomAccess<LabelingType<Integer>> randomAccess = labeling.randomAccess();
randomAccess.setPosition(point);
final List<Integer> existingLabels = randomAccess.get().getLabeling();
if (!existingLabels.isEmpty()) {
System.out.println("Found some labels under the seed point: " + existingLabels);// DEBUG
label = existingLabels.get(0).intValue(); // For future new annotation
for (final Integer existingLabel : existingLabels) {
final IterableRegionOfInterest roi = labelingSource.getCurrentLabelling().getIterableRegionOfInterest(existingLabel);
final IterableInterval<LabelingType<Integer>> overROI = roi.getIterableIntervalOverROI(labelingSource.getCurrentLabelling());
final IterableRegionOfInterest roi = labeling.getIterableRegionOfInterest(existingLabel);
final IterableInterval<LabelingType<Integer>> overROI = roi.getIterableIntervalOverROI(labeling);
for (final LabelingType<Integer> labelingType : overROI) {
final ArrayList<Integer> labels = new ArrayList<Integer>(labelingType.getLabeling());
labels.clear();
......@@ -107,13 +120,13 @@ public class RegionGrowingAnnotationTool<T extends RealType<T>> implements Mouse
* Remove old stuff
*/
if (labelingSource.getCurrentLabelling().getLabels().contains(Integer.valueOf(label))) {
if (labeling.getLabels().contains(Integer.valueOf(label))) {
final IterableRegionOfInterest iterableRegionOfInterest = labelingSource.getCurrentLabelling().getIterableRegionOfInterest(Integer.valueOf(label));
for (final LabelingType<Integer> labeling : iterableRegionOfInterest.getIterableIntervalOverROI(labelingSource.getCurrentLabelling())) {
final ArrayList<Integer> labels = new ArrayList<Integer>(labeling.getLabeling());
final IterableRegionOfInterest iterableRegionOfInterest = labeling.getIterableRegionOfInterest(Integer.valueOf(label));
for (final LabelingType<Integer> ll : iterableRegionOfInterest.getIterableIntervalOverROI(labeling)) {
final ArrayList<Integer> labels = new ArrayList<Integer>(ll.getLabeling());
labels.remove(Integer.valueOf(label));
labeling.setLabeling(labels);
ll.setLabeling(labels);
}
}
......@@ -122,36 +135,27 @@ public class RegionGrowingAnnotationTool<T extends RealType<T>> implements Mouse
* Make new stuff
*/
final RandomAccessibleInterval<T> rai = source.getSource(t, level);
final RandomAccess<T> ra = rai.randomAccess();
final Point current = getLocationOnCurrentSource();
ra.setPosition(current);
final T threshold = ra.get().copy();
final ThresholdRegionGrowing<T, Integer> regionGrowing = new ThresholdRegionGrowing<T, Integer>(ra, threshold, seed, growingMode, structuringElement, labelingSource.getCurrentLabelling());
final ThresholdRegionGrowing<T, Integer> regionGrowing = new ThresholdRegionGrowing<T, Integer>(ra, threshold, seed, growingMode, structuringElement, labeling);
regionGrowing.checkInput();
regionGrowing.process();
labelingSource.updateColorTable();
viewer.requestRepaint();
System.out.println(label + ": area = " + regionGrowing.getResult().getArea(Integer.valueOf(label)));// DEBUG
}
@Override
public void mouseMoved(final MouseEvent arg0) {}
private Point getLocationOnCurrentSource() {
// Ok, then create this spot, wherever it is.
final double[] coordinates = new double[3];
final RealPoint click = RealPoint.wrap(coordinates);
viewer.getGlobalMouseCoordinates(click);
final AffineTransform3D sourceToGlobal = source.getSourceTransform(t, level);
final Point roundedSourcePos = new Point(3);
sourceToGlobal.applyInverse(new Round<Point>(roundedSourcePos), click);
return roundedSourcePos;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment