Changeset 7059


Ignore:
Timestamp:
10/08/10 20:09:48 (9 years ago)
Author:
aivar
Message:

Extensive changes: Refactored into packages. New interface.

Location:
branches/maven/projects/slim-plugin/src/main/java/loci/slim
Files:
3 added
7 copied

Legend:

Unmodified
Added
Removed
  • branches/maven/projects/slim-plugin/src/main/java/loci/slim/ChunkyPixel.java

    r6932 r7059  
    3333*/ 
    3434 
    35 package loci; 
     35package loci.slim; 
    3636 
    3737/** 
  • branches/maven/projects/slim-plugin/src/main/java/loci/slim/ChunkyPixelEffectIterator.java

    r6932 r7059  
    3333*/ 
    3434 
    35 package loci; 
     35package loci.slim; 
    3636 
    3737import java.lang.UnsupportedOperationException; 
  • branches/maven/projects/slim-plugin/src/main/java/loci/slim/ChunkyPixelTableImpl.java

    r6932 r7059  
    3333*/ 
    3434 
    35 package loci; 
     35package loci.slim; 
    3636 
    3737/** 
  • branches/maven/projects/slim-plugin/src/main/java/loci/slim/DataColorizer.java

    r6932 r7059  
    3333*/ 
    3434 
    35 package loci; 
     35package loci.slim; 
    3636 
    3737import ij.ImagePlus; 
  • branches/maven/projects/slim-plugin/src/main/java/loci/slim/DecayGraph.java

    r7023 r7059  
    3333*/ 
    3434 
    35 package loci; 
    36  
     35package loci.slim; 
     36 
     37import loci.slim.ui.IStartStopListener; 
    3738import javax.swing.*; 
    3839import java.awt.BasicStroke; 
  • branches/maven/projects/slim-plugin/src/main/java/loci/slim/IChunkyPixelTable.java

    r6932 r7059  
    3333*/ 
    3434 
    35 package loci; 
     35package loci.slim; 
    3636 
    3737/** 
  • branches/maven/projects/slim-plugin/src/main/java/loci/slim/SLIMProcessor.java

    r7024 r7059  
    3333*/ 
    3434 
    35 package loci; 
     35package loci.slim; 
    3636 
    3737//TODO need to add fiji-lib.jar to maven repository: 
     
    4141import ij.ImagePlus; 
    4242import ij.gui.GenericDialog; 
     43import ij.gui.ImageWindow; 
    4344import ij.gui.NonBlockingGenericDialog; 
    4445import ij.gui.Roi; 
     
    4849import ij.process.ImageProcessor; 
    4950 
     51import imagej.io.ImageOpener; 
     52 
     53import java.awt.Canvas; 
    5054import java.awt.Color; 
    5155import java.awt.Rectangle; 
     56import java.awt.event.MouseEvent; 
     57import java.awt.event.MouseListener; 
    5258import java.util.ArrayList; 
     59import java.util.HashMap; 
     60import java.util.Map; 
    5361import java.util.prefs.Preferences; 
    5462 
    5563import javax.swing.JComponent; 
    5664import javax.swing.JFrame; 
    57  
    58 import loci.colorizer.DataColorizer; 
     65import javax.swing.JPanel; 
     66 
     67import loci.slim.colorizer.DataColorizer; 
     68import loci.slim.ui.IStartStopListener; 
     69import loci.slim.ui.IUserInterfacePanel; 
     70import loci.slim.ui.IUserInterfacePanelListener; 
     71import loci.slim.ui.UserInterfacePanel; 
    5972import loci.common.DataTools; 
    6073import loci.curvefitter.CurveFitData; 
     
    7184import loci.formats.IFormatReader; 
    7285 
     86import mpicbg.imglib.cursor.Cursor; 
     87import mpicbg.imglib.cursor.LocalizableByDimCursor; 
     88import mpicbg.imglib.image.Image; 
     89//import mpicbg.imglib.Type; 
     90import mpicbg.imglib.type.numeric.RealType; 
     91 
    7392/** 
    7493 * TODO 
     
    8099 * @author Aivar Grislis grislis at wisc.edu 
    81100 */ 
    82 public class SLIMProcessor { 
     101public class SLIMProcessor <T extends RealType<T>> implements MouseListener { 
     102//public class SLIMProcessor <T extends Type> { 
     103    private static final String X = "X"; 
     104    private static final String Y = "Y"; 
     105    private static final String LIFETIME = "Lifetime"; 
     106    private static final String CHANNELS = "Channels"; 
     107 
    83108    // this affects how lifetimes are colorized: 
    84109    private static final double MAXIMUM_LIFETIME = 0.075; // for fitting fake with Jaolho // for fitting brian with barber triple integral 100.0f X tau vs lambda issue here 
     
    88113 
    89114    // Unicode special characters 
    90     private static final Character CHI = '\u03c7'; 
     115    private static final Character CHI    = '\u03c7'; 
    91116    private static final Character SQUARE = '\u00b2'; 
    92     private static final Character TAU = '\u03c4'; 
     117    private static final Character TAU    = '\u03c4'; 
    93118    private static final Character LAMBDA = '\u03bb'; 
    94     private static final Character SIGMA = '\u03c3'; 
    95     private static final Character SUB_1 = '\u2081'; 
    96     private static final Character SUB_2 = '\u2082'; 
    97     private static final Character SUB_3 = '\u2083'; 
     119    private static final Character SIGMA  = '\u03c3'; 
     120    private static final Character SUB_1  = '\u2081'; 
     121    private static final Character SUB_2  = '\u2082'; 
     122    private static final Character SUB_3  = '\u2083'; 
     123 
     124    private Object m_synchFit = new Object(); 
     125    private volatile boolean m_fitInProgress; 
     126    private volatile boolean m_fitted; 
    98127 
    99128    //TODO total kludge; just to get started 
     
    109138 
    110139    private ImageProcessor m_grayscaleImageProcessor; 
     140    private Canvas m_grayscaleCanvas; 
    111141 
    112142    // data parameters //TODO Curtis has these as protected 
     
    124154    private boolean m_floating; 
    125155    private float m_timeRange; 
    126     private int m_minWave, m_waveStep, m_maxWave; 
     156    private int m_minWave, m_waveStep; //, m_maxWave; 
    127157 
    128158    // fit parameters 
    129     private int m_numExp; 
    130     private int m_binRadius; 
    131     private int m_cutBins; 
    132     private int m_maxPeak; 
     159   // private int m_numExp; 
     160   // private int m_binRadius; 
     161   // private int m_cutBins; 
     162   // private int m_maxPeak; 
    133163 
    134164 
     
    151181    private int m_x; 
    152182    private int m_y; 
     183    private int m_channel; 
    153184 
    154185    private double[] m_param = new double[7]; 
    155186    private boolean[] m_free = { true, true, true, true, true, true, true }; 
    156  
    157     private boolean m_fitA1fixed; 
    158     private boolean m_fitT1fixed; 
    159     private boolean m_fitA2fixed; 
    160     private boolean m_fitT2fixed; 
    161     private boolean m_fitA3fixed; 
    162     private boolean m_fitT3fixed; 
    163     private boolean m_fitCfixed; 
    164187 
    165188    private int m_startBin; 
     
    169192    private float m_chiSqTarget; 
    170193 
     194    private int m_debug = 0; 
     195 
    171196    /** 
    172197     * Run thread for the plugin. 
     
    175200     */ 
    176201    public void run(String arg) { 
     202        m_fitInProgress = false; 
     203        m_fitted = false; 
     204 
     205        IUserInterfacePanel uiPanel = new UserInterfacePanel(true); 
     206        JPanel panel = uiPanel.getPanel(); 
     207         
     208        m_channel = 0; //TODO s/b a JSlider that controls current channel 
     209         
     210        boolean success = false; 
     211        if (showFileDialog(getFileFromPreferences())) { 
     212            if (m_fakeData) { 
     213                fakeData(); 
     214                success = true; 
     215            } 
     216            else { 
     217                if (newLoadData(m_file)) { 
     218                    saveFileInPreferences(m_file); 
     219                    success = true; 
     220                } 
     221            } 
     222        } 
     223         
     224        if (success) { 
     225            // create a grayscale image from the data 
     226            createGlobalGrayScale(); 
     227            while (true) { 
     228                // ask what kind fo fit 
     229                if (!showFitDialog()) { 
     230                    break; 
     231                } 
     232                // ask for fit parameters 
     233                if (!showFitParamsDialog()) { 
     234                    break; 
     235                } 
     236                fitData(); 
     237            } 
     238        } 
     239 
    177240        // ask for which file to load 
    178         if (showFileDialog(getFileFromPreferences())) { 
     241       /* if (showFileDialog(getFileFromPreferences())) { 
    179242            // load the file 
    180243            if (loadFile(m_file)) { 
     
    209272                IJ.error("File Error", "Unable to load file."); 
    210273            } 
    211         } 
     274        }*/ 
    212275    } 
    213276 
     
    237300    } 
    238301 
     302    private boolean newLoadData(String file) { 
     303        ImageOpener imageOpener = new ImageOpener(); 
     304        Image<T> image = null; 
     305        try { 
     306            image = imageOpener.openImage(file); 
     307        } 
     308        catch (Exception e) { 
     309            System.out.println("Error " + e.getMessage()); 
     310        } 
     311 
     312        int[] dimensions = image.getDimensions(); 
     313        Map map = dimensionMap(image.getName()); 
     314        Integer xIndex, yIndex, lifetimeIndex, channelIndex; 
     315        xIndex = (Integer) map.get(X); 
     316        yIndex = (Integer) map.get(Y); 
     317        lifetimeIndex = (Integer) map.get(LIFETIME); 
     318        if (null != xIndex && null != yIndex && null != lifetimeIndex) { 
     319            m_width = dimensions[xIndex]; 
     320            m_height = dimensions[yIndex]; 
     321            m_timeBins = dimensions[lifetimeIndex]; 
     322        } 
     323        else { 
     324            System.out.println("Can't find dimensions of .sdt Image " + image.getName()); 
     325            return false; 
     326        } 
     327        m_channels = 1; 
     328        channelIndex = (Integer) map.get(CHANNELS); 
     329        if (null != channelIndex) { 
     330            m_channels = dimensions[channelIndex]; 
     331        } 
     332 
     333        System.out.println("width " + m_width + " height " + m_height + " timeBins " + m_timeBins + " channels " + m_channels); 
     334        m_data = new int[m_channels][m_height][m_width][m_timeBins]; 
     335        final LocalizableByDimCursor<T> cursor = image.createLocalizableByDimCursor(); 
     336        int x, y, bin, channel; 
     337        for (channel = 0; channel < m_channels; ++channel) { 
     338            if (null != channelIndex) { 
     339                dimensions[channelIndex] = channel; 
     340            } 
     341            for (y = 0; y < m_height; ++y) { 
     342                dimensions[yIndex] = y; 
     343                for (x = 0; x < m_width; ++x) { 
     344                    dimensions[xIndex] = x; 
     345                    for (bin = 0; bin < m_timeBins; ++bin) { 
     346                        dimensions[lifetimeIndex] = bin; 
     347                        cursor.moveTo(dimensions); 
     348                        m_data[channel][y][x][bin] = (int) cursor.getType().getRealFloat(); 
     349                        if (m_data[channel][y][x][bin] > 100 && ++m_debug < 100) { 
     350                            System.out.println("m_data " + m_data[channel][y][x][bin] + " cursor " + cursor.getType().getRealFloat()); 
     351                        } 
     352                    } 
     353                } 
     354            } 
     355        } 
     356        cursor.close(); 
     357        // print out some useful information about the image 
     358        //System.out.println(image); 
     359        //final Cursor<T> cursor = image.createCursor(); 
     360        //cursor.fwd(); 
     361        //System.out.println("\tType = " + cursor.getType().getClass().getName()); 
     362        //cursor.close(); 
     363 
     364        // patch things up 
     365        m_timeRange = 10.0f; 
     366 
     367        return true; 
     368    } 
     369 
     370    /* 
     371     * This method parses a string of the format: 
     372     * "Name [X Y Timebins]" and builds a map with 
     373     * the dimensions 'X', 'Y', and 'Timebins'. 
     374     * 
     375     * Temporary kludge. 
     376     */ 
     377    private Map dimensionMap(String name) { 
     378        Map map = new HashMap<String, Integer>(); 
     379        int startIndex = name.indexOf('[') + 1; 
     380        int endIndex = name.indexOf(']'); 
     381        String coded = name.substring(startIndex, endIndex); 
     382        String dimensions[] = coded.split(" "); 
     383        int index = 0; 
     384        for (String dimension : dimensions) { 
     385            map.put(dimension, index++); 
     386        } 
     387        return map; 
     388    } 
     389 
    239390    /** 
    240391     * Loads the .sdt file. 
     
    242393     * 
    243394     * @param file 
    244      * @return 
     395     * @return whether successful 
    245396     */ 
    246397    private boolean loadFile(String file) { 
     
    283434            m_minWave = 400; 
    284435            m_waveStep = 10; 
    285             m_binRadius = 3; 
     436            //m_binRadius = 3; 
    286437            status = true; 
    287438        } 
     
    295446     * This routine creates an artificial set of data that is useful to test fitting. 
    296447     * 
    297      * @return 
     448     * @return whether successful 
    298449     */ 
    299450    private boolean fakeData() { 
     
    342493     * Restores file name from Java Preferences. 
    343494     * 
    344      * @return 
     495     * @return file name String 
    345496     */ 
    346497    private String getFileFromPreferences() { 
     
    360511 
    361512    /** 
    362      * This dialog shows the parameters from the .sdt file.  Currently this is 
    363      * only for display.  I believe SLIMPlotter lets you edit them. 
    364      * 
    365      * @return 
     513     * This dialog shows the parameters from the .sdt file and allows user 
     514     * to edit 
     515     * 
     516     * @return whether successful 
    366517     */ 
    367518    private boolean showParamsDialog() { 
     
    379530            return false; 
    380531        } 
     532        m_width     = (int) dialog.getNextNumber(); 
     533        m_height    = (int) dialog.getNextNumber(); 
     534        m_timeBins  = (int) dialog.getNextNumber(); 
     535        m_channels  = (int) dialog.getNextNumber(); 
     536        m_timeRange = (int) dialog.getNextNumber(); 
     537        m_minWave   = (int) dialog.getNextNumber(); 
     538        m_waveStep  = (int) dialog.getNextNumber(); 
    381539        return true; 
    382540    } 
     
    386544     * Based on loci.slim.SlimData constructor. 
    387545     * 
    388      * @return whether or not successful 
     546     * @return whether successful 
    389547     */ 
    390548    private boolean loadData() { 
     
    436594     * image for the data. 
    437595     * 
    438      * @return 
     596     * @return whether successful 
    439597     */ 
    440598    private boolean createGlobalGrayScale() { 
     
    468626        imagePlus.show(); 
    469627        m_grayscaleImageProcessor = imageProcessor; //TODO for now 
     628 
     629        // hook up mouse listener 
     630        ImageWindow imageWindow = imagePlus.getWindow(); 
     631        m_grayscaleCanvas = imageWindow.getCanvas(); 
     632        m_grayscaleCanvas.addMouseListener(this); 
    470633        return true; 
    471634    } 
     
    717880 
    718881    /** 
     882     * MouseListener handler for button press. 
     883     * Ignored. 
     884     * 
     885     * @param e 
     886     */ 
     887    public void mousePressed(MouseEvent e) { 
     888    } 
     889     
     890    /** 
     891     * MouseListener handler for mouse exit. 
     892     * Ignored. 
     893     * 
     894     * @param e 
     895     */ 
     896    public void mouseExited(MouseEvent e) { 
     897    } 
     898     
     899    /** 
     900     * MouseListener handler for button click. 
     901     * Ignored. 
     902     * 
     903     * @param e 
     904     */ 
     905    public void mouseClicked(MouseEvent e) { 
     906    } 
     907     
     908    /** 
     909     * MouseListener handler for mouse enter. 
     910     * Ignored. 
     911     * 
     912     * @param e 
     913     */ 
     914    public void mouseEntered(MouseEvent e) { 
     915    } 
     916 
     917 
     918    /** 
     919     * MouseListener handler for button release. 
     920     * Clicking on a pixel triggers a fit. 
     921     * 
     922     * @param e 
     923     */ 
     924    public void mouseReleased(MouseEvent e) { 
     925        // just ignore clicks during a fit 
     926        System.out.println("mouseReleased " + e); 
     927        if (!m_fitInProgress) { 
     928            System.out.println("fit " + e.getX() + " " + e.getY()); 
     929            fitPixel(e.getX(), e.getY()); 
     930        } 
     931     } 
     932     
     933    private void fitData() { 
     934        System.out.println("FIT DATA"); 
     935        // only one fit at a time 
     936        synchronized (m_synchFit) { 
     937            // disable mouse click pixel fits 
     938            m_fitInProgress = true; 
     939             
     940            switch (m_region) { 
     941                case SUMMED: 
     942                    // sum all pixels 
     943                    fitSummed(); 
     944                    break; 
     945                case ROI: 
     946                    // fit summed ROIs 
     947                    fitROIs(); 
     948                    break; 
     949                case POINT: 
     950                    // fit single pixel 
     951                    fitPixel(m_x, m_y); 
     952                    break; 
     953                case EACH: 
     954                    // fit every pixel 
     955                    fitEachPixel(); 
     956                    break; 
     957            } 
     958System.out.println("m_fitInProgress goes false"); 
     959            m_fitInProgress = false; 
     960        } 
     961    } 
     962 
     963    /* 
     964     * Sums all pixels and fits the result. 
     965     */ 
     966    private void fitSummed() { 
     967        double params[] = getParams(); 
     968         
     969        // build the data 
     970        ArrayList<ICurveFitData> curveFitDataList = new ArrayList<ICurveFitData>(); 
     971        ICurveFitData curveFitData; 
     972        double yCount[]; 
     973        double yFitted[]; 
     974         
     975        // sum up all the photons 
     976        curveFitData = new CurveFitData(); 
     977        curveFitData.setParams(params); 
     978        yCount = new double[m_timeBins]; 
     979        for (int b = 0; b < m_timeBins; ++b) { 
     980            yCount[b] = 0.0; 
     981        } 
     982        int photons = 0; 
     983        for (int y = 0; y < m_height; ++y) { 
     984            for (int x = 0; x < m_width; ++x) { 
     985                for (int b = 0; b < m_timeBins; ++b) { 
     986                    yCount[b] += m_data[m_channel][y][x][b]; 
     987                    photons += m_data[m_channel][y][x][b]; 
     988                } 
     989            } 
     990        } 
     991        System.out.println("SUMMED photons " + photons); 
     992        curveFitData.setYCount(yCount); 
     993        yFitted = new double[m_timeBins]; 
     994        curveFitData.setYFitted(yFitted); 
     995        curveFitDataList.add(curveFitData); 
     996 
     997        // do the fit 
     998        ICurveFitData dataArray[] = curveFitDataList.toArray(new ICurveFitData[0]); 
     999        doFit(dataArray); 
     1000         
     1001        //TODO display results for summed? 
     1002        IJ.showMessage("Summed " + dataArray[0].getParams()[0] + " " + dataArray[0].getParams()[1] + " " + dataArray[0].getParams()[2]); 
     1003 
     1004        showDecayGraph(dataArray); 
     1005        saveParams(dataArray); 
     1006    } 
     1007 
     1008    /* 
     1009     * Sums and fits each ROI. 
     1010     */ 
     1011    private void fitROIs() { 
     1012        double params[] = getParams(); 
     1013         
     1014        // build the data 
     1015        ArrayList<ICurveFitData> curveFitDataList = new ArrayList<ICurveFitData>(); 
     1016        ICurveFitData curveFitData; 
     1017        double yCount[]; 
     1018        double yFitted[]; 
     1019         
     1020        int roiNumber = 0; 
     1021        for (Roi roi: getRois()) { 
     1022            ++roiNumber; 
     1023            curveFitData = new CurveFitData(); 
     1024            curveFitData.setParams(params.clone()); 
     1025            yCount = new double[m_timeBins]; 
     1026            for (int b = 0; b < m_timeBins; ++b) { 
     1027                yCount[b] = 0.0; 
     1028            } 
     1029            Rectangle bounds = roi.getBounds(); 
     1030            for (int x = 0; x < bounds.width; ++x) { 
     1031                for (int y = 0; y < bounds.height; ++y) { 
     1032                    if (roi.contains(bounds.x + x, bounds.y + y)) { 
     1033                        System.out.println("roi " + roiNumber + " x " + x + " Y " + y); 
     1034                        for (int b = 0; b < m_timeBins; ++b) { 
     1035                           yCount[b] += m_data[m_channel][y][x][b]; 
     1036                        } 
     1037                    } 
     1038                } 
     1039            } 
     1040            curveFitData.setYCount(yCount); 
     1041            yFitted = new double[m_timeBins]; 
     1042            curveFitData.setYFitted(yFitted); 
     1043            curveFitDataList.add(curveFitData); 
     1044        } 
     1045         
     1046        // do the fit 
     1047        ICurveFitData dataArray[] = curveFitDataList.toArray(new ICurveFitData[0]); 
     1048        doFit(dataArray); 
     1049         
     1050        showDecayGraph(dataArray); 
     1051         
     1052        // show colorized lifetimes 
     1053        ImageProcessor imageProcessor = new ColorProcessor(m_width, m_height); 
     1054        ImagePlus imagePlus = new ImagePlus("Fitted Lifetimes", imageProcessor); 
     1055        int i = 0; 
     1056        for (Roi roi: getRois()) { 
     1057            IJ.showMessage("Roi " + i + " " + dataArray[i].getParams()[0] + " " + dataArray[i].getParams()[1] + " " + dataArray[i].getParams()[2]); 
     1058            double lifetime = dataArray[i++].getParams()[1]; 
     1059            imageProcessor.setColor(lifetimeColorMap(MAXIMUM_LIFETIME, lifetime)); 
     1060 
     1061            Rectangle bounds = roi.getBounds(); 
     1062            for (int x = 0; x < bounds.width; ++x) { 
     1063                for (int y = 0; y < bounds.height; ++y) { 
     1064                    if (roi.contains(bounds.x + x, bounds.y + y)) { 
     1065                        imageProcessor.drawPixel(bounds.x + x, bounds.y + y); 
     1066                    } 
     1067                } 
     1068            } 
     1069        } 
     1070        imagePlus.show();   
     1071         
     1072        saveParams(dataArray); 
     1073    } 
     1074 
     1075    /* 
     1076     * Fits a given pixel. 
     1077     *  
     1078     * @param x 
     1079     * @param y 
     1080     */ 
     1081    private void fitPixel(int x, int y) { 
     1082        double params[] = getParams(); 
     1083         
     1084        // build the data 
     1085        ArrayList<ICurveFitData> curveFitDataList = new ArrayList<ICurveFitData>(); 
     1086        ICurveFitData curveFitData; 
     1087        double yCount[]; 
     1088        double yFitted[]; 
     1089         
     1090        curveFitData = new CurveFitData(); 
     1091        curveFitData.setParams(params); 
     1092        yCount = new double[m_timeBins]; 
     1093        for (int b = 0; b < m_timeBins; ++b) { 
     1094            yCount[b] = m_data[m_channel][m_height - y - 1][x][b]; 
     1095        } 
     1096        curveFitData.setYCount(yCount); 
     1097        yFitted = new double[m_timeBins]; 
     1098        curveFitData.setYFitted(yFitted); 
     1099        curveFitDataList.add(curveFitData); 
     1100         
     1101        // do the fit 
     1102        ICurveFitData dataArray[] = curveFitDataList.toArray(new ICurveFitData[0]); 
     1103        doFit(dataArray); 
     1104         
     1105        showDecayGraph(dataArray); 
     1106         
     1107        //TODO display results for single point? 
     1108        IJ.showMessage("Point A " + dataArray[0].getParams()[0] + " " + LAMBDA + " " + dataArray[0].getParams()[1] + " b " + dataArray[0].getParams()[2]); 
     1109         
     1110        saveParams(dataArray); 
     1111    } 
     1112  
     1113    /* 
     1114     * Fits each and every pixel.  This is the most complicated fit. 
     1115     * 
     1116     * If a channel is visible it is fit first and drawn incrementally. 
     1117     * 
     1118     * Results of the fit go to VisAD for analysis. 
     1119     */ 
     1120    private void fitEachPixel() { 
     1121        long start = System.nanoTime(); 
     1122         
     1123        double params[] = getParams(); 
     1124         
     1125        // build the data 
     1126        ArrayList<ICurveFitData> curveFitDataList = new ArrayList<ICurveFitData>(); 
     1127        ArrayList<ChunkyPixel> pixelList = new ArrayList<ChunkyPixel>(); 
     1128        ICurveFitData curveFitData; 
     1129        double yCount[]; 
     1130        double yFitted[]; 
     1131 
     1132        // special handling for visible channel 
     1133        int visibleChannel = m_channel; //TODO somehow else; m_channel s/b 0 
     1134        if (-1 != visibleChannel) { 
     1135            // show colorized image 
     1136            DataColorizer dataColorizer = new DataColorizer(m_width, m_height, m_algorithm + " Fitted Lifetimes"); 
     1137 
     1138            ChunkyPixelEffectIterator pixelIterator = new ChunkyPixelEffectIterator(new ChunkyPixelTableImpl(), m_width, m_height); 
     1139 
     1140            int pixelCount = 0; 
     1141            int pixelsToProcessCount = 0; 
     1142            while (pixelIterator.hasNext()) { 
     1143                ++pixelCount; 
     1144                IJ.showProgress(pixelCount, m_height * m_width); 
     1145                ChunkyPixel pixel = pixelIterator.next(); 
     1146                if (wantFitted(pixel.getX(), pixel.getY())) { 
     1147                    curveFitData = new CurveFitData(); 
     1148                    curveFitData.setParams(params.clone()); 
     1149                    yCount = new double[m_timeBins]; 
     1150                    for (int b = 0; b < m_timeBins; ++b) { 
     1151                        yCount[b] = m_data[visibleChannel][pixel.getY()][pixel.getX()][b]; 
     1152                    } 
     1153                    curveFitData.setYCount(yCount); 
     1154                    yFitted = new double[m_timeBins]; 
     1155                    curveFitData.setYFitted(yFitted); 
     1156                    curveFitDataList.add(curveFitData); 
     1157                    pixelList.add(pixel); 
     1158 
     1159 
     1160                    if (++pixelsToProcessCount >= PIXEL_COUNT) { 
     1161                        processPixels(dataColorizer, m_height, curveFitDataList.toArray(new ICurveFitData[0]), pixelList.toArray(new ChunkyPixel[0])); 
     1162                        curveFitDataList.clear(); 
     1163                        pixelList.clear(); 
     1164                        pixelsToProcessCount = 0; 
     1165                    } 
     1166                } 
     1167            } 
     1168            if (0 < pixelsToProcessCount) { 
     1169                processPixels(dataColorizer, m_height, curveFitDataList.toArray(new ICurveFitData[0]), pixelList.toArray(new ChunkyPixel[0])); 
     1170            } 
     1171        } 
     1172  
     1173        // any channels remaining? 
     1174        if (-1 == visibleChannel || m_channels > 1) { 
     1175            // fit rest of channels in expeditious way 
     1176            Roi[] rois = getRois(); 
     1177            // are there ROIs defined? 
     1178            if (0 < rois.length) { 
     1179                for (Roi roi: rois) { 
     1180                    // yes, use ROI bounding boxes to limit iteration 
     1181                    Rectangle bounds = roi.getBounds(); 
     1182                    for (int x = 0; x < bounds.width; ++x) { 
     1183                        for (int y = 0; y < bounds.height; ++y) { 
     1184                            if (roi.contains(bounds.x + x, bounds.y + y)) { 
     1185                                for (int channel = 0; channel < m_channels; ++channel) { 
     1186                                    if (channel != visibleChannel) { 
     1187                                        if (wantFitted(bounds.x + x, bounds.y + y)) { 
     1188                                            curveFitData = new CurveFitData(); 
     1189                                            curveFitData.setParams(params.clone()); 
     1190                                            yCount = new double[m_timeBins]; 
     1191                                            for (int b = 0; b < m_timeBins; ++b) { 
     1192                                                yCount[b] = m_data[channel][y][x][b]; 
     1193                                            } 
     1194                                            curveFitData.setYCount(yCount); 
     1195                                            yFitted = new double[m_timeBins]; 
     1196                                            curveFitData.setYFitted(yFitted); 
     1197                                            curveFitDataList.add(curveFitData); 
     1198                                        } 
     1199                                    } 
     1200                                } 
     1201                            } 
     1202                        } 
     1203                    } 
     1204                } 
     1205            } 
     1206            else { 
     1207                // no ROIs, loop over entire image 
     1208                for (int channel = 0; channel < m_channels; ++channel) { 
     1209                    if (channel != visibleChannel) { 
     1210                        for (int y = 0; y < m_height; ++y) { 
     1211                            for (int x = 0; x < m_width; ++x) { 
     1212                                if (aboveThreshold(x, y)) { 
     1213                                    curveFitData = new CurveFitData(); 
     1214                                    curveFitData.setParams(params.clone()); 
     1215                                    yCount = new double[m_timeBins]; 
     1216                                    for (int b = 0; b < m_timeBins; ++b) { 
     1217                                        yCount[b] = m_data[channel][y][x][b]; 
     1218                                    } 
     1219                                    curveFitData.setYCount(yCount); 
     1220                                    yFitted = new double[m_timeBins]; 
     1221                                    curveFitData.setYFitted(yFitted); 
     1222                                    curveFitDataList.add(curveFitData); 
     1223                                } 
     1224                            } 
     1225                        } 
     1226                    } 
     1227 
     1228                } 
     1229            } 
     1230        }      
     1231        //TODO break the fit up into chunks to lower memory requirements 
     1232        ICurveFitData dataArray[] = curveFitDataList.toArray(new ICurveFitData[0]); 
     1233        doFit(dataArray); 
     1234        //TODO save results 
     1235 
     1236        long elapsed = System.nanoTime() - start; 
     1237        System.out.println("nanoseconds " + elapsed); 
     1238    } 
     1239 
     1240    /** 
     1241     * Processes (fits) a batch of pixels. 
     1242     * 
     1243     * @param dataColorizer automatically sets colorization range and updates colorized image 
     1244     * @param height passed in to fix a vertical orientation problem 
     1245     * @param data list of data corresponding to pixels to be fitted 
     1246     * @param pixels parallel list of rectangles with which to draw the fitted pixel 
     1247     */ 
     1248    void processPixels(DataColorizer dataColorizer, int height, ICurveFitData data[], ChunkyPixel pixels[]) { 
     1249        doFit(data); 
     1250        //TODO save results 
     1251 
     1252        // draw as you go; 'chunky' pixels get smaller as the overall fit progresses 
     1253        for (int i = 0; i < pixels.length; ++i) { 
     1254            ChunkyPixel pixel = pixels[i]; 
     1255            double lifetime = data[i].getParams()[1]; 
     1256 
     1257            //TODO debugging: 
     1258            if (lifetime > 2 * m_param[1]) { 
     1259                System.out.println("BAD FIT??? x " + pixel.getX() + " y " + pixel.getY() + " fitted lifetime " + lifetime); 
     1260            } 
     1261 
     1262            //TODO BUG: 
     1263            // With the table as is, you can get 
     1264            //   x   y   w   h 
     1265            //   12  15  2   1 
     1266            //   14  15  2   1 
     1267            // all within the same drawing cycle. 
     1268            // So it looks like a 4x1 slice gets drawn (it 
     1269            // is composed of two adjacent 2x1 slices with 
     1270            // potentially two different colors). 
     1271            //if (pixel.getWidth() == 2) { 
     1272            //    System.out.println("x " + pixel.getX() + " y " + pixel.getY() + " w " + pixel.getWidth() + " h " + pixel.getHeight()); 
     1273            //} 
     1274            //System.out.println("w " + pixel.getWidth() + " h " + pixel.getHeight()); 
     1275            //System.out.println("lifetime is " + lifetime); 
     1276            //Color color = lifetimeColorMap(MAXIMUM_LIFETIME, lifetime); 
     1277            //imageProcessor.setColor(color); 
     1278 
     1279            boolean firstTime = true; 
     1280            for (int x = pixel.getX(); x < pixel.getX() + pixel.getWidth(); ++x) { 
     1281                for (int y = pixel.getY(); y < pixel.getY() + pixel.getHeight(); ++y) { 
     1282                    if (wantFitted(x, y)) { 
     1283                        // (flip vertically) 
     1284                        dataColorizer.setData(firstTime, x, height - y - 1 , lifetime); 
     1285                        firstTime = false; 
     1286                    } 
     1287                } 
     1288            } 
     1289        } 
     1290        dataColorizer.update(); 
     1291    } 
     1292 
     1293    /** 
     1294     * Checks criterion for whether this pixel needs to get fitted or drawn. 
     1295     * 
     1296     * @param x 
     1297     * @param y 
     1298     * @return whether to include or ignore this pixel 
     1299     */ 
     1300    boolean wantFitted(int x, int y) { 
     1301        return (aboveThreshold(x, y) & isInROIs(x, y)); 
     1302    } 
     1303 
     1304    /** 
     1305     * Checks whether a given pixel is above threshold photon count value. 
     1306     * 
     1307     * @param x 
     1308     * @param y 
     1309     * @return whether above threshold 
     1310     */ 
     1311    boolean aboveThreshold(int x, int y) { 
     1312        //TODO should the threshold be the same for all channels? 
     1313        return (m_threshold <= m_grayscaleImageProcessor.getPixel(x, m_height - y - 1)); 
     1314    } 
     1315 
     1316    /** 
     1317     * Checks whether a given pixel is included in ROIs.  If no ROIs are 
     1318     * selected then all pixels are included. 
     1319     * 
     1320     * @param x 
     1321     * @param y 
     1322     * @return whether or not included in ROIs 
     1323     */ 
     1324    boolean isInROIs(int x, int y) { 
     1325        Roi[] rois = getRois(); 
     1326        if (0 < rois.length) { 
     1327            for (Roi roi: rois) { 
     1328                if (roi.contains(x, y)) { 
     1329                    return true; 
     1330                } 
     1331            } 
     1332            return false; 
     1333        } 
     1334        else { 
     1335            return true; 
     1336        } 
     1337    } 
     1338 
     1339    /** 
     1340     * Gets a list of ROIs (may be empty). 
     1341     * 
     1342     * @return array of ROIs. 
     1343     */ 
     1344    private Roi[] getRois() { 
     1345        Roi[] rois = {}; 
     1346        RoiManager manager = RoiManager.getInstance(); 
     1347        if (null != manager) { 
     1348            rois = manager.getRoisAsArray(); 
     1349        } 
     1350        return rois; 
     1351    } 
     1352 
     1353    /** 
     1354     * Colorizes a given lifetime value. 
     1355     * 
     1356     * Note this is much cruder than the DataColorizer that is 
     1357     * used in fitEachPixel. 
     1358     * 
     1359     * @param max 
     1360     * @param lifetime 
     1361     * @return 
     1362     */ 
     1363    //TODO make consistent with fitEachPixel's DataColorizer 
     1364     private Color lifetimeColorMap(double max, double lifetime) { 
     1365        Color returnColor = Color.BLACK; 
     1366        if (lifetime > 0.0) { 
     1367            if (lifetime < max/2.0) { 
     1368                returnColor = interpolateColor(Color.BLUE, Color.GREEN, 2.0 * lifetime / max); 
     1369            } 
     1370            else if (lifetime < max) { 
     1371                returnColor = interpolateColor(Color.GREEN, Color.RED, 2.0 * (lifetime - max / 2.0) / max); 
     1372            } 
     1373            else returnColor = Color.RED; 
     1374        } 
     1375        return returnColor; 
     1376    } 
     1377 
     1378     /** 
     1379      * Interpolates between two colors based on a blend factor. 
     1380      * 
     1381      * @param start color 
     1382      * @param end color 
     1383      * @param blend factor 
     1384      * @return interpolated color 
     1385      */ 
     1386    private Color interpolateColor(Color start, Color end, double blend) { 
     1387        int startRed   = start.getRed(); 
     1388        int startGreen = start.getGreen(); 
     1389        int startBlue  = start.getBlue(); 
     1390        int endRed   = end.getRed(); 
     1391        int endGreen = end.getGreen(); 
     1392        int endBlue  = end.getBlue(); 
     1393        int red   = interpolateColorComponent(startRed, endRed, blend); 
     1394        int green = interpolateColorComponent(startGreen, endGreen, blend); 
     1395        int blue  = interpolateColorComponent(startBlue, endBlue, blend); 
     1396        return new Color(red, green, blue); 
     1397    } 
     1398 
     1399    /** 
     1400     * Interpolates a single RGB component between two values based on 
     1401     * a blend factor. 
     1402     * 
     1403     * @param start component value 
     1404     * @param end component value 
     1405     * @param blend factor 
     1406     * @return interpolated component value 
     1407     */ 
     1408    private int interpolateColorComponent(int start, int end, double blend) { 
     1409        return (int)(blend * (end - start) + start); 
     1410    } 
     1411 
     1412    /* 
     1413     * Helper function for the fit.  Initializes params array. 
     1414     *  
     1415     * @return initialized params array 
     1416     */ 
     1417    private double[] getParams() { 
     1418        // build the params 
     1419        double params[] = null; 
     1420        switch (m_function) { 
     1421            case SINGLE_EXPONENTIAL: 
     1422                params = new double[3]; 
     1423                params[0] = m_param[0]; 
     1424                params[1] = m_param[1]; 
     1425                params[2] = m_param[2]; 
     1426                break; 
     1427            case DOUBLE_EXPONENTIAL: 
     1428                params = new double[5]; 
     1429                params[0] = m_param[0]; 
     1430                params[1] = m_param[1]; 
     1431                params[2] = m_param[2]; 
     1432                params[3] = m_param[3]; 
     1433                params[4] = m_param[4]; 
     1434                break; 
     1435            case TRIPLE_EXPONENTIAL: 
     1436                params = new double[7]; 
     1437                params[0] = m_param[0]; 
     1438                params[1] = m_param[1]; 
     1439                params[2] = m_param[2]; 
     1440                params[3] = m_param[3]; 
     1441                params[4] = m_param[4]; 
     1442                params[5] = m_param[5]; 
     1443                params[6] = m_param[6]; 
     1444                break; 
     1445            case STRETCHED_EXPONENTIAL: 
     1446                System.out.println("NOT IMPLEMENTED YET"); 
     1447                break; 
     1448        } 
     1449        return params; 
     1450    } 
     1451  
     1452    /* 
     1453     * Helper function for the fit.  Does the actual fit. 
     1454     *  
     1455     * @param dataArray array of data to fit 
     1456     */ 
     1457    //TODO s/b a mechanism to add these curve fit libraries? 
     1458    private void doFit(ICurveFitData dataArray[]) { 
     1459        // do the fit 
     1460        ICurveFitter curveFitter = null; 
     1461        switch (m_algorithm) { 
     1462            case JAOLHO: 
     1463                curveFitter = new JaolhoCurveFitter(); 
     1464                break; 
     1465           /* case AKUTAN: 
     1466                curveFitter = new AkutanCurveFitter(); 
     1467                break; */ 
     1468            case BARBER_RLD: 
     1469                curveFitter = new GrayCurveFitter(0); 
     1470                break; 
     1471            case BARBER_LMA: 
     1472                curveFitter = new GrayCurveFitter(1); 
     1473                break; 
     1474            case MARKWARDT: 
     1475                curveFitter = new MarkwardtCurveFitter(); 
     1476                break; 
     1477            case BARBER2_RLD: 
     1478                curveFitter = new GrayNRCurveFitter(0); 
     1479                break; 
     1480            case BARBER2_LMA: 
     1481                curveFitter = new GrayNRCurveFitter(1); 
     1482                break; 
     1483            case SLIMCURVE_RLD: 
     1484                curveFitter = new SLIMCurveFitter(0); 
     1485                break; 
     1486            case SLIMCURVE_LMA: 
     1487                curveFitter = new SLIMCurveFitter(1); 
     1488                break; 
     1489        } 
     1490        curveFitter.setXInc(m_timeRange); 
     1491        curveFitter.setFree(m_free); 
     1492        int startBin = m_startBin + (256 * m_startX); 
     1493        curveFitter.fitData(dataArray, startBin, m_stopBin);         
     1494    } 
     1495 
     1496    /* 
     1497     * Helper function for the fit.  Shows the decay curve. 
     1498     *  
     1499     * @param dataArray array of fitted data 
     1500     */ 
     1501    private void showDecayGraph(ICurveFitData dataArray[]) { 
     1502        if (0 < dataArray.length) { 
     1503            //TODO need to be able to examine any fitted pixel; for now just show the last fitted pixel. // first! 
     1504            DecayGraph decayGraph = new DecayGraph(m_timeRange, m_startBin, m_stopBin, dataArray[0]); //dataArray.length - 1]); 
     1505            decayGraph.setStartStopListener(new MyListener()); 
     1506                    JFrame window = new JFrame("SLIM"); 
     1507                    JComponent component = decayGraph.getComponent(); 
     1508                    window.getContentPane().add(component); 
     1509                    window.setSize(450, 450); 
     1510                    window.pack(); 
     1511                    window.setVisible(true); 
     1512        } 
     1513         
     1514    } 
     1515 
     1516    /* 
     1517     * Helper function for the fit.  Saves params array. 
     1518     *  
     1519     * @param dataArray array of fitted data 
     1520     */ 
     1521    //TODO params are saved to the UI now 
     1522    private void saveParams(ICurveFitData dataArray[]) { 
     1523        double params[] = null; 
     1524        if (0 < dataArray.length) { 
     1525            params = dataArray[0].getParams(); 
     1526            switch (m_function) { 
     1527                case SINGLE_EXPONENTIAL: 
     1528                    m_param[0] = params[0]; 
     1529                    m_param[1] = params[1]; 
     1530                    m_param[2] = params[2]; 
     1531                    break; 
     1532                case DOUBLE_EXPONENTIAL: 
     1533                    m_param[0] = params[0]; 
     1534                    m_param[1] = params[1]; 
     1535                    m_param[2] = params[2]; 
     1536                    m_param[3] = params[3]; 
     1537                    m_param[4] = params[4]; 
     1538                    break; 
     1539                case TRIPLE_EXPONENTIAL: 
     1540                    m_param[0] = params[0]; 
     1541                    m_param[1] = params[1]; 
     1542                    m_param[2] = params[2]; 
     1543                    m_param[3] = params[3]; 
     1544                    m_param[4] = params[4]; 
     1545                    m_param[5] = params[5]; 
     1546                    m_param[6] = params[6]; 
     1547                    break; 
     1548                case STRETCHED_EXPONENTIAL: 
     1549                    System.out.println("Not implemented yet"); 
     1550                    break; 
     1551            } 
     1552        } 
     1553    } 
     1554     
     1555    /** 
    7191556     * This routine does the fit, once all settings have 
    7201557     * been specified. 
     
    7261563     * and fit by ROI. 
    7271564     */ 
    728     private void fitData() { 
     1565    private void fitDataXX() { 
    7291566        if (m_region.EACH == m_region) { 
    7301567            fitEachPixel(); 
     
    10191856    } 
    10201857 
    1021     int m_maxX = 0; 
    1022     int m_maxY = 0; 
    1023     int m_maxValue = -1; 
    1024  
    10251858    /** 
    10261859     * Fits each & every pixel in the image that is 
     
    10341867     * do the fit. 
    10351868     */ 
    1036     private void fitEachPixel() { 
     1869    private void fitEachPixelX() { 
    10371870        long start = System.nanoTime(); 
    10381871 
     
    11181951        } 
    11191952        long elapsed = System.nanoTime() - start; 
    1120         System.out.println("m_maxX, " + m_maxX + " m_maxY " + m_maxY + " m_maxVaue " + m_maxValue + " nanoseconds " + elapsed); 
    1121     } 
    1122  
    1123     /** 
    1124      * Processes (fits) a batch of pixels. 
    1125      * 
    1126      * @param dataColorizer automatically sets colorization range and updates colorized image 
    1127      * @param height passed in to fix a vertical orientation problem 
    1128      * @param data list of data corresponding to pixels to be fitted 
    1129      * @param pixels parallel list of rectangles with which to draw the fitted pixel 
    1130      */ 
    1131     void processPixels(DataColorizer dataColorizer, int height, ICurveFitData data[], ChunkyPixel pixels[]) { 
    1132         // do the fit 
    1133         ICurveFitter curveFitter = null; 
    1134         switch (m_algorithm) { 
    1135             case JAOLHO: 
    1136                 curveFitter = new JaolhoCurveFitter(); 
    1137                 break; 
    1138             /* case AKUTAN: 
    1139                 curveFitter = new AkutanCurveFitter(); 
    1140                 break; */ 
    1141             case BARBER_RLD: 
    1142                 curveFitter = new GrayCurveFitter(0); 
    1143                 break; 
    1144             case BARBER_LMA: 
    1145                 curveFitter = new GrayCurveFitter(1); 
    1146                 break; 
    1147             case MARKWARDT: 
    1148                 curveFitter = new MarkwardtCurveFitter(); 
    1149                 break; 
    1150             //TODO ARG this same switch statement is in 2 places!!! 
    1151             case BARBER2_RLD: 
    1152                 curveFitter = new GrayNRCurveFitter(0); 
    1153                 break; 
    1154             case BARBER2_LMA: 
    1155                 curveFitter = new GrayNRCurveFitter(1); 
    1156                 break; 
    1157             case SLIMCURVE_RLD: 
    1158                 curveFitter = new SLIMCurveFitter(0); 
    1159                 break; 
    1160             case SLIMCURVE_LMA: 
    1161                 curveFitter = new SLIMCurveFitter(1); 
    1162                 break; 
    1163         } 
    1164         curveFitter.setXInc(m_timeRange); 
    1165         curveFitter.setFree(m_free); 
    1166         int startBin = m_startBin + (256 * m_startX); 
    1167         curveFitter.fitData(data, startBin, m_stopBin); 
    1168  
    1169         // draw as you go; 'chunky' pixels get smaller as the overall fit progresses 
    1170         for (int i = 0; i < pixels.length; ++i) { 
    1171             ChunkyPixel pixel = pixels[i]; 
    1172             double lifetime = data[i].getParams()[1]; 
    1173  
    1174             //TODO debugging: 
    1175             if (lifetime > 2 * m_param[1]) { 
    1176                 System.out.println("BAD FIT??? x " + pixel.getX() + " y " + pixel.getY() + " fitted lifetime " + lifetime); 
    1177             } 
    1178  
    1179             //TODO BUG: 
    1180             // With the table as is, you can get 
    1181             //   x   y   w   h 
    1182             //   12  15  2   1 
    1183             //   14  15  2   1 
    1184             // all within the same drawing cycle. 
    1185             // So it looks like a 4x1 slice gets drawn (it 
    1186             // is composed of two adjacent 2x1 slices with 
    1187             // potentially two different colors). 
    1188             //if (pixel.getWidth() == 2) { 
    1189             //    System.out.println("x " + pixel.getX() + " y " + pixel.getY() + " w " + pixel.getWidth() + " h " + pixel.getHeight()); 
    1190             //} 
    1191             //System.out.println("w " + pixel.getWidth() + " h " + pixel.getHeight()); 
    1192             //System.out.println("lifetime is " + lifetime); 
    1193             //Color color = lifetimeColorMap(MAXIMUM_LIFETIME, lifetime); 
    1194             //imageProcessor.setColor(color); 
    1195  
    1196             boolean firstTime = true; 
    1197             for (int x = pixel.getX(); x < pixel.getX() + pixel.getWidth(); ++x) { 
    1198                 for (int y = pixel.getY(); y < pixel.getY() + pixel.getHeight(); ++y) { 
    1199                     if (wantFitted(x, y)) { 
    1200                         // (flip vertically) 
    1201                         dataColorizer.setData(firstTime, x, height - y - 1 , lifetime); 
    1202                         firstTime = false; 
    1203                     } 
    1204                 } 
    1205             } 
    1206         } 
    1207         dataColorizer.update(); 
    1208     } 
    1209  
    1210     /** 
    1211      * Checks criterion for whether this pixel needs to get fitted or drawn. 
    1212      * 
    1213      * @param x 
    1214      * @param y 
    1215      * @return whether to include or ignore this pixel 
    1216      */ 
    1217     boolean wantFitted(int x, int y) { 
    1218         if (m_threshold <= m_grayscaleImageProcessor.getPixel(x, m_height - y - 1)) { 
    1219             if (m_grayscaleImageProcessor.getPixel(x, m_height - y - 1) > m_maxValue) { 
    1220                 m_maxValue = m_grayscaleImageProcessor.getPixel(x, m_height - y - 1); 
    1221                 m_maxX = x; 
    1222                 m_maxY = y; 
    1223             } 
    1224             return isIncluded(x,y); 
    1225         } 
    1226         else { 
    1227             return false; 
    1228         } 
    1229     } 
    1230  
    1231     /** 
    1232      * Checks whether a given pixel is included in ROIs.  If no ROIs are 
    1233      * selected then all pixels are included. 
    1234      * 
    1235      * @param x 
    1236      * @param y 
    1237      * @return whether or not included in ROIs 
    1238      */ 
    1239  
    1240     boolean isIncluded(int x, int y) { 
    1241         Roi[] rois = getRois(); 
    1242         if (0 < rois.length) { 
    1243             for (Roi roi: rois) { 
    1244                 if (roi.contains(x, y)) { 
    1245                     return true; 
    1246                 } 
    1247             } 
    1248             return false; 
    1249         } 
    1250         else { 
    1251             return true; 
    1252         } 
    1253     } 
    1254  
    1255     /** 
    1256      * Gets a list of ROIs (may be empty). 
    1257      * 
    1258      * @return array of ROIs. 
    1259      */ 
    1260     private Roi[] getRois() { 
    1261         Roi[] rois = {}; 
    1262         RoiManager manager = RoiManager.getInstance(); 
    1263         if (null != manager) { 
    1264             rois = manager.getRoisAsArray(); 
    1265         } 
    1266         return rois; 
    1267     } 
    1268  
    1269     /** 
    1270      * Colorizes a given lifetime value. 
    1271      * 
    1272      * Note this is much cruder than the DataColorizer that is 
    1273      * used in fitEachPixel. 
    1274      * 
    1275      * @param max 
    1276      * @param lifetime 
    1277      * @return 
    1278      */ 
    1279  
    1280      private Color lifetimeColorMap(double max, double lifetime) { 
    1281         Color returnColor = Color.BLACK; 
    1282         if (lifetime > 0.0) { 
    1283             if (lifetime < max/2.0) { 
    1284                 returnColor = interpolateColor(Color.BLUE, Color.GREEN, 2.0 * lifetime / max); 
    1285             } 
    1286             else if (lifetime < max) { 
    1287                 returnColor = interpolateColor(Color.GREEN, Color.RED, 2.0 * (lifetime - max / 2.0) / max); 
    1288             } 
    1289             else returnColor = Color.RED; 
    1290         } 
    1291         return returnColor; 
    1292     } 
    1293  
    1294      /** 
    1295       * Interpolates between two colors based on a blend factor. 
    1296       * 
    1297       * @param start color 
    1298       * @param end color 
    1299       * @param blend factor 
    1300       * @return interpolated color 
    1301       */ 
    1302     private Color interpolateColor(Color start, Color end, double blend) { 
    1303         int startRed   = start.getRed(); 
    1304         int startGreen = start.getGreen(); 
    1305         int startBlue  = start.getBlue(); 
    1306         int endRed   = end.getRed(); 
    1307         int endGreen = end.getGreen(); 
    1308         int endBlue  = end.getBlue(); 
    1309         int red   = interpolateColorComponent(startRed, endRed, blend); 
    1310         int green = interpolateColorComponent(startGreen, endGreen, blend); 
    1311         int blue  = interpolateColorComponent(startBlue, endBlue, blend); 
    1312         return new Color(red, green, blue); 
    1313     } 
    1314  
    1315     /** 
    1316      * Interpolates a single RGB component between two values based on 
    1317      * a blend factor. 
    1318      * 
    1319      * @param start component value 
    1320      * @param end component value 
    1321      * @param blend factor 
    1322      * @return interpolated component value 
    1323      */ 
    1324     private int interpolateColorComponent(int start, int end, double blend) { 
    1325         return (int)(blend * (end - start) + start); 
     1953        System.out.println("nanoseconds " + elapsed); 
    13261954    } 
    13271955 
Note: See TracChangeset for help on using the changeset viewer.