Skip to content
This repository was archived by the owner on Sep 11, 2025. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file added Compiled plugin/Thunder_STORM_FIJI.jar
Binary file not shown.
Binary file added Compiled plugin/Thunder_STORM_ImageJ.jar
Binary file not shown.
Binary file not shown.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,6 @@ Install [ImageJ](http://imagej.nih.gov/ij/index.html) and download the latest ve
## How to cite ThunderSTORM
If you use ThunderSTORM to process your data, please, cite our [paper](http://dx.doi.org/10.1093/bioinformatics/btu202):
* M. Ovesný, P. Křížek, J. Borkovec, Z. Švindrych, G. M. Hagen. _ThunderSTORM: a comprehensive ImageJ plugin for PALM and STORM data analysis and super-resolution imaging._ Bioinformatics 30(16):2389-2390, 2014.

If you use the phasor sub-pixel estimator, please cite this paper in addition (https://doi.org/10.1101/191957):
* K.J.A. Martens, A.N. Bader, S. Baas, B. Rieger, J. Hohlbein. _Phasor based single-molecule localization microscopy in 3D (pSMLM-3D): an algorithm for MHz localization rates using standard CPUs_ bioRxiv, 2017.
22 changes: 15 additions & 7 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,15 @@
<version>dev-2016-09-10-b1</version>
<packaging>jar</packaging>

<name>ThunderSTORM</name>
<name>ThunderSTORM-Phasor_KM</name>
<description>ThunderSTORM: a comprehensive ImageJ plugin for PALM and STORM data analysis and super-resolution imaging</description>
<url>https://github.com/zitmen/thunderstorm</url>

<properties>
<skipTests>true</skipTests>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<kotlin.version>1.0.3</kotlin.version>
<imagej.path>C:\Program Files\ImageJ</imagej.path>
<imagej.path>C:\Users\Koen Martens\Desktop\Fiji.app</imagej.path>
<imagej1.version>1.49s</imagej1.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
Expand Down Expand Up @@ -270,6 +270,14 @@
<artifactId>swingbox</artifactId>
<version>1.1</version>
</dependency>
<!--Added by KM-->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
<scope>provided</scope>
</dependency>
<!--End Added by KM-->
<dependency>
<groupId>net.java.balloontip</groupId>
<artifactId>balloontip</artifactId>
Expand Down Expand Up @@ -311,16 +319,16 @@
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.bitbucket.pepa_borkovec</groupId>
<artifactId>MacroAwareUI</artifactId>
<version>889b2b553e96e8493bf6a103acfe2197eb0733ca</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
<type>jar</type>
</dependency>
<dependency>
<groupId>org.bitbucket.pepa_borkovec</groupId>
<artifactId>MacroAwareUI</artifactId>
<version>889b2b553e96e8493bf6a103acfe2197eb0733ca</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public class BiPlaneCalibrationPlugin implements PlugIn {
String savePath;
double stageStep;
double zRangeLimit;//in nm
double zzeropos;//in nm
ImagePlus imp1, imp2;
Roi roi1, roi2;

Expand Down Expand Up @@ -81,6 +82,7 @@ public void run(String arg) {
savePath = dialog.getSavePath();
stageStep = dialog.getStageStep();
zRangeLimit = dialog.getZRangeLimit();
zzeropos = 0;
defocusModel = dialog.getActiveDefocusFunction();

if (!isStack(imp1 = dialog.getFirstPlaneStack())) return;
Expand All @@ -98,7 +100,7 @@ public void run(String arg) {
final ICalibrationProcess process = CalibrationProcessFactory.create(
calibrationConfig,
selectedFilterUI, selectedDetectorUI, calibrationEstimatorUI,
defocusModel, stageStep, zRangeLimit, imp1, imp2, roi1, roi2);
defocusModel, stageStep, zRangeLimit, imp1, imp2, roi1, roi2, zzeropos);

try {
process.runCalibration();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package cz.cuni.lf1.lge.ThunderSTORM;

import cz.cuni.lf1.lge.ThunderSTORM.estimators.ui.PhasorAstigmatismCalibrationEstimatorUI;
import cz.cuni.lf1.lge.ThunderSTORM.UI.AstigmatismCalibrationDialog;
import cz.cuni.lf1.lge.ThunderSTORM.UI.GUI;
import cz.cuni.lf1.lge.ThunderSTORM.calibration.*;
Expand All @@ -24,10 +25,13 @@ public class CylindricalLensCalibrationPlugin implements PlugIn {
DefocusFunction defocusModel;
IFilterUI selectedFilterUI;
IDetectorUI selectedDetectorUI;
IEstimatorUI selectedEstimatorUI;
PhasorAstigmatismCalibrationEstimatorUI phasorCalibrationEstimatorUI;
AstigmatismCalibrationEstimatorUI calibrationEstimatorUI;
String savePath;
double stageStep;
double zRangeLimit;//in nm
double zzeropos;
ImagePlus imp;
Roi roi;

Expand All @@ -47,9 +51,10 @@ public void run(String arg) {
try {
//load modules
calibrationEstimatorUI = new AstigmatismCalibrationEstimatorUI();
phasorCalibrationEstimatorUI = new PhasorAstigmatismCalibrationEstimatorUI();
List<IFilterUI> filters = ModuleLoader.getUIModules(IFilterUI.class);
List<IDetectorUI> detectors = ModuleLoader.getUIModules(IDetectorUI.class);
List<IEstimatorUI> estimators = Arrays.asList(new IEstimatorUI[]{calibrationEstimatorUI}); // only one estimator can be used
List<IEstimatorUI> estimators = Arrays.asList(new IEstimatorUI[]{calibrationEstimatorUI, phasorCalibrationEstimatorUI});
List<DefocusFunction> defocusFunctions = ModuleLoader.getUIModules(DefocusFunction.class);
Thresholder.loadFilters(filters);

Expand All @@ -60,24 +65,59 @@ public void run(String arg) {
IJ.handleException(e);
}
AstigmatismCalibrationDialog dialog;

dialog = new AstigmatismCalibrationDialog(imp, filters, detectors, estimators, defocusFunctions);
if(dialog.showAndGetResult() != JOptionPane.OK_OPTION) {
return;
}
selectedFilterUI = dialog.getActiveFilterUI();
selectedDetectorUI = dialog.getActiveDetectorUI();
selectedEstimatorUI = dialog.getActiveEstimatorUI();
savePath = dialog.getSavePath();
stageStep = dialog.getStageStep();
zRangeLimit = dialog.getZRangeLimit();
defocusModel = dialog.getActiveDefocusFunction();

//zzeropos is boolean indicator for setting z=0 at intersection of defocus curves, or at middle of calibration stack - KM
zzeropos = dialog.getZZeroPos();

String activeEstimator = ""+selectedEstimatorUI;
String subStringGauss = "ui.AstigmatismCalibrationEstimatorUI";
String subStringPhasor = "ui.PhasorAstigmatismCalibrationEstimatorUI";
//IJ.log(activeEstimator);
roi = imp.getRoi() != null ? imp.getRoi() : new Roi(0, 0, imp.getWidth(), imp.getHeight());

// perform the calibration
//if Phasor is selected - KM
if (activeEstimator.toLowerCase().contains(subStringPhasor.toLowerCase())){
final PhasorAstigmaticCalibrationProcess process = (PhasorAstigmaticCalibrationProcess) PhasorCalibrationProcessFactory.create(
new CalibrationConfig(),
selectedFilterUI, selectedDetectorUI, phasorCalibrationEstimatorUI,
defocusModel, stageStep, zRangeLimit, imp, roi, zzeropos);

try {
process.runCalibration();
} catch(NoMoleculesFittedException ex) {
// if no beads were succesfully fitted, draw localizations anyway
process.drawOverlay();
IJ.handleException(ex);
return;
}
process.drawOverlay();
process.drawSigmaPlots();

try {
process.getCalibration(defocusModel).saveToFile(savePath);
} catch(IOException ex) {
UI.showAnotherLocationDialog(ex, process.getCalibration(defocusModel));
}
} else
//If Gauss is selected, do the standard calibration -KM
{
//The boolean zzeropos is added to differentiate between zero at intersection or middle of calibration stack -KM
final AstigmaticCalibrationProcess process = (AstigmaticCalibrationProcess) CalibrationProcessFactory.create(
new CalibrationConfig(),
selectedFilterUI, selectedDetectorUI, calibrationEstimatorUI,
defocusModel, stageStep, zRangeLimit, imp, roi);
defocusModel, stageStep, zRangeLimit, imp, roi, zzeropos);

try {
process.runCalibration();
Expand All @@ -95,6 +135,7 @@ public void run(String arg) {
} catch(IOException ex) {
UI.showAnotherLocationDialog(ex, process.getCalibration(defocusModel));
}
}
} catch(Exception ex) {
IJ.handleException(ex);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -353,11 +353,11 @@ public ImportDialog(Window owner, boolean groundTruth) {
assert moduleNames != null && moduleNames.length > 0;
fileFormat = fileParams.createStringField("fileFormat", StringValidatorFactory.isMember(moduleNames), moduleNames[0]);
filePath = fileParams.createStringField("filePath", StringValidatorFactory.fileExists(), "");
detectMeasurementProtocol = fileParams.createBooleanField("detectMeasurementProtocol", null, true);
startingFrame = params.createIntField("startingFrame", IntegerValidatorFactory.positiveNonZero(), 1);
append = params.createBooleanField("append", null, false);
this.groundTruth = groundTruth;
if(!groundTruth) {
detectMeasurementProtocol = fileParams.createBooleanField("detectMeasurementProtocol", null, true);
showPreview = params.createBooleanField("livePreview", null, true);
rawImageStack = params.createStringField("rawImageStack", StringValidatorFactory.openImages(true), "");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ public class AstigmatismCalibrationDialog extends DialogStub implements ActionLi
ParameterKey.String detectorName;
ParameterKey.String estimatorName;
ParameterKey.String defocusName;
ParameterKey.String zzeropos;

protected transient ParameterKey.String ZZEROPOS;

private List<IFilterUI> filters;
private List<IDetectorUI> detectors;
private List<IEstimatorUI> estimators;
Expand All @@ -60,6 +63,8 @@ public AstigmatismCalibrationDialog(ImagePlus imp, List<IFilterUI> filters, List
detectorName = params.createStringField("detector", null, detectors.get(0).getName());
estimatorName = params.createStringField("estimator", null, estimators.get(0).getName());
defocusName = params.createStringField("defocusing", null, defocusing.get(0).getName());

zzeropos = params.createStringField("ZzeroPosition", null, "Z=0 at intersection of polynomials");

this.filters = filters;
this.detectors = detectors;
Expand All @@ -77,7 +82,6 @@ protected void layoutComponents() {
componentConstraints.gridx = 0;
componentConstraints.fill = GridBagConstraints.BOTH;
componentConstraints.weightx = 1;

JButton cameraSetup = new JButton("Camera setup");
cameraSetup.addActionListener(new ActionListener() {
@Override
Expand Down Expand Up @@ -112,6 +116,15 @@ public void actionPerformed(ActionEvent e) {

JPanel aditionalOptions = new JPanel(new GridBagLayout());
aditionalOptions.setBorder(BorderFactory.createTitledBorder("Additional options"));


ButtonGroup btnGroup = new ButtonGroup();
JRadioButton intersectionRadioButton = new JRadioButton("Z=0 at intersection of polynomials");
JRadioButton middleStackRadioButton = new JRadioButton("Z=0 at middle of image stack");
btnGroup.add(intersectionRadioButton);
btnGroup.add(middleStackRadioButton);
zzeropos.registerComponent(btnGroup);

aditionalOptions.add(new JLabel("Z stage step [nm]:"), GridBagHelper.leftCol());
JTextField stageStepTextField = new JTextField("", 20);
stageStep.registerComponent(stageStepTextField);
Expand All @@ -130,7 +143,10 @@ public void actionPerformed(ActionEvent e) {
gbc.fill = GridBagConstraints.HORIZONTAL;
aditionalOptions.add(calibrationPanel, gbc);
pane.add(aditionalOptions, componentConstraints);

aditionalOptions.add(new JLabel("Z calibration: "), GridBagHelper.leftCol());
aditionalOptions.add(intersectionRadioButton, GridBagHelper.rightCol());
aditionalOptions.add(middleStackRadioButton, GridBagHelper.rightCol());

JButton defaults = new JButton("Defaults");
JButton preview = new JButton("Preview");
JButton ok = new JButton("OK");
Expand Down Expand Up @@ -295,6 +311,11 @@ public double getZRangeLimit() {
return zRangeLimit.getValue();
}

public double getZZeroPos() {
if (zzeropos.getValue()=="Z=0 at middle of image stack"){return 1;}
else {return 0;}
}

@Override
public void dispose() {
super.dispose();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ private void showInTextWindow() throws IOException {
//set page shown in browser
if(url != null && !url.equals(htmlBrowser.getPage())) {
try {
htmlBrowser.setPage(url);
htmlBrowser.setPage(url.toString());
} catch(Exception e) {
htmlBrowser.setText("Could not load help file");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ abstract class AbstractCalibrationProcess implements ICalibrationProcess {
protected DefocusFunction defocusModel;
protected double stageStep;
protected double zRange;
protected double zzeropos;

// results
protected double angle = 0.0;
Expand All @@ -53,14 +54,15 @@ abstract class AbstractCalibrationProcess implements ICalibrationProcess {
protected double[] allSigma1s;
protected double[] allSigma2s;

public AbstractCalibrationProcess(CalibrationConfig config, IFilterUI selectedFilterUI, IDetectorUI selectedDetectorUI, ICalibrationEstimatorUI calibrationEstimatorUI, DefocusFunction defocusModel, double stageStep, double zRangeLimit) {
public AbstractCalibrationProcess(CalibrationConfig config, IFilterUI selectedFilterUI, IDetectorUI selectedDetectorUI, ICalibrationEstimatorUI calibrationEstimatorUI, DefocusFunction defocusModel, double stageStep, double zRangeLimit, double zzeropos) {
this.config = config;
this.selectedFilterUI = selectedFilterUI;
this.selectedDetectorUI = selectedDetectorUI;
this.calibrationEstimatorUI = calibrationEstimatorUI;
this.defocusModel = defocusModel;
this.stageStep = stageStep;
this.zRange = zRangeLimit;
this.zzeropos = zzeropos;
}

/**
Expand Down Expand Up @@ -123,7 +125,7 @@ public void run(int i) {
return MathProxy.atan2(sin, cos) / 4;
}

protected void fitQuadraticPolynomials(Collection<PSFSeparator.Position> positions) {
protected void fitQuadraticPolynomials(ImagePlus imp, Collection<PSFSeparator.Position> positions) {
// fit a quadratic polynomial to sigma1 = f(zpos) and sigma1 = f(zpos) for each bead
IterativeFitting polynomialFitter = new IterativeFitting(config.inlierFittingMaxIters, config.inlierFittingInlierFraction);
allPolynomsS1 = new ArrayList<DefocusFunction>();
Expand All @@ -144,7 +146,7 @@ protected void fitQuadraticPolynomials(Collection<PSFSeparator.Position> positio
if(p.getSize() < config.minimumFitsCount) {
continue;
}
double z0guess = guessZ0(p);
double z0guess = guessZ0(imp, p);
p.discardFitsByFrameRange(z0guess - zRange/stageStep, z0guess + zRange/stageStep);

// retrieve values again after filtering out fits not in range
Expand Down Expand Up @@ -321,7 +323,8 @@ protected static void drawOverlay(ImagePlus imp, Roi roi, List<Molecule> allFits
/**
* guess z0 of molecule
*/
protected double guessZ0(PSFSeparator.Position p) {
protected double guessZ0(ImagePlus imp, PSFSeparator.Position p) {
final ImageStack stack = imp.getStack();
double[] sigma1AsArray = p.getAsArray(LABEL_SIGMA1);
double[] sigma2AsArray = p.getAsArray(LABEL_SIGMA2);
double[] intensityAsArray = p.getAsArray(LABEL_INTENSITY);
Expand All @@ -341,7 +344,11 @@ protected double guessZ0(PSFSeparator.Position p) {
}
}

return p.fits.get(minIdx).getParam(LABEL_FRAME);
double stackSize = stack.getSize();
if (zzeropos==1){//If zero is at middle of image stack -KM
return (stackSize/2);
}else{//If zero is a polynomial crossover -KM
return p.fits.get(minIdx).getParam(LABEL_FRAME);}
}

private static double[] flattenListOfArrays(List<double[]> list) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ public class AstigmaticBiplaneCalibrationProcess extends AbstractCalibrationProc

public AstigmaticBiplaneCalibrationProcess(CalibrationConfig config, IFilterUI selectedFilterUI, IDetectorUI selectedDetectorUI,
AstigmaticBiplaneCalibrationEstimatorUI calibrationEstimatorUI, DefocusFunction defocusModel,
double stageStep, double zRangeLimit, ImagePlus imp1, ImagePlus imp2, Roi roi1, Roi roi2) {
super(config, selectedFilterUI, selectedDetectorUI, calibrationEstimatorUI, defocusModel, stageStep, zRangeLimit);
double stageStep, double zRangeLimit, ImagePlus imp1, ImagePlus imp2, Roi roi1, Roi roi2, double zzeropos) {
super(config, selectedFilterUI, selectedDetectorUI, calibrationEstimatorUI, defocusModel, stageStep, zRangeLimit, zzeropos);
this.imp1 = imp1;
this.imp2 = imp2;
this.roi1 = roi1;
Expand All @@ -60,7 +60,7 @@ public void runCalibration() {
IJ.log("angle2 = " + angle2);
IJ.log("Homography transformation matrix: " + transformationMatrix.toString());

fitQuadraticPolynomials(pos12.keySet());
fitQuadraticPolynomials(imp1, pos12.keySet());
polyS11 = polynomS1Final;
polyS12 = polynomS2Final;
allPolyS11 = allPolynomsS1;
Expand All @@ -71,7 +71,7 @@ public void runCalibration() {
IJ.log("s11 = " + polynomS1Final.toString());
IJ.log("s12 = " + polynomS2Final.toString());

fitQuadraticPolynomials(pos12.values());
fitQuadraticPolynomials(imp1, pos12.values());
polyS21 = polynomS1Final;
polyS22 = polynomS2Final;
allPolyS21 = allPolynomsS1;
Expand Down Expand Up @@ -155,7 +155,7 @@ public void drawSigmaPlots() {
}

@Override
protected double guessZ0(PSFSeparator.Position p) {
protected double guessZ0(ImagePlus imp, PSFSeparator.Position p) {
double[] sigma1AsArray = p.getAsArray(LABEL_SIGMA1);
double[] sigma2AsArray = p.getAsArray(LABEL_SIGMA2);
double[] sigma3AsArray = p.getAsArray(LABEL_SIGMA3);
Expand Down
Loading