package cz.cuni.lf1.lge.ThunderSTORM.results;
import com.google.gson.*;
import cz.cuni.lf1.lge.ThunderSTORM.CameraSetupPlugIn;
import cz.cuni.lf1.lge.ThunderSTORM.ModuleLoader;
import cz.cuni.lf1.lge.ThunderSTORM.ThunderSTORM;
import cz.cuni.lf1.lge.ThunderSTORM.calibration.DefocusCalibration;
import cz.cuni.lf1.lge.ThunderSTORM.calibration.DefocusFunction;
import cz.cuni.lf1.lge.ThunderSTORM.detectors.EmptyDetector;
import cz.cuni.lf1.lge.ThunderSTORM.detectors.ui.IDetectorUI;
import cz.cuni.lf1.lge.ThunderSTORM.estimators.EmptyEstimator;
import cz.cuni.lf1.lge.ThunderSTORM.estimators.ui.EllipticGaussianEstimatorUI;
import cz.cuni.lf1.lge.ThunderSTORM.estimators.ui.IBiplaneEstimatorUI;
import cz.cuni.lf1.lge.ThunderSTORM.estimators.ui.IEstimatorUI;
import cz.cuni.lf1.lge.ThunderSTORM.filters.EmptyFilter;
import cz.cuni.lf1.lge.ThunderSTORM.filters.ui.IFilterUI;
import cz.cuni.lf1.lge.ThunderSTORM.results.OperationsHistoryPanel.Operation;
import cz.cuni.lf1.lge.ThunderSTORM.results.PostProcessingModule.DefaultOperation;
import ij.IJ;
import ij.ImagePlus;
import org.apache.commons.lang3.SystemUtils;
import java.io.*;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
public class MeasurementProtocol {
public String version;
public HashMap<String, Object> imageInfo;
public HashMap<String, Object> cameraSettings;
public IFilterUI analysisFilter;
public IDetectorUI analysisDetector;
public IEstimatorUI analysisEstimator;
public IBiplaneEstimatorUI analysisBiplaneEstimator;
public List<Operation> postProcessing;
private boolean is3d;
private boolean isSet3d;
public MeasurementProtocol() {
this.version = "ThunderSTORM (" + ThunderSTORM.INSTANCE.getVERSION() + ")";
this.imageInfo = new HashMap<String, Object>();
this.cameraSettings = new HashMap<String, Object>();
this.analysisFilter = new EmptyFilter();
this.analysisDetector = new EmptyDetector();
this.analysisEstimator = new EmptyEstimator();
this.postProcessing = IJResultsTable.getResultsTable().getOperationHistoryPanel().getHistory();
this.isSet3d = false;
}
public MeasurementProtocol(ImagePlus analyzedImage, IFilterUI filter, IDetectorUI detector, IEstimatorUI estimator) {
this.version = "ThunderSTORM (" + ThunderSTORM.INSTANCE.getVERSION() + ")";
this.imageInfo = getImageInfo(analyzedImage);
this.cameraSettings = CameraSetupPlugIn.exportSettings();
this.analysisFilter = filter;
this.analysisDetector = detector;
this.analysisEstimator = estimator;
this.postProcessing = IJResultsTable.getResultsTable().getOperationHistoryPanel().getHistory();
this.isSet3d = false;
}
public MeasurementProtocol(ImagePlus analyzedPlane1, ImagePlus analyzedPlane2, IFilterUI filter, IDetectorUI detector, IBiplaneEstimatorUI biplaneEstimator) {
this.version = "ThunderSTORM (" + ThunderSTORM.INSTANCE.getVERSION() + ")";
this.imageInfo = getImageInfo(analyzedPlane1); // TODO: append the second image info!!!
this.cameraSettings = CameraSetupPlugIn.exportSettings();
this.analysisFilter = filter;
this.analysisDetector = detector;
this.analysisBiplaneEstimator = biplaneEstimator;
this.postProcessing = IJResultsTable.getResultsTable().getOperationHistoryPanel().getHistory();
this.isSet3d = false;
}
public boolean is3D() {
// this is used as an indicator whether to calculate the z-uncertainty;
// since we don't have a implementation for biplane, the function returns
// tru only for astigmatism
if (!this.isSet3d) {
this.is3d = ((analysisEstimator != null) && (analysisEstimator instanceof EllipticGaussianEstimatorUI));
this.isSet3d = true;
}
return this.is3d;
}
public void exportToFile(String fpath) {
assert(fpath != null);
assert(!fpath.trim().isEmpty());
BufferedWriter writer = null;
try {
writer = new BufferedWriter(new FileWriter(fpath));
Gson gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
this.postProcessing = IJResultsTable.getResultsTable().getOperationHistoryPanel().getHistory(); // update
writer.write(fixNewLines(gson.toJson(this)));
} catch(IOException ex) {
IJ.handleException(ex);
} finally {
try {
if(writer != null) {
writer.close();
}
} catch(IOException ex) {
IJ.handleException(ex);
}
}
}
public static MeasurementProtocol importFromFile(String fpath) {
GsonBuilder gson = new GsonBuilder();
gson.registerTypeAdapter(IFilterUI.class, new FilterAdapter());
gson.registerTypeAdapter(IDetectorUI.class, new DetectorAdapter());
gson.registerTypeAdapter(IEstimatorUI.class, new EstimatorAdapter());
gson.registerTypeAdapter(IBiplaneEstimatorUI.class, new BiplaneEstimatorAdapter());
gson.registerTypeAdapter(DefocusCalibration.class, new CylindricalLensCalibrationAdapter());
gson.registerTypeAdapter(Operation.class, new OperationAdapter());
BufferedReader reader = null;
try {
reader = new BufferedReader(new FileReader(fpath));
return gson.create().fromJson(reader, MeasurementProtocol.class);
} catch (FileNotFoundException ex) {
IJ.showMessage("Measurement protocol can't be opened!");
IJ.handleException(ex);
} catch (JsonParseException ex) {
IJ.showMessage("Invalid format of measurement protocol: parsing error!");
IJ.handleException(ex);
} finally {
try {
if(reader != null) {
reader.close();
}
} catch(IOException ex) {
IJ.handleException(ex);
}
}
return new MeasurementProtocol();
}
private HashMap<String,Object> getImageInfo(ImagePlus img) {
HashMap<String,Object> info = new HashMap<String,Object>();
info.put("title", img.getTitle());
info.put("roiBounds", img.getRoi() == null ? null : img.getRoi().getBounds());
return info;
}
private String fixNewLines(String json) {
String fixed = json.replace("\r\n", "\n").replace("\r", "\n"); // convert Windows and Mac to Unix
// now convert to the coding dependant on the OS
if(SystemUtils.IS_OS_WINDOWS) { // Windows
return fixed.replace("\n", "\r\n");
} else if(SystemUtils.IS_OS_MAC) { // Mac OS
return fixed.replace("\n", "\r");
} else { // Unix-based systems
return fixed; // "\n"
}
}
private static class FilterAdapter implements JsonDeserializer<IFilterUI> {
@Override
public IFilterUI deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String name = json.getAsJsonObject().get("name").getAsString();
for (IFilterUI filter : ModuleLoader.getUIModules(IFilterUI.class)) {
if (name.equals(filter.getName())) {
return context.deserialize(json, filter.getClass());
}
}
throw new JsonParseException("Unknown filter \"" + name + "\"!");
}
}
private static class DetectorAdapter implements JsonDeserializer<IDetectorUI> {
@Override
public IDetectorUI deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String name = json.getAsJsonObject().get("name").getAsString();
for (IDetectorUI detector : ModuleLoader.getUIModules(IDetectorUI.class)) {
if (name.equals(detector.getName())) {
return context.deserialize(json, detector.getClass());
}
}
throw new JsonParseException("Unknown detector \"" + name + "\"!");
}
}
private static class EstimatorAdapter implements JsonDeserializer<IEstimatorUI> {
@Override
public IEstimatorUI deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String name = json.getAsJsonObject().get("name").getAsString();
for (IEstimatorUI estimator : ModuleLoader.getUIModules(IEstimatorUI.class)) {
if (name.equals(estimator.getName())) {
return context.deserialize(json, estimator.getClass());
}
}
throw new JsonParseException("Unknown estimator \"" + name + "\"!");
}
}
private static class BiplaneEstimatorAdapter implements JsonDeserializer<IBiplaneEstimatorUI> {
@Override
public IBiplaneEstimatorUI deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String name = json.getAsJsonObject().get("name").getAsString();
for (IBiplaneEstimatorUI biplaneEstimator : ModuleLoader.getUIModules(IBiplaneEstimatorUI.class)) {
if (name.equals(biplaneEstimator.getName())) {
return context.deserialize(json, biplaneEstimator.getClass());
}
}
throw new JsonParseException("Unknown estimator \"" + name + "\"!");
}
}
private static class CylindricalLensCalibrationAdapter implements JsonDeserializer<DefocusCalibration> {
@Override
public DefocusCalibration deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
String name = json.getAsJsonObject().get("name").getAsString();
for (DefocusFunction defocusFn : ModuleLoader.getUIModules(DefocusFunction.class)) {
if (name.equals(defocusFn.getName())) {
return context.deserialize(json, defocusFn.getCalibration().getClass());
}
}
throw new JsonParseException("Unknown calibration model \"" + name + "\"!");
}
}
private static class OperationAdapter implements JsonDeserializer<Operation> {
@Override
public Operation deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
return context.deserialize(json, DefaultOperation.class);
}
}
}