OughtaFocus.java Source code

Java tutorial

Introduction

Here is the source code for OughtaFocus.java

Source

///////////////////////////////////////////////////////////////////////////////
//FILE:           OughtaFocus.java
//PROJECT:        Micro-Manager
//SUBSYSTEM:      Autofocusing plug-in for mciro-manager and ImageJ
//-----------------------------------------------------------------------------
//
//AUTHOR:         Arthur Edelstein, October 2010
//                Based on SimpleAutofocus by Karl Hoover
//                and the Autofocus "H&P" plugin
//                by Pakpoom Subsoontorn & Hernan Garcia
//
//COPYRIGHT:      University of California San Francisco
//                
//LICENSE:        This file is distributed under the BSD license.
//                License text is included with the source distribution.
//
//                This file is distributed in the hope that it will be useful,
//                but WITHOUT ANY WARRANTY; without even the implied warranty
//                of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
//                IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//                CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//                INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES.
//
//CVS:            $Id: MetadataDlg.java 1275 2008-06-03 21:31:24Z nenad $

import ij.process.ImageProcessor;
import ij.process.ImageStatistics;

import java.awt.Rectangle;
import java.text.ParseException;
import javax.swing.SwingUtilities;

import mmcorej.CMMCore;
import mmcorej.Configuration;
import mmcorej.TaggedImage;

import org.apache.commons.math.FunctionEvaluationException;
import org.apache.commons.math.analysis.UnivariateRealFunction;
import org.apache.commons.math.optimization.GoalType;
import org.apache.commons.math.optimization.univariate.BrentOptimizer;
import org.micromanager.api.ScriptInterface;
import org.micromanager.utils.AutofocusBase;
import org.micromanager.utils.ImageUtils;
import org.micromanager.utils.MMException;
import org.micromanager.utils.MathFunctions;
import org.micromanager.utils.NumberUtils;
import org.micromanager.utils.ReportingUtils;
import org.micromanager.utils.TextUtils;

public class OughtaFocus extends AutofocusBase implements org.micromanager.api.Autofocus {

    private ScriptInterface app_;
    private static final String AF_DEVICE_NAME = "OughtaFocus";
    private static final String SEARCH_RANGE = "SearchRange_um";
    private static final String TOLERANCE = "Tolerance_um";
    private static final String CROP_FACTOR = "CropFactor";
    private static final String CHANNEL = "Channel";
    private static final String EXPOSURE = "Exposure";
    private static final String SHOW_IMAGES = "ShowImages";
    private static final String SCORING_METHOD = "Maximize";
    private static final String showValues[] = { "Yes", "No" };
    private final static String scoringMethods[] = { "Edges", "StdDev", "Mean", "SharpEdges" };

    private double searchRange = 10;
    private double tolerance = 1;
    private double cropFactor = 1;
    private String channel = "";
    private double exposure = 100;
    private String show = "No";
    private String scoringMethod = "Edges";

    private int imageCount_;
    private long startTimeMs_;
    private double startZUm_;
    private boolean liveModeOn_;

    private boolean settingsLoaded_ = false;

    public OughtaFocus() {
        super();
        createProperty(SEARCH_RANGE, NumberUtils.doubleToDisplayString(searchRange));
        createProperty(TOLERANCE, NumberUtils.doubleToDisplayString(tolerance));
        createProperty(CROP_FACTOR, NumberUtils.doubleToDisplayString(cropFactor));
        createProperty(EXPOSURE, NumberUtils.doubleToDisplayString(exposure));
        createProperty(SHOW_IMAGES, show, showValues);
        createProperty(SCORING_METHOD, scoringMethod, scoringMethods);
        imageCount_ = 0;
    }

    public void applySettings() {
        try {
            searchRange = NumberUtils.displayStringToDouble(getPropertyValue(SEARCH_RANGE));
            tolerance = NumberUtils.displayStringToDouble(getPropertyValue(TOLERANCE));
            cropFactor = NumberUtils.displayStringToDouble(getPropertyValue(CROP_FACTOR));
            cropFactor = MathFunctions.clip(0.01, cropFactor, 1.0);
            channel = getPropertyValue(CHANNEL);
            exposure = NumberUtils.displayStringToDouble(getPropertyValue(EXPOSURE));
            show = getPropertyValue(SHOW_IMAGES);
            scoringMethod = getPropertyValue(SCORING_METHOD);

        } catch (MMException ex) {
            ReportingUtils.logError(ex);
        } catch (ParseException ex) {
            ReportingUtils.logError(ex);
        }
    }

    public String getDeviceName() {
        return AF_DEVICE_NAME;
    }

    public double fullFocus() throws MMException {
        startTimeMs_ = System.currentTimeMillis();
        applySettings();
        try {
            Rectangle oldROI = app_.getROI();
            CMMCore core = app_.getMMCore();
            liveModeOn_ = app_.isLiveModeOn();

            //ReportingUtils.logMessage("Original ROI: " + oldROI);
            int w = (int) (oldROI.width * cropFactor);
            int h = (int) (oldROI.height * cropFactor);
            int x = oldROI.x + (oldROI.width - w) / 2;
            int y = oldROI.y + (oldROI.height - h) / 2;
            Rectangle newROI = new Rectangle(x, y, w, h);
            //ReportingUtils.logMessage("Setting ROI to: " + newROI);
            Configuration oldState = null;
            if (channel.length() > 0) {
                String chanGroup = core.getChannelGroup();
                oldState = core.getConfigGroupState(chanGroup);
                core.setConfig(chanGroup, channel);
            }

            // avoid wasting time on setting roi if it is the same
            if (cropFactor < 1.0) {
                app_.setROI(newROI);
                core.waitForDevice(core.getCameraDevice());
            }
            double oldExposure = core.getExposure();
            core.setExposure(exposure);

            double z = runAutofocusAlgorithm();

            if (cropFactor < 1.0) {
                app_.setROI(oldROI);
                core.waitForDevice(core.getCameraDevice());
            }
            if (oldState != null) {
                core.setSystemState(oldState);
            }
            core.setExposure(oldExposure);
            setZPosition(z);
            return z;
        } catch (Exception ex) {
            throw new MMException(ex.getMessage());
        }
    }

    private double runAutofocusAlgorithm() throws Exception {
        UnivariateRealFunction scoreFun = new UnivariateRealFunction() {
            public double value(double d) throws FunctionEvaluationException {
                try {
                    return measureFocusScore(d);
                } catch (Exception e) {
                    throw new FunctionEvaluationException(e, d);
                }
            }
        };
        BrentOptimizer brentOptimizer = new BrentOptimizer();
        brentOptimizer.setAbsoluteAccuracy(tolerance);
        imageCount_ = 0;

        CMMCore core = app_.getMMCore();
        double z = core.getPosition(core.getFocusDevice());
        startZUm_ = z;
        //      getCurrentFocusScore();
        double zResult = brentOptimizer.optimize(scoreFun, GoalType.MAXIMIZE, z - searchRange / 2,
                z + searchRange / 2);
        ReportingUtils.logMessage("OughtaFocus Iterations: " + brentOptimizer.getIterationCount() + ", z="
                + TextUtils.FMT2.format(zResult) + ", dz=" + TextUtils.FMT2.format(zResult - startZUm_) + ", t="
                + (System.currentTimeMillis() - startTimeMs_));
        return zResult;
    }

    private void setZPosition(double z) throws Exception {
        CMMCore core = app_.getMMCore();
        String focusDevice = core.getFocusDevice();
        core.setPosition(focusDevice, z);
        core.waitForDevice(focusDevice);
    }

    public double measureFocusScore(double z) throws Exception {
        CMMCore core = app_.getMMCore();
        long start = System.currentTimeMillis();
        try {
            setZPosition(z);
            long tZ = System.currentTimeMillis() - start;

            TaggedImage img = null;
            if (liveModeOn_) {
                img = core.getLastTaggedImage();
            } else {
                core.waitForDevice(core.getCameraDevice());
                core.snapImage();
                final TaggedImage img1 = core.getTaggedImage();
                img = img1;
                if (show.contentEquals("Yes")) {
                    SwingUtilities.invokeLater(new Runnable() {
                        public void run() {
                            app_.displayImage(img1);
                        }
                    });
                }
            }
            long tI = System.currentTimeMillis() - start - tZ;
            ImageProcessor proc = ImageUtils.makeProcessor(core, img.pix);
            double score = computeScore(proc);
            long tC = System.currentTimeMillis() - start - tZ - tI;
            ReportingUtils.logMessage("OughtaFocus: image=" + imageCount_++ + ", t="
                    + (System.currentTimeMillis() - startTimeMs_) + ", z=" + TextUtils.FMT2.format(z) + ", score="
                    + TextUtils.FMT2.format(score) + ", Tz=" + tZ + ", Ti=" + tI + ", Tc=" + tC);
            return score;
        } catch (Exception e) {
            ReportingUtils.logError(e);
            throw e;
        }
    }

    public double incrementalFocus() throws MMException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public int getNumberOfImages() {
        return imageCount_;
    }

    public String getVerboseStatus() {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public double getCurrentFocusScore() {
        CMMCore core = app_.getMMCore();
        double z = 0.0;
        double score = 0.0;
        try {
            z = core.getPosition(core.getFocusDevice());
            core.waitForDevice(core.getCameraDevice());
            core.snapImage();
            Object img = core.getImage();
            if (show.contentEquals("Yes")) {
                app_.displayImage(img);
            }
            ImageProcessor proc = ImageUtils.makeProcessor(core, img);
            score = computeScore(proc);
            ReportingUtils.logMessage(
                    "OughtaFocus: z=" + TextUtils.FMT2.format(z) + ", score=" + TextUtils.FMT2.format(score));
        } catch (Exception e) {
            ReportingUtils.logError(e);
        }
        return score;
    }

    public void focus(double coarseStep, int numCoarse, double fineStep, int numFine) throws MMException {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    private double computeEdges(ImageProcessor proc) {
        // mean intensity for the original image
        double meanIntensity = proc.getStatistics().mean;
        ImageProcessor proc1 = proc.duplicate();
        // mean intensity of the edge map
        proc1.findEdges();
        double meanEdge = proc.getStatistics().mean;

        return meanEdge / meanIntensity;
    }

    private double computeSharpEdges(ImageProcessor proc) {
        // mean intensity for the original image
        double meanIntensity = proc.getStatistics().mean;
        ImageProcessor proc1 = proc.duplicate();
        // mean intensity of the edge map
        proc1.sharpen();
        proc1.findEdges();
        double meanEdge = proc.getStatistics().mean;

        return meanEdge / meanIntensity;
    }

    private double computeMean(ImageProcessor proc) {
        return proc.getStatistics().mean;
    }

    private double computeNormalizedStdDev(ImageProcessor proc) {

        ImageStatistics stats = proc.getStatistics();
        return stats.stdDev / stats.mean;
    }

    private double computeScore(ImageProcessor proc) {
        if (scoringMethod.contentEquals("Mean")) {
            return computeMean(proc);
        } else if (scoringMethod.contentEquals("StdDev")) {
            return computeNormalizedStdDev(proc);
        } else if (scoringMethod.contentEquals("Edges")) {
            return computeEdges(proc);
        } else if (scoringMethod.contentEquals("SharpEdges")) {
            return computeSharpEdges(proc);
        } else {
            return 0;
        }
    }

    public void setApp(ScriptInterface app) {
        app_ = app;
        CMMCore core = app_.getMMCore();
        String chanGroup = core.getChannelGroup();
        String curChan;
        try {
            curChan = core.getCurrentConfig(chanGroup);
            createProperty(CHANNEL, curChan, core.getAvailableConfigs(core.getChannelGroup()).toArray());
        } catch (Exception ex) {
            ReportingUtils.logError(ex);
        }

        if (!settingsLoaded_) {
            super.loadSettings();
            settingsLoaded_ = true;
        }
    }
}