Skip to content

Instantly share code, notes, and snippets.

@NicoKiaru
Created February 1, 2021 10:31
Show Gist options
  • Save NicoKiaru/b6b0fcd28692e1a35ba4c30da393778a to your computer and use it in GitHub Desktop.
Save NicoKiaru/b6b0fcd28692e1a35ba4c30da393778a to your computer and use it in GitHub Desktop.
package ch.epfl.biop.trackmategdsc;
import fiji.plugin.trackmate.*;
import fiji.plugin.trackmate.action.AbstractTMAction;
import fiji.plugin.trackmate.action.ExportTracksToXML;
import fiji.plugin.trackmate.action.TrackMateAction;
import fiji.plugin.trackmate.action.TrackMateActionFactory;
import fiji.plugin.trackmate.gui.TrackMateGUIController;
import fiji.plugin.trackmate.util.TMUtils;
import org.jdom2.Element;
import java.util.Set;
import java.util.TreeSet;
import static ch.epfl.biop.trackmategdsc.LocalizationToTracksCounter.RADIUS_AROUND_TRACK;
import static ch.epfl.biop.trackmategdsc.LocalizationToTracksCounter.SPOTS_AROUND_TRACK;
import fiji.plugin.trackmate.Logger;
import fiji.plugin.trackmate.Model;
import fiji.plugin.trackmate.Settings;
import fiji.plugin.trackmate.Spot;
import fiji.plugin.trackmate.TrackMate;
import fiji.plugin.trackmate.gui.TrackMateGUIController;
import fiji.plugin.trackmate.gui.TrackMateWizard;
import fiji.plugin.trackmate.io.IOUtils;
import fiji.plugin.trackmate.util.TMUtils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.ImageIcon;
import org.jdom2.Document;
import org.jdom2.Element;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.scijava.plugin.Plugin;
public class TrackXMLExporter extends AbstractTMAction {
public static final ImageIcon ICON = new ImageIcon(TrackMateWizard.class.getResource("images/page_save.png"));
public static final String NAME = "Export tracks to XML file";
public static final String KEY = "EXPORT_TRACKS_TO_XML_SIMPLE";
public static final String INFO_TEXT = "<html>" +
"Export the tracks in the current model content to a XML " +
"file in a simple format. " +
"<p> " +
"The file will have one element per track, and each track " +
"contains several spot elements. These spots are " +
"sorted by frame number, and have 4 numerical attributes: " +
"the frame number this spot is in, and its X, Y, Z position in " +
"physical units as specified in the image properties. " +
"<p>" +
"As such, this format <u>cannot</u> handle track merging and " +
"splitting properly, and is suited only for non-branching tracks." +
"</html>";
private final TrackMateGUIController controller;
/*
* CONSTRUCTOR
*/
public TrackXMLExporter( final TrackMateGUIController controller )
{
this.controller = controller;
}
/*
* METHODS
*/
/**
* Static utility that silently exports tracks in a simplified xml format,
* describe in this class.
*
* @param model
* the {@link Model} that contains the tracks to export.
* @param settings
* a {@link Settings} object, only used to read its
* {@link Settings#dt} field, the frame interval.
* @param file
* the file to save to.
* @throws FileNotFoundException
* if the target file cannot be written.
* @throws IOException
* if there is a problem writing the file.
*/
public static void export(final Model model, final Settings settings, final File file) throws FileNotFoundException, IOException {
final Element root = marshall(model, settings, Logger.VOID_LOGGER);
final Document document = new Document(root);
final XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
outputter.output(document, new FileOutputStream(file));
}
@Override
public void execute(final TrackMate trackmate) {
logger.log("Exporting tracks to simple XML format.\n");
final Model model = trackmate.getModel();
final int ntracks = model.getTrackModel().nTracks(true);
if (ntracks == 0) {
logger.log("No visible track found. Aborting.\n");
return;
}
logger.log(" Preparing XML data.\n");
final Element root = marshall(model, trackmate.getSettings(), logger);
File folder;
try {
folder = new File(trackmate.getSettings().imp.getOriginalFileInfo().directory);
} catch (final NullPointerException npe) {
folder = new File(System.getProperty("user.dir")).getParentFile().getParentFile();
}
File file;
try {
String filename = trackmate.getSettings().imageFileName;
final int dot = filename.indexOf(".");
filename = dot < 0 ? filename : filename.substring(0, dot);
file = new File(folder.getPath() + File.separator + filename +"_Tracks.xml");
} catch (final NullPointerException npe) {
file = new File(folder.getPath() + File.separator + "Tracks.xml");
}
file = IOUtils.askForFileForSaving(file, controller.getGUI(), logger);
if (null == file) {
return;
}
logger.log(" Writing to file.\n");
final Document document = new Document(root);
final XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
try {
outputter.output(document, new FileOutputStream(file));
} catch (final FileNotFoundException e) {
logger.error("Trouble writing to "+file+":\n" + e.getMessage());
} catch (final IOException e) {
logger.error("Trouble writing to "+file+":\n" + e.getMessage());
}
logger.log("Done.\n");
}
private static Element marshall(final Model model, final Settings settings, final Logger logger) {
logger.setStatus("Marshalling...");
final Element content = new Element(CONTENT_KEY);
content.setAttribute(NTRACKS_ATT, ""+model.getTrackModel().nTracks(true));
content.setAttribute(PHYSUNIT_ATT, model.getSpaceUnits());
content.setAttribute(FRAMEINTERVAL_ATT, ""+settings.dt);
content.setAttribute(FRAMEINTERVALUNIT_ATT, ""+model.getTimeUnits());
content.setAttribute(DATE_ATT, TMUtils.getCurrentTimeString());
content.setAttribute(FROM_ATT, TrackMate.PLUGIN_NAME_STR + " v" + TrackMate.PLUGIN_NAME_VERSION);
final Set<Integer> trackIDs = model.getTrackModel().trackIDs(true);
int i = 0;
for (final Integer trackID : trackIDs) {
final Set<Spot> track = model.getTrackModel().trackSpots(trackID);
final Element trackElement = new Element(TRACK_KEY);
trackElement.setAttribute(NSPOTS_ATT, ""+track.size());
trackElement.setAttribute(RADIUS_AROUND_TRACK, ""+ model.getFeatureModel().getTrackFeature(trackID, RADIUS_AROUND_TRACK));
trackElement.setAttribute(SPOTS_AROUND_TRACK, ""+ model.getFeatureModel().getTrackFeature(trackID, SPOTS_AROUND_TRACK));
// Sort them by time
final TreeSet<Spot> sortedTrack = new TreeSet<>(Spot.timeComparator);
sortedTrack.addAll(track);
for (final Spot spot : sortedTrack) {
final int frame = spot.getFeature(Spot.FRAME).intValue();
final double x = spot.getFeature(Spot.POSITION_X);
final double y = spot.getFeature(Spot.POSITION_Y);
final double z = spot.getFeature(Spot.POSITION_Z);
final Element spotElement = new Element(SPOT_KEY);
spotElement.setAttribute(T_ATT, ""+frame);
spotElement.setAttribute(X_ATT, ""+x);
spotElement.setAttribute(Y_ATT, ""+y);
//spotElement.setAttribute(Z_ATT, ""+z);
trackElement.addContent(spotElement);
}
content.addContent(trackElement);
logger.setProgress(i++ / (0d + model.getTrackModel().nTracks(true)));
}
logger.setStatus("");
logger.setProgress(1);
return content;
}
/*
* XML KEYS
*/
private static final String CONTENT_KEY = "Tracks";
private static final String DATE_ATT = "generationDateTime";
private static final String PHYSUNIT_ATT = "spaceUnits";
private static final String FRAMEINTERVAL_ATT = "frameInterval";
private static final String FRAMEINTERVALUNIT_ATT = "timeUnits";
private static final String FROM_ATT = "from";
private static final String NTRACKS_ATT = "nTracks";
private static final String NSPOTS_ATT = "nSpots";
private static final String TRACK_KEY = "particle";
private static final String SPOT_KEY = "detection";
private static final String X_ATT = "x";
private static final String Y_ATT = "y";
private static final String Z_ATT = "z";
private static final String T_ATT = "t";
@Plugin( type = TrackMateActionFactory.class )
public static class Factory implements TrackMateActionFactory
{
@Override
public String getInfoText()
{
return INFO_TEXT;
}
@Override
public String getName()
{
return NAME;
}
@Override
public String getKey()
{
return KEY;
}
@Override
public TrackMateAction create(final TrackMateGUIController controller )
{
return new fiji.plugin.trackmate.action.ExportTracksToXML( controller );
}
@Override
public ImageIcon getIcon()
{
return ICON;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment