ActionTrackPoints.java
package com.github.celldynamics.quimp.plugin.protanalysis;
import java.awt.event.ActionEvent;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.github.celldynamics.quimp.QParamsQconf;
import com.github.celldynamics.quimp.filesystem.QconfLoader;
import com.github.celldynamics.quimp.geom.MapCoordConverter;
import com.github.celldynamics.quimp.plugin.qanalysis.STmap;
import ij.ImagePlus;
import ij.WindowManager;
import ij.gui.Overlay;
import ij.plugin.ZProjector;
/**
* Generalisation of action for tracking points.
*
* <p>Read:
* <ol>
* <li>{@link ProtAnalysisOptions#chbNewImage}
* <li>{@link ProtAnalysisOptions#plotStaticDynamic}
* <li>{@link ProtAnalysisOptions#chbFlattenStaticTrackImage}
* <li>{@link ProtAnalysisOptions#chbShowTrackMotility}
* <li>{@link ProtAnalysisOptions#chbShowPoint}
* <li>{@link ProtAnalysisOptions#chbShowTrack}
* <li>{@link ProtAnalysisOptions#circleRadius}
* </ol>
*
* @author p.baniukiewicz
*
*/
@SuppressWarnings("serial")
public class ActionTrackPoints extends ProtAnalysisAbstractAction {
protected ImagePlus image; // image used for plotting overlay
/**
* Action creator.
*
* @param name name
* @param desc description
* @param ui reference to outer class.
*/
public ActionTrackPoints(String name, String desc, ProtAnalysisUi ui) {
super(name, desc, ui);
}
/**
* Initialise this action as ActionListener without properties.
*
* @param ui reference to outer class.
*/
public ActionTrackPoints(ProtAnalysisUi ui) {
super(ui);
}
/*
* (non-Javadoc)
*
* @see java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
*/
@Override
public void actionPerformed(ActionEvent e) {
if (options.chbNewImage.getValue()) { // if true = new image
image = ui.getImagePlus().duplicate();
Overlay overlay = image.getOverlay();
if (overlay != null) {
overlay.clear();
}
} else {
image = ui.getImagePlus();
}
QconfLoader qconfLoader = ui.getModel().getQconfLoader();
switch (options.plotStaticDynamic.shortValue()) {
case 0:
if (options.chbFlattenStaticTrackImage.booleanValue()) {
image = trackStaticFlat(qconfLoader); // static flat image, return new copy of image
} else {
trackStatic(qconfLoader); // static but we have slices
}
break;
case 1:
trackDynamic(qconfLoader); // dynamic
break;
default:
throw new IllegalArgumentException("Type of plot not supported.");
}
if (options.chbShowTrackMotility.booleanValue()) {
plotOnMap(qconfLoader);
}
if (options.chbNewImage.getValue()) {
image.setTitle(WindowManager.makeUniqueName(image.getTitle() + " - tracking"));
image.show(); // show new image
} else { // clear user selection at the end if no new image
new ActionClearPoints(ui).clear();
}
}
/**
* Plot tracking lines on map.
*
* @param qconfLoader qconfLoader
* @see ProtAnalysisOptions#chbShowTrackMotility
*/
void plotOnMap(QconfLoader qconfLoader) {
STmap[] stMap = ((QParamsQconf) qconfLoader.getQp()).getLoadedDataContainer().getQState();
HashMap<Integer, List<Point2D>> tmpSelected = extractPoints(stMap);
// plot - iterate over cells (keys) and plot all points
for (Map.Entry<Integer, List<Point2D>> entry : tmpSelected.entrySet()) {
Integer cellNo = entry.getKey(); // cell number
List<Point2D> points = entry.getValue(); // users points
// time - y
// outline - x
ImagePlus mm = ActionPlotMap.getUnscaledMap(stMap[cellNo], "MOT", 0,
WindowManager.makeUniqueName("motility_map_cell_" + cellNo));
// This is for unscaled map
// TrackVisualisation.Map visSingle = new TrackVisualisation.Map(
// WindowManager.makeUniqueName("motility_map_cell_" + cellNo),
// QuimPArrayUtils.double2dfloat(stMap[cellNo].getMotMap()));
TrackVisualisation.Map visSingle = new TrackVisualisation.Map(mm, true,
(double) stMap[cellNo].getRes() / stMap[cellNo].getT(), 1.0);
MaximaFinder mf = new MaximaFinder(ui.getImagePlus().getProcessor());
mf.setMaxima(points);
TrackCollection trackCollection = getTracks(stMap, cellNo, mf);
visSingle.addMaximaToImage(mf);
visSingle.addTrackingLinesToImage(trackCollection);
visSingle.getOriginalImage().show();
}
}
/**
* Dynamic plot.
*
* @param qconfLoader qconfLoader
*/
void trackDynamic(QconfLoader qconfLoader) {
STmap[] stMap = ((QParamsQconf) qconfLoader.getQp()).getLoadedDataContainer().getQState();
// wrap original image into TrackVisualisation object. All changes will modify the image
// Note that TrackVisualisation keeps only reference and adds overlay object to it.
TrackVisualisation.Stack visStackDynamic = new TrackVisualisation.Stack(image);
visStackDynamic.circleRadius = options.circleRadius;
HashMap<Integer, List<Point2D>> tmpSelected = extractPoints(stMap);
// plot - iterate over cells (keys) and plot all points
for (Map.Entry<Integer, List<Point2D>> entry : tmpSelected.entrySet()) {
Integer cellNo = entry.getKey(); // cell number
List<Point2D> points = entry.getValue(); // users points
MaximaFinder mf = new MaximaFinder(ui.getImagePlus().getProcessor());
mf.setMaxima(points);
TrackCollection trackCollection = getTracks(stMap, cellNo, mf);
if (options.chbShowPoint.booleanValue()) {
visStackDynamic.addMaximaToImage(stMap[cellNo], mf);
visStackDynamic.addTrackingMaximaToImage(stMap[cellNo], trackCollection);
}
// tracking lines
if (options.chbShowTrack.booleanValue()) {
visStackDynamic.addTrackingLinesToImage(stMap[cellNo], trackCollection);
}
}
addOutline(stMap, visStackDynamic);
}
/**
* Order data by cell numbers. For each key (cell number) collect all users points.
*
* @param stMap maps
* @return Map(CellNo, ListOfPoints for this cellNo). Point has coordinate of Map [frame,index]
*/
HashMap<Integer, List<Point2D>> extractPoints(STmap[] stMap) {
HashMap<Integer, List<Point2D>> tmpSelected = new HashMap<>();
for (PointCoords p : ui.getModel().selected) {
int tmpIndex = MapCoordConverter.findPointIndex(stMap[p.cellNo].getxMap()[p.frame],
stMap[p.cellNo].getyMap()[p.frame], p.point.getX(), p.point.getY(), Double.MAX_VALUE);
if (tmpIndex >= 0) {
// if no cell in HashMap - create
if (tmpSelected.get(p.cellNo) == null) {
tmpSelected.put(p.cellNo, new ArrayList<Point2D>());
}
// add point to the cell
tmpSelected.get(p.cellNo).add(new Point2D.Double(p.frame, tmpIndex));
}
}
logger.trace("Added " + tmpSelected.size() + " points");
return tmpSelected;
}
/**
* Combination of static and dynamic.
*
* @param qconfLoader qconfLoader
*/
void trackStatic(QconfLoader qconfLoader) {
STmap[] stMap = ((QParamsQconf) qconfLoader.getQp()).getLoadedDataContainer().getQState();
// wrap original image into TrackVisualisation object. All changes will modify the image
// Note that TrackVisualisation keeps only reference and adds overlay object to it.
TrackVisualisation.Stack visStackStatic = new TrackVisualisation.Stack(image);
visStackStatic.circleRadius = options.circleRadius;
HashMap<Integer, List<Point2D>> tmpSelected = extractPoints(stMap);
// plot - iterate over cells (keys) and plot all points
for (Map.Entry<Integer, List<Point2D>> entry : tmpSelected.entrySet()) {
Integer cellNo = entry.getKey(); // cell number
List<Point2D> points = entry.getValue(); // users points
MaximaFinder mf = new MaximaFinder(ui.getImagePlus().getProcessor());
mf.setMaxima(points);
TrackCollection trackCollection = getTracks(stMap, cellNo, mf);
if (options.chbShowPoint.booleanValue()) {
visStackStatic.addTrackingMaximaToImage(stMap[cellNo], trackCollection);
}
// tracking lines
TrackVisualisation.Image vis = new TrackVisualisation.Image(image);
if (options.chbShowTrack.booleanValue()) {
vis.addElementsToImage(stMap[cellNo], trackCollection, mf);
}
}
// add outline always even if no points
addOutline(stMap, visStackStatic);
}
/**
* Get tracks.
*
* @param stMap stMap
* @param cellNo cellNo
* @param mf mf
* @return trackCollection
*/
protected TrackCollection getTracks(STmap[] stMap, Integer cellNo, MaximaFinder mf) {
TrackMapAnalyser pt = new TrackMapAnalyser();
pt.trackMaxima(stMap[cellNo], -1.0, mf); // TODO Add as parameter
TrackCollection trackCollection = pt.getTrackCollection();
return trackCollection;
}
/**
* Plot outlines.
*
* @param stMap stMap
* @param visStackStatic visStackStatic
*/
private void addOutline(STmap[] stMap, TrackVisualisation.Stack visStackStatic) {
for (STmap mapCell : stMap) {
// color outlines
visStackStatic.addOutlinesToImage(mapCell, options);
}
}
/**
* Fully static.
*
* @param qconfLoader qconfLoader
* @return flattened image
*/
ImagePlus trackStaticFlat(QconfLoader qconfLoader) {
STmap[] stMap = ((QParamsQconf) qconfLoader.getQp()).getLoadedDataContainer().getQState();
// wrap original image into TrackVisualisation object. All changes will modify the image
// Note that TrackVisualisation keeps only reference and adds overlay object to it.
TrackVisualisation.Image visStackStatic = new TrackVisualisation.Image(image);
visStackStatic.circleRadius = options.circleRadius;
visStackStatic.flatten(ZProjector.AVG_METHOD, false);
// order data by cell numbers. For each key (cell number) collect all users points
HashMap<Integer, List<Point2D>> tmpSelected = new HashMap<>();
for (PointCoords p : ui.getModel().selected) {
int tmpIndex = MapCoordConverter.findPointIndex(stMap[p.cellNo].getxMap()[p.frame],
stMap[p.cellNo].getyMap()[p.frame], p.point.getX(), p.point.getY(), Double.MAX_VALUE);
if (tmpIndex >= 0) {
// if no cell in HashMap - create
if (tmpSelected.get(p.cellNo) == null) {
tmpSelected.put(p.cellNo, new ArrayList<Point2D>());
}
// add point to the cell
tmpSelected.get(p.cellNo).add(new Point2D.Double(p.frame, tmpIndex));
}
}
logger.trace("Added " + tmpSelected.size() + " points");
// plot - iterate over cells (keys) and plot all points
for (Map.Entry<Integer, List<Point2D>> entry : tmpSelected.entrySet()) {
Integer cellNo = entry.getKey(); // cell number
List<Point2D> points = entry.getValue(); // users points
MaximaFinder mf = new MaximaFinder(ui.getImagePlus().getProcessor());
mf.setMaxima(points);
TrackCollection trackCollection = getTracks(stMap, cellNo, mf);
// tracking lines
MaximaFinder mfTmp = null;
TrackCollection tcTmp = null;
if (options.chbShowTrack.booleanValue()) {
tcTmp = trackCollection;
}
if (options.chbShowPoint.booleanValue()) {
mfTmp = mf;
}
if (options.chbShowTrack.booleanValue()) {
visStackStatic.addElementsToImage(stMap[cellNo], tcTmp, mfTmp);
}
}
return visStackStatic.getOriginalImage();
}
}