Search in sources :

Example 6 with CalibrationWriter

use of uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter in project GDSC-SMLM by aherbert.

the class PeakFit method configureFitSolver.

/**
 * Show a dialog to configure the fit solver. The updated settings are saved to the settings file.
 * An error message is shown if the dialog is cancelled or the configuration is invalid.
 *
 * <p>The bounds are used to validate the camera model. The camera model must be large enough to
 * cover the source bounds. If larger then it will be cropped. Optionally an internal region of
 * the input image can be specified. This is relative to the width and height of the input image.
 * If no camera model is present then the bounds can be null.
 *
 * @param config the configuration
 * @param sourceBounds the source image bounds (used to validate the camera model dimensions)
 * @param bounds the crop bounds (relative to the input image, used to validate the camera model
 *        dimensions)
 * @param flags the flags
 * @return True if the configuration succeeded
 */
public static boolean configureFitSolver(FitEngineConfiguration config, Rectangle sourceBounds, Rectangle bounds, int flags) {
    final boolean extraOptions = BitFlagUtils.anySet(flags, FLAG_EXTRA_OPTIONS);
    final boolean ignoreCalibration = BitFlagUtils.anySet(flags, FLAG_IGNORE_CALIBRATION);
    final boolean saveSettings = BitFlagUtils.anyNotSet(flags, FLAG_NO_SAVE);
    final FitConfiguration fitConfig = config.getFitConfiguration();
    final CalibrationWriter calibration = fitConfig.getCalibrationWriter();
    final FitSolver fitSolver = fitConfig.getFitSolver();
    final boolean isLvm = fitSolver == FitSolver.LVM_LSE || fitSolver == FitSolver.LVM_WLSE || fitSolver == FitSolver.LVM_MLE;
    // Support the deprecated backtracking FastMLE solver as a plain FastMLE solver
    final boolean isFastMml = fitSolver == FitSolver.FAST_MLE || fitSolver == FitSolver.BACKTRACKING_FAST_MLE;
    final boolean isSteppingFunctionSolver = isLvm || isFastMml;
    if (fitSolver == FitSolver.MLE) {
        final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
        if (!ignoreCalibration) {
            gd.addMessage("Maximum Likelihood Estimation requires CCD-type camera parameters");
            gd.addNumericField("Camera_bias", calibration.getBias(), 2, 6, "count");
            gd.addCheckbox("Model_camera_noise", fitConfig.isModelCamera());
            gd.addNumericField("Read_noise", calibration.getReadNoise(), 2, 6, "count");
            gd.addNumericField("Quantum_efficiency", calibration.getQuantumEfficiency(), 2, 6, "electron/photon");
            gd.addCheckbox("EM-CCD", calibration.isEmCcd());
        } else {
            gd.addMessage("Maximum Likelihood Estimation requires additional parameters");
        }
        final String[] searchNames = SettingsManager.getSearchMethodNames();
        gd.addChoice("Search_method", searchNames, FitProtosHelper.getName(fitConfig.getSearchMethod()));
        gd.addStringField("Relative_threshold", MathUtils.rounded(fitConfig.getRelativeThreshold()));
        gd.addStringField("Absolute_threshold", MathUtils.rounded(fitConfig.getAbsoluteThreshold()));
        gd.addNumericField("Max_iterations", fitConfig.getMaxIterations(), 0);
        gd.addNumericField("Max_function_evaluations", fitConfig.getMaxFunctionEvaluations(), 0);
        if (extraOptions) {
            gd.addCheckbox("Gradient_line_minimisation", fitConfig.isGradientLineMinimisation());
        }
        gd.showDialog();
        if (gd.wasCanceled()) {
            return false;
        }
        if (!ignoreCalibration) {
            calibration.setBias(Math.abs(gd.getNextNumber()));
            fitConfig.setModelCamera(gd.getNextBoolean());
            calibration.setReadNoise(Math.abs(gd.getNextNumber()));
            calibration.setQuantumEfficiency(Math.abs(gd.getNextNumber()));
            calibration.setCameraType((gd.getNextBoolean()) ? CameraType.EMCCD : CameraType.CCD);
            fitConfig.setCalibration(calibration.getCalibration());
        }
        fitConfig.setSearchMethod(SettingsManager.getSearchMethodValues()[gd.getNextChoiceIndex()]);
        fitConfig.setRelativeThreshold(getThresholdNumber(gd));
        fitConfig.setAbsoluteThreshold(getThresholdNumber(gd));
        fitConfig.setMaxIterations((int) gd.getNextNumber());
        fitConfig.setMaxFunctionEvaluations((int) gd.getNextNumber());
        if (extraOptions) {
            fitConfig.setGradientLineMinimisation(gd.getNextBoolean());
        } else {
            // This option is for the Conjugate Gradient optimiser and makes it less stable
            fitConfig.setGradientLineMinimisation(false);
        }
        if (saveSettings) {
            saveFitEngineSettings(config);
        }
        try {
            ParameterUtils.isAboveZero("Relative threshold", fitConfig.getRelativeThreshold());
            ParameterUtils.isAboveZero("Absolute threshold", fitConfig.getAbsoluteThreshold());
            ParameterUtils.isAboveZero("Max iterations", fitConfig.getMaxIterations());
            ParameterUtils.isAboveZero("Max function evaluations", fitConfig.getMaxFunctionEvaluations());
            fitConfig.getFunctionSolver();
        } catch (final IllegalArgumentException | IllegalStateException ex) {
            IJ.error(TITLE, ex.getMessage());
            return false;
        }
    } else if (isSteppingFunctionSolver) {
        final boolean requireCalibration = !ignoreCalibration && fitSolver != FitSolver.LVM_LSE;
        // Collect options for LVM fitting
        final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
        final String fitSolverName = FitProtosHelper.getName(fitSolver);
        gd.addMessage(fitSolverName + " requires additional parameters");
        gd.addStringField("Relative_threshold", MathUtils.rounded(fitConfig.getRelativeThreshold()));
        gd.addStringField("Absolute_threshold", MathUtils.rounded(fitConfig.getAbsoluteThreshold()));
        gd.addStringField("Parameter_relative_threshold", MathUtils.rounded(fitConfig.getParameterRelativeThreshold()));
        gd.addStringField("Parameter_absolute_threshold", MathUtils.rounded(fitConfig.getParameterAbsoluteThreshold()));
        gd.addNumericField("Max_iterations", fitConfig.getMaxIterations(), 0);
        if (isLvm) {
            gd.addNumericField("Lambda", fitConfig.getLambda(), 4);
        }
        if (isFastMml) {
            gd.addCheckbox("Fixed_iterations", fitConfig.isFixedIterations());
            // This works because the proto configuration enum matches the named enum
            final String[] lineSearchNames = SettingsManager.getNames((Object[]) FastMleSteppingFunctionSolver.LineSearchMethod.values());
            gd.addChoice("Line_search_method", lineSearchNames, lineSearchNames[fitConfig.getLineSearchMethod().getNumber()]);
        }
        gd.addCheckbox("Use_clamping", fitConfig.isUseClamping());
        gd.addCheckbox("Dynamic_clamping", fitConfig.isUseDynamicClamping());
        final PSF psf = fitConfig.getPsf();
        final boolean isAstigmatism = psf.getPsfType() == PSFType.ASTIGMATIC_GAUSSIAN_2D;
        final int nParams = PsfHelper.getParameterCount(psf);
        if (extraOptions) {
            gd.addNumericField("Clamp_background", fitConfig.getClampBackground(), 2);
            gd.addNumericField("Clamp_signal", fitConfig.getClampSignal(), 2);
            gd.addNumericField("Clamp_x", fitConfig.getClampX(), 2);
            gd.addNumericField("Clamp_y", fitConfig.getClampY(), 2);
            if (isAstigmatism) {
                gd.addNumericField("Clamp_z", fitConfig.getClampZ(), 2);
            } else {
                if (nParams > 1 || !fitConfig.isFixedPsf()) {
                    gd.addNumericField("Clamp_sx", fitConfig.getClampXSd(), 2);
                }
                if (nParams > 1) {
                    gd.addNumericField("Clamp_sy", fitConfig.getClampYSd(), 2);
                }
                if (nParams > 2) {
                    gd.addNumericField("Clamp_angle", fitConfig.getClampAngle(), 2);
                }
            }
        }
        // Extra parameters are needed for calibrated fit solvers
        if (requireCalibration) {
            switch(calibration.getCameraType()) {
                case CCD:
                case EMCCD:
                case SCMOS:
                    break;
                default:
                    IJ.error(TITLE, fitSolverName + " requires camera calibration");
                    return false;
            }
            gd.addMessage(fitSolverName + " requires calibration for camera: " + CalibrationProtosHelper.getName(calibration.getCameraType()));
            if (calibration.isScmos()) {
                final String[] models = CameraModelManager.listCameraModels(true);
                gd.addChoice("Camera_model_name", models, fitConfig.getCameraModelName());
            } else {
                gd.addNumericField("Camera_bias", calibration.getBias(), 2, 6, "Count");
                gd.addNumericField("Gain", calibration.getCountPerPhoton(), 2, 6, "Count/photon");
                gd.addNumericField("Read_noise", calibration.getReadNoise(), 2, 6, "Count");
            }
        }
        gd.showDialog();
        if (gd.wasCanceled()) {
            return false;
        }
        fitConfig.setRelativeThreshold(getThresholdNumber(gd));
        fitConfig.setAbsoluteThreshold(getThresholdNumber(gd));
        fitConfig.setParameterRelativeThreshold(getThresholdNumber(gd));
        fitConfig.setParameterAbsoluteThreshold(getThresholdNumber(gd));
        fitConfig.setMaxIterations((int) gd.getNextNumber());
        if (isLvm) {
            fitConfig.setLambda(gd.getNextNumber());
        }
        if (isFastMml) {
            fitConfig.setFixedIterations(gd.getNextBoolean());
            fitConfig.setLineSearchMethod(gd.getNextChoiceIndex());
        }
        fitConfig.setUseClamping(gd.getNextBoolean());
        fitConfig.setUseDynamicClamping(gd.getNextBoolean());
        if (extraOptions) {
            fitConfig.setClampBackground(Math.abs(gd.getNextNumber()));
            fitConfig.setClampSignal(Math.abs(gd.getNextNumber()));
            fitConfig.setClampX(Math.abs(gd.getNextNumber()));
            fitConfig.setClampY(Math.abs(gd.getNextNumber()));
            if (isAstigmatism) {
                fitConfig.setClampZ(Math.abs(gd.getNextNumber()));
            } else {
                if (nParams > 1 || !fitConfig.isFixedPsf()) {
                    fitConfig.setClampXSd(Math.abs(gd.getNextNumber()));
                }
                if (nParams > 1) {
                    fitConfig.setClampYSd(Math.abs(gd.getNextNumber()));
                }
                if (nParams > 2) {
                    fitConfig.setClampAngle(Math.abs(gd.getNextNumber()));
                }
            }
        }
        if (requireCalibration) {
            if (calibration.isScmos()) {
                fitConfig.setCameraModelName(gd.getNextChoice());
            } else {
                calibration.setBias(Math.abs(gd.getNextNumber()));
                calibration.setCountPerPhoton(Math.abs(gd.getNextNumber()));
                calibration.setReadNoise(Math.abs(gd.getNextNumber()));
                fitConfig.setCalibration(calibration.getCalibration());
            }
        }
        // camera model is set.
        if (calibration.isScmos()) {
            fitConfig.setCameraModel(CameraModelManager.load(fitConfig.getCameraModelName()));
            if (!checkCameraModel(fitConfig, sourceBounds, bounds, true)) {
                return false;
            }
        }
        if (saveSettings) {
            saveFitEngineSettings(config);
        }
        try {
            if (isLvm) {
                ParameterUtils.isAboveZero("Lambda", fitConfig.getLambda());
            }
            // This call will check if the configuration is OK (including convergence criteria)
            fitConfig.getFunctionSolver();
        } catch (final IllegalArgumentException | IllegalStateException ex) {
            IJ.error(TITLE, ex.getMessage());
            return false;
        }
    } else {
        IJ.error(TITLE, "Unknown fit solver: " + fitSolver);
        return false;
    }
    if (config.isIncludeNeighbours() && !fitConfig.getFunctionSolver().isBounded()) {
        IJ.error(TITLE, "Including neighbours requires a bounded fit solver");
        return false;
    }
    return true;
}
Also used : FitSolver(uk.ac.sussex.gdsc.smlm.data.config.FitProtos.FitSolver) PSF(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.PSF) FitConfiguration(uk.ac.sussex.gdsc.smlm.engine.FitConfiguration) CalibrationWriter(uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog)

Example 7 with CalibrationWriter

use of uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter in project GDSC-SMLM by aherbert.

the class PeakFit method readDialog.

private boolean readDialog(ExtendedGenericDialog gd, boolean isCrop) {
    // Ignore the template
    gd.getNextChoice();
    final CalibrationWriter calibration = fitConfig.getCalibrationWriter();
    calibration.setCameraType(SettingsManager.getCameraTypeValues()[gd.getNextChoiceIndex()]);
    calibration.setNmPerPixel(Math.abs(gd.getNextNumber()));
    calibration.setExposureTime(Math.abs(gd.getNextNumber()));
    fitConfig.setCalibration(calibration.getCalibration());
    // The simple fix is to create a plugin to allow the configuration to be changed for results.
    if (isCrop) {
        ignoreBoundsForNoise = extraSettings.optionIgnoreBoundsForNoise = gd.getNextBoolean();
    }
    fitConfig.setPsfType(PeakFit.getPsfTypeValues()[gd.getNextChoiceIndex()]);
    config.setDataFilterType(gd.getNextChoiceIndex());
    // Note: The absolute flag is set in extra options
    config.setDataFilter(gd.getNextChoiceIndex(), Math.abs(gd.getNextNumber()), 0);
    config.setSearch(gd.getNextNumber());
    config.setBorder(gd.getNextNumber());
    config.setFitting(gd.getNextNumber());
    if (extraOptions && !fitMaxima) {
        extraSettings.interlacedData = gd.getNextBoolean();
        extraSettings.integrateFrames = (int) gd.getNextNumber();
    }
    if (!maximaIdentification) {
        // Some enum values are not supported
        fitConfig.setFitSolver(SettingsManager.getFitSolverValues()[gd.getNextChoiceIndex()]);
        if (extraOptions) {
            fitConfig.setBackgroundFitting(gd.getNextBoolean());
        }
        config.setFailuresLimit((int) gd.getNextNumber());
        config.setPassRate(gd.getNextNumber());
        config.setIncludeNeighbours(gd.getNextBoolean());
        config.setNeighbourHeightThreshold(gd.getNextNumber());
        config.setResidualsThreshold(gd.getNextNumber());
        config.setDuplicateDistance(gd.getNextNumber());
        fitConfig.setSmartFilter(gd.getNextBoolean());
        fitConfig.setDisableSimpleFilter(gd.getNextBoolean());
        fitConfig.setCoordinateShiftFactor(gd.getNextNumber());
        fitConfig.setSignalStrength(gd.getNextNumber());
        fitConfig.setMinPhotons(gd.getNextNumber());
        if (extraOptions) {
            fitConfig.setNoise(gd.getNextNumber());
            config.setNoiseMethod(gd.getNextChoiceIndex());
        }
        fitConfig.setMinWidthFactor(gd.getNextNumber());
        fitConfig.setMaxWidthFactor(gd.getNextNumber());
        fitConfig.setPrecisionThreshold(gd.getNextNumber());
    }
    resultsSettings.setLogProgress(gd.getNextBoolean());
    if (!maximaIdentification) {
        resultsSettings.setShowDeviations(gd.getNextBoolean());
    }
    resultsSettings.getResultsTableSettingsBuilder().setShowTable(gd.getNextBoolean());
    resultsSettings.getResultsImageSettingsBuilder().setImageTypeValue(gd.getNextChoiceIndex());
    if (extraOptions) {
        extraSettings.showProcessedFrames = gd.getNextBoolean();
    }
    resultsSettings.getResultsFileSettingsBuilder().setFileFormatValue(gd.getNextChoiceIndex());
    resultsSettings.getResultsFileSettingsBuilder().setResultsDirectory(gd.getNextString());
    resultsSettings.getResultsInMemorySettingsBuilder().setInMemory(gd.getNextBoolean());
    if (extraOptions) {
        settings.fractionOfThreads = Math.abs(gd.getNextNumber());
    }
    gd.collectOptions();
    // Save to allow dialog state to be maintained even with invalid parameters
    saveFitEngineSettings();
    SettingsManager.writeSettings(resultsSettings.build());
    if (gd.invalidNumber()) {
        return false;
    }
    // Check arguments
    try {
        // No check on camera calibration. This is left to the FitConfiguration to
        // error if the settings are incorrect
        ParameterUtils.isAboveZero("nm per pixel", calibration.getNmPerPixel());
        ParameterUtils.isAboveZero("Exposure time", calibration.getExposureTime());
        if (fitConfig.getPsfTypeValue() != PSFType.ASTIGMATIC_GAUSSIAN_2D_VALUE) {
            ParameterUtils.isAboveZero("Initial SD0", fitConfig.getInitialXSd());
            if (fitConfig.getPsf().getParametersCount() > 1) {
                ParameterUtils.isAboveZero("Initial SD1", fitConfig.getInitialYSd());
            }
        }
        ParameterUtils.isAboveZero("Search_width", config.getSearch());
        ParameterUtils.isAboveZero("Fitting_width", config.getFitting());
        if (extraOptions && !fitMaxima) {
            ParameterUtils.isPositive("Integrate frames", extraSettings.integrateFrames);
        }
        if (!maximaIdentification) {
            // This can be negative to disable, i.e. fit everything
            // Parameters.isPositive("Failures limit", config.getFailuresLimit())
            ParameterUtils.isPositive("Neighbour height threshold", config.getNeighbourHeightThreshold());
            ParameterUtils.isPositive("Residuals threshold", config.getResidualsThreshold());
            ParameterUtils.isPositive("Duplicate distance", config.getDuplicateDistance());
            if (!fitConfig.isDisableSimpleFilter()) {
                ParameterUtils.isPositive("Coordinate Shift factor", fitConfig.getCoordinateShiftFactor());
                ParameterUtils.isPositive("Signal strength", fitConfig.getSignalStrength());
                ParameterUtils.isPositive("Min photons", fitConfig.getMinPhotons());
            }
            if (extraOptions) {
                ParameterUtils.isPositive("Noise", fitConfig.getNoise());
            }
            if (!fitConfig.isDisableSimpleFilter()) {
                ParameterUtils.isPositive("Min width factor", fitConfig.getMinWidthFactor());
                ParameterUtils.isPositive("Width factor", fitConfig.getMaxWidthFactor());
                ParameterUtils.isPositive("Precision threshold", fitConfig.getPrecisionThreshold());
                if (fitConfig.getPrecisionThreshold() > 0) {
                    if (fitConfig.getPrecisionMethod() == PrecisionMethod.PRECISION_METHOD_NA) {
                        throw new IllegalArgumentException("Precision filter requires a precision method");
                    }
                    if (fitConfig.isPrecisionUsingBackground() && calibration.isCcdCamera() && (calibration.getBias() == 0 || !calibration.hasCountPerPhoton())) {
                        throw new IllegalArgumentException("Precision using the local background requires the camera bias");
                    }
                }
            }
        }
        final ResultsImageSettings.Builder imageSettings = resultsSettings.getResultsImageSettingsBuilder();
        if (imageSettings.getImageType() == ResultsImageType.DRAW_INTENSITY_AVERAGE_PRECISION || imageSettings.getImageType() == ResultsImageType.DRAW_LOCALISATIONS_AVERAGE_PRECISION) {
            ParameterUtils.isAboveZero("Image precision", imageSettings.getAveragePrecision());
        }
        ParameterUtils.isAboveZero("Image scale", imageSettings.getScale());
        if (extraOptions) {
            ParameterUtils.isPositive("Image rolling window", imageSettings.getRollingWindowSize());
        }
    } catch (final IllegalArgumentException ex) {
        IJ.error(TITLE, ex.getMessage());
        return false;
    }
    final int flags = (extraOptions) ? FLAG_EXTRA_OPTIONS : 0;
    // If precision filtering then we need the camera bias
    if (!maximaIdentification) {
        if (!configurePsfModel(config, flags)) {
            return false;
        }
        if (!configureResultsFilter(config, flags)) {
            return false;
        }
    }
    if (!configureDataFilter(config, flags)) {
        return false;
    }
    // Second dialog for solver dependent parameters
    if (!maximaIdentification && !configureFitSolver(config, source.getBounds(), bounds, flags)) {
        return false;
    }
    // Extra parameters are needed for interlaced data
    if (extraSettings.interlacedData) {
        gd = new ExtendedGenericDialog(TITLE);
        gd.addMessage("Interlaced data requires a repeating pattern of frames to process.\n" + "Describe the regular repeat of the data:\n \n" + "Start = The first frame that contains data\n" + "Block = The number of continuous frames containing data\n" + "Skip = The number of continuous frames to ignore before the next data\n \n" + "E.G. 2:9:1 = Data was imaged from frame 2 for 9 frames, 1 frame to ignore," + " then repeat.");
        gd.addNumericField("Start", extraSettings.dataStart, 0);
        gd.addNumericField("Block", extraSettings.dataBlock, 0);
        gd.addNumericField("Skip", extraSettings.dataSkip, 0);
        gd.showDialog();
        if (gd.wasCanceled()) {
            return false;
        }
        if (!gd.wasCanceled()) {
            extraSettings.dataStart = (int) gd.getNextNumber();
            extraSettings.dataBlock = (int) gd.getNextNumber();
            extraSettings.dataSkip = (int) gd.getNextNumber();
            if (extraSettings.dataStart > 0 && extraSettings.dataBlock > 0 && extraSettings.dataSkip > 0) {
                // Store options for next time
                extraSettings.save();
            }
        } else {
            extraSettings.interlacedData = false;
        }
    }
    final boolean result = saveFitEngineSettings();
    if (!result) {
        IJ.error(TITLE, "Failed to save settings");
    }
    return result;
}
Also used : CalibrationWriter(uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter) ResultsImageSettings(uk.ac.sussex.gdsc.smlm.data.config.ResultsProtos.ResultsImageSettings) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog)

Example 8 with CalibrationWriter

use of uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter in project GDSC-SMLM by aherbert.

the class GaussianFit method runFinal.

/**
 * Perform fitting using the chosen maxima. Update the overlay if successful.
 *
 * @param ip The input image
 */
private void runFinal(ImageProcessor ip) {
    ip.reset();
    final Rectangle bounds = ip.getRoi();
    // Crop to the ROI
    final float[] data = ImageJImageConverter.getData(ip);
    final int width = bounds.width;
    final int height = bounds.height;
    // Sort the maxima
    float[] smoothData = data;
    if (getSmooth() > 0) {
        // Smoothing destructively modifies the data so create a copy
        smoothData = Arrays.copyOf(data, width * height);
        final BlockMeanFilter filter = new BlockMeanFilter();
        if (settings.smooth <= settings.border) {
            filter.stripedBlockFilterInternal(smoothData, width, height, (float) settings.smooth);
        } else {
            filter.stripedBlockFilter(smoothData, width, height, (float) settings.smooth);
        }
    }
    SortUtils.sortIndices(maxIndices, smoothData, true);
    // Show the candidate peaks
    if (maxIndices.length > 0) {
        final String message = String.format("Identified %d peaks", maxIndices.length);
        if (isLogProgress()) {
            IJ.log(message);
            for (final int index : maxIndices) {
                IJ.log(String.format("  %.2f @ [%d,%d]", data[index], bounds.x + index % width, bounds.y + index / width));
            }
        }
        // Check whether to run if the number of peaks is large
        if (maxIndices.length > 10) {
            final GenericDialog gd = new GenericDialog("Warning");
            gd.addMessage(message + "\nDo you want to fit?");
            gd.showDialog();
            if (gd.wasCanceled()) {
                return;
            }
        }
    } else {
        IJ.log("No maxima identified");
        return;
    }
    results = new ImageJTablePeakResults(settings.showDeviations, imp.getTitle() + " [" + imp.getCurrentSlice() + "]");
    final CalibrationWriter cw = new CalibrationWriter();
    cw.setIntensityUnit(IntensityUnit.COUNT);
    cw.setDistanceUnit(DistanceUnit.PIXEL);
    cw.setAngleUnit(AngleUnit.RADIAN);
    results.setCalibration(cw.getCalibration());
    results.setPsf(PsfProtosHelper.getDefaultPsf(getPsfType()));
    results.setShowFittingData(true);
    results.setAngleUnit(AngleUnit.DEGREE);
    results.begin();
    // Perform the Gaussian fit
    long ellapsed = 0;
    final FloatProcessor renderedImage = settings.showFit ? new FloatProcessor(ip.getWidth(), ip.getHeight()) : null;
    if (!settings.singleFit) {
        if (isLogProgress()) {
            IJ.log("Combined fit");
        }
        // Estimate height from smoothed data
        final double[] estimatedHeights = new double[maxIndices.length];
        for (int i = 0; i < estimatedHeights.length; i++) {
            estimatedHeights[i] = smoothData[maxIndices[i]];
        }
        final FitConfiguration config = new FitConfiguration();
        setupPeakFiltering(config);
        final long time = System.nanoTime();
        final double[] params = fitMultiple(data, width, height, maxIndices, estimatedHeights);
        ellapsed = System.nanoTime() - time;
        if (params != null) {
            // Copy all the valid parameters into a new array
            final double[] validParams = new double[params.length];
            int count = 0;
            int validPeaks = 0;
            validParams[count++] = params[0];
            final double[] initialParams = convertParameters(fitResult.getInitialParameters());
            final double[] paramsDev = convertParameters(fitResult.getParameterDeviations());
            final Rectangle regionBounds = new Rectangle();
            final float[] xpoints = new float[maxIndices.length];
            final float[] ypoints = new float[maxIndices.length];
            int npoints = 0;
            for (int i = 1, n = 0; i < params.length; i += Gaussian2DFunction.PARAMETERS_PER_PEAK, n++) {
                final int y = maxIndices[n] / width;
                final int x = maxIndices[n] % width;
                // Check the peak is a good fit
                if (settings.filterResults && config.validatePeak(n, initialParams, params, paramsDev) != FitStatus.OK) {
                    continue;
                }
                if (settings.showFit) {
                    // Copy the valid parameters before there are adjusted to global bounds
                    validPeaks++;
                    for (int ii = i, j = 0; j < Gaussian2DFunction.PARAMETERS_PER_PEAK; ii++, j++) {
                        validParams[count++] = params[ii];
                    }
                }
                final double[] peakParams = extractParams(params, i);
                final double[] peakParamsDev = extractParams(paramsDev, i);
                addResult(bounds, regionBounds, peakParams, peakParamsDev, npoints, x, y, data[maxIndices[n]]);
                // Add fit result to the overlay - Coords are updated with the region offsets in addResult
                final double xf = peakParams[Gaussian2DFunction.X_POSITION];
                final double yf = peakParams[Gaussian2DFunction.Y_POSITION];
                xpoints[npoints] = (float) xf;
                ypoints[npoints] = (float) yf;
                npoints++;
            }
            setOverlay(npoints, xpoints, ypoints);
            // Draw the fit
            if (validPeaks != 0) {
                addToImage(bounds.x, bounds.y, renderedImage, validParams, validPeaks, width, height);
            }
        } else {
            if (isLogProgress()) {
                IJ.log("Failed to fit " + TextUtils.pleural(maxIndices.length, "peak") + ": " + getReason(fitResult));
            }
            imp.setOverlay(null);
        }
    } else {
        if (isLogProgress()) {
            IJ.log("Individual fit");
        }
        int npoints = 0;
        final float[] xpoints = new float[maxIndices.length];
        final float[] ypoints = new float[maxIndices.length];
        // Extract each peak and fit individually
        final ImageExtractor ie = ImageExtractor.wrap(data, width, height);
        float[] region = null;
        final Gaussian2DFitter gf = createGaussianFitter(settings.filterResults);
        double[] validParams = null;
        final ShortProcessor renderedImageCount = settings.showFit ? new ShortProcessor(ip.getWidth(), ip.getHeight()) : null;
        for (int n = 0; n < maxIndices.length; n++) {
            final int y = maxIndices[n] / width;
            final int x = maxIndices[n] % width;
            final long time = System.nanoTime();
            final Rectangle regionBounds = ie.getBoxRegionBounds(x, y, settings.singleRegionSize);
            region = ie.crop(regionBounds, region);
            final int newIndex = (y - regionBounds.y) * regionBounds.width + x - regionBounds.x;
            if (isLogProgress()) {
                IJ.log("Fitting peak " + (n + 1));
            }
            final double[] peakParams = fitSingle(gf, region, regionBounds.width, regionBounds.height, newIndex, smoothData[maxIndices[n]]);
            ellapsed += System.nanoTime() - time;
            // Output fit result
            if (peakParams != null) {
                if (settings.showFit) {
                    // Copy the valid parameters before there are adjusted to global bounds
                    validParams = peakParams.clone();
                }
                double[] peakParamsDev = null;
                if (settings.showDeviations) {
                    peakParamsDev = convertParameters(fitResult.getParameterDeviations());
                }
                addResult(bounds, regionBounds, peakParams, peakParamsDev, n, x, y, data[maxIndices[n]]);
                // Add fit result to the overlay - Coords are updated with the region offsets in addResult
                final double xf = peakParams[Gaussian2DFunction.X_POSITION];
                final double yf = peakParams[Gaussian2DFunction.Y_POSITION];
                xpoints[npoints] = (float) xf;
                ypoints[npoints] = (float) yf;
                npoints++;
                // Draw the fit
                if (settings.showDeviations) {
                    final int ox = bounds.x + regionBounds.x;
                    final int oy = bounds.y + regionBounds.y;
                    addToImage(ox, oy, renderedImage, validParams, 1, regionBounds.width, regionBounds.height);
                    addCount(ox, oy, renderedImageCount, regionBounds.width, regionBounds.height);
                }
            } else if (isLogProgress()) {
                IJ.log("Failed to fit peak " + (n + 1) + ": " + getReason(fitResult));
            }
        }
        // Update the overlay
        if (npoints > 0) {
            setOverlay(npoints, xpoints, ypoints);
        } else {
            imp.setOverlay(null);
        }
        // Create the mean
        if (settings.showFit) {
            for (int i = renderedImageCount.getPixelCount(); i-- > 0; ) {
                final int count = renderedImageCount.get(i);
                if (count > 1) {
                    renderedImage.setf(i, renderedImage.getf(i) / count);
                }
            }
        }
    }
    results.end();
    if (renderedImage != null) {
        ImageJUtils.display(TITLE, renderedImage);
    }
    if (isLogProgress()) {
        IJ.log("Time = " + (ellapsed / 1000000.0) + "ms");
    }
}
Also used : FloatProcessor(ij.process.FloatProcessor) Gaussian2DFitter(uk.ac.sussex.gdsc.smlm.fitting.Gaussian2DFitter) Rectangle(java.awt.Rectangle) ImageJTablePeakResults(uk.ac.sussex.gdsc.smlm.ij.results.ImageJTablePeakResults) ShortProcessor(ij.process.ShortProcessor) BlockMeanFilter(uk.ac.sussex.gdsc.smlm.filters.BlockMeanFilter) FitConfiguration(uk.ac.sussex.gdsc.smlm.engine.FitConfiguration) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) GenericDialog(ij.gui.GenericDialog) CalibrationWriter(uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter) ImageExtractor(uk.ac.sussex.gdsc.core.utils.ImageExtractor)

Example 9 with CalibrationWriter

use of uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter in project GDSC-SMLM by aherbert.

the class LoadLocalisations method getFields.

private static boolean getFields(LoadLocalisationsSettings.Builder settings) {
    settings.getLocalisationsFilename();
    final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
    gd.addMessage("Load delimited localisations");
    // Show a preview of the file in a text area
    final List<String> preview = loadLines(settings, 100);
    if (!preview.isEmpty()) {
        // Add a TextArea. This cannot add scroll bars after the constructor so we put up
        // with this. But we can use a monospaced font and size the text area nicely.
        gd.addTextAreas(preview.stream().collect(Collectors.joining("\n")), null, Math.min(10, preview.size()), Math.min(80, preview.stream().mapToInt(String::length).max().getAsInt()));
        final TextArea ta = gd.getTextArea1();
        final Font font = new Font(Font.MONOSPACED, Font.PLAIN, (int) (10 * Prefs.getGuiScale()));
        ta.setFont(font);
        ta.setEditable(false);
    }
    if (!settings.getHideFieldDatasetName()) {
        gd.addStringField("Dataset_name", settings.getName(), 30);
    }
    gd.addMessage("Calibration:");
    // Allow the full camera type top be captured
    final Calibration.Builder calibrationBuilder = settings.getCalibrationBuilder();
    final CalibrationWriter cw = new CalibrationWriter(calibrationBuilder);
    PeakFit.addCameraOptions(gd, 0, cw);
    // Only primitive support for other calibration
    gd.addNumericField("Pixel_size", cw.getNmPerPixel(), 3, 8, "nm");
    gd.addNumericField("Exposure_time", cw.getExposureTime(), 3, 8, "");
    // This is the unit for the exposure time (used to convert the exposure time to milliseconds).
    // Use the name as the list is a truncated list of the full enum.
    final TimeUnit t = calibrationBuilder.getTimeCalibration().getTimeUnit();
    gd.addChoice("Time_unit", TimeUnitLoader.getTimeUnits(), SettingsManager.getName(UnitHelper.getName(t), UnitHelper.getShortName(t)));
    gd.addMessage("Records:");
    gd.addNumericField("Header_lines", settings.getHeaderLines(), 0);
    gd.addStringField("Comment", settings.getComment());
    gd.addStringField("Delimiter", settings.getDelimiter());
    gd.addChoice("Distance_unit", SettingsManager.getDistanceUnitNames(), cw.getDistanceUnitValue());
    gd.addChoice("Intensity_unit", SettingsManager.getIntensityUnitNames(), cw.getIntensityUnitValue());
    gd.addMessage("Define the fields:");
    gd.addNumericField("Frame", settings.getFieldT(), 0);
    gd.addNumericField("ID", settings.getFieldId(), 0);
    gd.addNumericField("Category", settings.getFieldCategory(), 0);
    gd.addNumericField("X", settings.getFieldX(), 0);
    gd.addNumericField("Y", settings.getFieldY(), 0);
    gd.addNumericField("Z", settings.getFieldZ(), 0);
    gd.addNumericField("Intensity", settings.getFieldI(), 0);
    gd.addNumericField("Sx", settings.getFieldSx(), 0);
    gd.addNumericField("Sy", settings.getFieldSy(), 0);
    gd.addNumericField("Precision", settings.getFieldPrecision(), 0);
    gd.addChoice("Precision_method", SettingsManager.getPrecisionMethodNames(), cw.getPrecisionMethodValue());
    gd.addHelp(HelpUrls.getUrl("load-localisations"));
    gd.showDialog();
    if (gd.wasCanceled()) {
        return false;
    }
    if (!settings.getHideFieldDatasetName()) {
        settings.setName(getNextString(gd, settings.getName()));
    }
    cw.setCameraType(SettingsManager.getCameraTypeValues()[gd.getNextChoiceIndex()]);
    cw.setNmPerPixel(gd.getNextNumber());
    cw.setExposureTime(gd.getNextNumber());
    // The time units used a truncated list so look-up the value from the index
    calibrationBuilder.getTimeCalibrationBuilder().setTimeUnit(TimeUnitLoader.getTimeUnitValues()[gd.getNextChoiceIndex()]);
    settings.setHeaderLines((int) gd.getNextNumber());
    settings.setComment(gd.getNextString());
    settings.setDelimiter(getNextString(gd, settings.getDelimiter()));
    cw.setDistanceUnit(DistanceUnit.forNumber(gd.getNextChoiceIndex()));
    cw.setIntensityUnit(IntensityUnit.forNumber(gd.getNextChoiceIndex()));
    final int[] columns = new int[10];
    for (int i = 0; i < columns.length; i++) {
        columns[i] = (int) gd.getNextNumber();
    }
    int index = 0;
    settings.setFieldT(columns[index++]);
    settings.setFieldId(columns[index++]);
    settings.setFieldCategory(columns[index++]);
    settings.setFieldX(columns[index++]);
    settings.setFieldY(columns[index++]);
    settings.setFieldZ(columns[index++]);
    settings.setFieldI(columns[index++]);
    settings.setFieldSx(columns[index++]);
    settings.setFieldSy(columns[index++]);
    settings.setFieldPrecision(columns[index]);
    cw.setPrecisionMethod(PrecisionMethod.forNumber(gd.getNextChoiceIndex()));
    // Collect the camera calibration
    gd.collectOptions();
    // Validate after reading the dialog (so we store the last entered values)
    if (gd.invalidNumber()) {
        IJ.error(TITLE, "Invalid number in input fields");
        return false;
    }
    for (int i = 0; i < columns.length; i++) {
        if (columns[i] < 0) {
            continue;
        }
        for (int j = i + 1; j < columns.length; j++) {
            if (columns[j] < 0) {
                continue;
            }
            if (columns[i] == columns[j]) {
                IJ.error(TITLE, "Duplicate indicies: " + columns[i]);
                return false;
            }
        }
    }
    if (cw.getNmPerPixel() <= 0) {
        IJ.error(TITLE, "Require positive pixel pitch");
        return false;
    }
    if (cw.isCcdCamera()) {
        if (!cw.hasCountPerPhoton()) {
            IJ.error(TITLE, "Require positive count/photon for CCD camera type");
            return false;
        }
    } else {
    // Q.Validate other camera types?
    }
    if (settings.getFieldX() < 0 || settings.getFieldY() < 0) {
        IJ.error(TITLE, "Require valid X and Y indices");
        return false;
    }
    return true;
}
Also used : TextArea(java.awt.TextArea) CalibrationWriter(uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter) TimeUnit(uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.TimeUnit) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) Calibration(uk.ac.sussex.gdsc.smlm.data.config.CalibrationProtos.Calibration) Font(java.awt.Font)

Example 10 with CalibrationWriter

use of uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter in project GDSC-SMLM by aherbert.

the class PeakResultsReader method getCalibration.

/**
 * Gets the calibration specified in the results header.
 *
 * @return The calibration specified in the results header.
 */
@SuppressWarnings("deprecation")
public Calibration getCalibration() {
    if (calibration == null) {
        getHeader();
        if (header != null && header.length() > 0) {
            if (format == FileFormat.RAPID_STORM) {
                calibration.setDistanceUnit(DistanceUnit.NM);
                // RapidSTORM has a resolution attribute in the header in units of px m^-1
                final Pattern pattern = Pattern.compile("resolution=\"([^ ]+) px m");
                final Matcher match = pattern.matcher(header);
                if (match.find()) {
                    try {
                        final float resolution = Float.parseFloat(match.group(1));
                        if (Double.isFinite(resolution) && resolution > 0) {
                            final double nmPerPixel = (float) (1e9 / resolution);
                            calibration = new CalibrationWriter();
                            calibration.setNmPerPixel(nmPerPixel);
                        }
                    } catch (final NumberFormatException ex) {
                    // Ignore
                    }
                }
            } else {
                final String calibrationString = getField("Calibration");
                if (calibrationString != null && calibrationString.length() > 0) {
                    // Older formats used XML
                    if (calibrationString.startsWith("<")) {
                        // Convert the XML back
                        try {
                            // Support package gdsc.smlm renamed to uk.ac.sussex.gdsc.smlm
                            final uk.ac.sussex.gdsc.smlm.results.Calibration cal = (uk.ac.sussex.gdsc.smlm.results.Calibration) XStreamUtils.fromXml(XStreamUtils.updateGdscPackageName(calibrationString));
                            cal.validate();
                            // Convert to a calibration helper
                            calibration = new CalibrationWriter();
                            if (cal.hasNmPerPixel()) {
                                calibration.setNmPerPixel(cal.getNmPerPixel());
                            }
                            if (cal.hasGain()) {
                                calibration.setCountPerPhoton(cal.getGain());
                            }
                            if (cal.hasExposureTime()) {
                                calibration.setExposureTime(cal.getExposureTime());
                            }
                            if (cal.hasReadNoise()) {
                                calibration.setReadNoise(cal.getReadNoise());
                            }
                            if (cal.hasBias()) {
                                calibration.setBias(cal.getBias());
                            }
                            if (cal.emCCD) {
                                calibration.setCameraType(CameraType.EMCCD);
                            }
                            if (cal.hasAmplification() && cal.hasGain()) {
                                calibration.setQuantumEfficiency(cal.getGain() / cal.getAmplification());
                            }
                            // Previous version were always in fixed units
                            calibration.setDistanceUnit(DistanceUnit.PIXEL);
                            calibration.setIntensityUnit(IntensityUnit.COUNT);
                            calibration.setAngleUnit(AngleUnit.DEGREE);
                            calibration.setTimeUnit(TimeUnit.FRAME);
                        } catch (final Exception ex) {
                            logger.log(Level.WARNING, "Unable to deserialise the Calibration settings", ex);
                        }
                    } else {
                        // Assume JSON format
                        try {
                            final Calibration.Builder calibrationBuilder = Calibration.newBuilder();
                            JsonFormat.parser().merge(calibrationString, calibrationBuilder);
                            calibration = new CalibrationWriter(calibrationBuilder);
                            // Old results did not save the time unit
                            if (calibration.getTimeUnitValue() == TimeUnit.TIME_UNIT_NA_VALUE) {
                                calibration.setTimeUnit(TimeUnit.FRAME);
                            }
                        } catch (final InvalidProtocolBufferException ex) {
                            logger.log(Level.WARNING, "Unable to deserialise the Calibration settings", ex);
                        }
                    }
                }
                if (format == FileFormat.MALK) {
                    if (calibration == null) {
                        calibration = new CalibrationWriter();
                    }
                    calibration.setDistanceUnit(DistanceUnit.NM);
                    calibration.setIntensityUnit(IntensityUnit.PHOTON);
                    calibration.setTimeUnit(TimeUnit.FRAME);
                }
            }
        }
        // Calibration is a smart object so we can create an empty one
        if (calibration == null) {
            calibration = new CalibrationWriter();
        }
    }
    return calibration.getCalibration();
}
Also used : Pattern(java.util.regex.Pattern) Matcher(java.util.regex.Matcher) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) Calibration(uk.ac.sussex.gdsc.smlm.data.config.CalibrationProtos.Calibration) NoSuchElementException(java.util.NoSuchElementException) InvalidProtocolBufferException(com.google.protobuf.InvalidProtocolBufferException) IOException(java.io.IOException) EOFException(java.io.EOFException) CalibrationWriter(uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter)

Aggregations

CalibrationWriter (uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter)45 ExtendedGenericDialog (uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog)18 UniformRandomProvider (org.apache.commons.rng.UniformRandomProvider)8 Rectangle (java.awt.Rectangle)7 Calibration (uk.ac.sussex.gdsc.smlm.data.config.CalibrationProtos.Calibration)7 SeededTest (uk.ac.sussex.gdsc.test.junit5.SeededTest)7 Test (org.junit.jupiter.api.Test)5 PSF (uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.PSF)5 FitConfiguration (uk.ac.sussex.gdsc.smlm.engine.FitConfiguration)5 CalibrationReader (uk.ac.sussex.gdsc.smlm.data.config.CalibrationReader)4 InvalidProtocolBufferException (com.google.protobuf.InvalidProtocolBufferException)3 Checkbox (java.awt.Checkbox)3 TextField (java.awt.TextField)3 IOException (java.io.IOException)3 NonBlockingExtendedGenericDialog (uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog)3 IntensityUnit (uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.IntensityUnit)3 MemoryPeakResults (uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults)3 PeakResultProcedure (uk.ac.sussex.gdsc.smlm.results.procedures.PeakResultProcedure)3 ImagePlus (ij.ImagePlus)2 Calibration (ij.measure.Calibration)2