Ignore:
Timestamp:
03/16/12 20:01:59 (8 years ago)
Author:
aivar
Message:

SLIM Plugin: Working on Trac #674 Ensure TRI2 and SLIMPlugin results agree. Also fixed #675, #676, and #677.

Location:
trunk/projects/slim-plugin/src/main/java/loci/slim
Files:
6 edited
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/projects/slim-plugin/src/main/java/loci/slim/GrayScaleImage.java

    r7887 r7922  
    6565    private ISelectListener m_listener; 
    6666    private byte[] m_saveOutPixels[]; 
     67    private double m_minNonZeroPhotonCount; 
     68    private int[] m_brightestPoint; 
    6769 
    6870    public GrayScaleImage(Image<T> image) { 
     
    9294        int[] position = (channels > 1) ? new int[4] : new int[3]; 
    9395 
     96        m_minNonZeroPhotonCount = Double.MAX_VALUE; 
    9497        for (int c = 0; c < channels; ++c) { 
    9598            if (channels > 1) { 
     
    109112 
    110113                        cursor.setPosition(position); 
    111                         pixels[x][y] += ((ComplexType) cursor.getType()).getRealDouble(); 
     114                        double photonCount = ((ComplexType) cursor.getType()).getRealDouble(); 
     115                        pixels[x][y] += photonCount; 
     116                         
     117                        // keep track of minimum 
     118                        if (0.0 < photonCount && photonCount < m_minNonZeroPhotonCount) { 
     119                            m_minNonZeroPhotonCount = photonCount; 
     120                        } 
    112121                    } 
    113                     // keep track of maximum 
     122                    // keep track of maximum value and its coordinates 
    114123                    if (pixels[x][y] > maxPixel) { 
    115124                        maxPixel = pixels[x][y]; 
     125                        m_brightestPoint = new int[] { x , y }; 
    116126                    } 
    117127                } 
     
    133143        m_stackWindow = new MyStackWindow(imagePlus); 
    134144        m_stackWindow.setVisible(true); 
     145         
     146        System.out.println("minNonZeroPhotonCount is " + m_minNonZeroPhotonCount); 
    135147 
    136148        //System.out.println("Channel selector " + m_stackWindow.getChannelSelector()); 
     
    214226        return returnValue; 
    215227    } 
     228     
     229    @Override 
     230    public double getMinNonZeroPhotonCount() { 
     231        return m_minNonZeroPhotonCount; 
     232    } 
     233     
     234    @Override 
     235    public int[] getBrightestPoint() { 
     236        return m_brightestPoint; 
     237    } 
    216238} 
  • trunk/projects/slim-plugin/src/main/java/loci/slim/IGrayScaleImage.java

    r7677 r7922  
    8585     */ 
    8686    public float getZoomFactor(); 
     87     
     88    /** 
     89     * Gets the minimum, non-zero photon count encountered in the image. 
     90     *  
     91     * Usually 1.0, but sometimes its 10.0 and all photon counts are multiples 
     92     * of 10.0. 
     93     *  
     94     * @return  
     95     */ 
     96    public double getMinNonZeroPhotonCount(); 
     97 
     98    /** 
     99     * Gets the coordinates of the brightest point in the image. 
     100     *  
     101     * @return { x, y } 
     102     */ 
     103    public int[] getBrightestPoint(); 
    87104} 
  • trunk/projects/slim-plugin/src/main/java/loci/slim/SLIMProcessor.java

    r7915 r7922  
    3535package loci.slim; 
    3636 
    37 import loci.slim.heuristics.CursorHelper; 
     37import loci.slim.heuristics.CursorEstimator; 
    3838import ij.IJ; 
    3939import ij.ImagePlus; 
     
    4848import java.awt.Color; 
    4949import java.awt.Rectangle; 
     50import java.io.IOException; 
    5051import java.util.ArrayList; 
     52import java.util.Hashtable; 
    5153import java.util.List; 
    5254import java.util.prefs.Preferences; 
     
    6264import loci.curvefitter.MarkwardtCurveFitter; 
    6365import loci.curvefitter.SLIMCurveFitter; 
     66import loci.formats.FormatException; 
    6467import loci.formats.FormatTools; 
    6568import loci.formats.IFormatReader; 
     69import loci.formats.ImageReader; 
    6670import loci.slim.analysis.SLIMAnalysis; 
    6771import loci.slim.binning.SLIMBinning; 
    6872import loci.slim.colorizer.DataColorizer; 
    6973import loci.slim.colorizer.DataColorizer2; 
    70 import loci.slim.heuristics.CursorHelper; 
     74import loci.slim.heuristics.CursorEstimator; 
    7175import loci.slim.process.IProcessor; 
    7276import loci.slim.process.Threshold; 
     
    152156    private static final Character SUB_2  = '\u2082'; 
    153157    private static final Character SUB_3  = '\u2083'; 
     158     
     159    private IUserInterfacePanel m_uiPanel; 
    154160 
    155161    private Object m_synchFit = new Object(); 
     
    163169    private String m_file; 
    164170    private String m_path; 
    165  
    166     IFormatReader m_reader; 
     171    private Hashtable<String, Object> m_globalMetadata; 
    167172 
    168173    private Image<T> m_image; 
     
    183188    private int m_binIndex; 
    184189 
    185     private boolean m_little; 
    186     private int m_pixelType; 
    187     private int m_bpp; 
    188     private boolean m_floating; 
    189     private float m_timeRange; 
    190     private int m_minWave, m_waveStep; //, m_maxWave; 
     190    private double m_timeRange; 
     191    private double m_minNonZeroPhotonCount; 
    191192 
    192193    private FitRegion m_region; 
     
    199200    private ExcitationPanel m_excitationPanel = null; 
    200201    private IGrayScaleImage m_grayScaleImage; 
    201     // user sets these from the grayScalePanel 
     202    // user sets this from the grayScalePanel control 
    202203    private int m_channel; 
    203204    private boolean m_fitAllChannels; 
    204205 
    205     // current channel, x, y 
    206     private int m_xchannel; // channel to fit; -1 means fit all channels 
     206    // current x, y 
    207207    private int m_x; 
    208208    private int m_y; 
    209     private int m_xvisibleChannel; // channel being displayed; -1 means none 
    210209 
    211210    private double[] m_param = new double[7]; 
     
    289288                USE_TAU, m_analysis.getChoices(), m_binning.getChoices(), 
    290289                fittingCursorHelper); 
     290        m_uiPanel = uiPanel; //TODO almost got by having it just be a local variable 
    291291        uiPanel.setX(0); 
    292292        uiPanel.setY(0); 
     
    381381                    } 
    382382                } 
     383 
     384                /** 
     385                 * Estimates prompt and decay cursors. 
     386                 */ 
     387                public void estimateCursors() { 
     388                    double xInc = m_timeRange; 
     389                    double[] prompt = null; 
     390                    double[] decay = null; 
     391                    double chiSqTarget = m_uiPanel.getChiSquareTarget(); 
     392                    if (_fittingCursor.getHasPrompt()) { 
     393                        double[] results = CursorEstimator.estimateCursors 
     394                                (xInc, prompt, decay, chiSqTarget); 
     395                        double promptBaseline = results[CursorEstimator.PROMPT_BASELINE]; 
     396                        double promptStart    = results[CursorEstimator.PROMPT_START]; 
     397                        double promptStop     = results[CursorEstimator.PROMPT_STOP]; 
     398                        double transientStart = results[CursorEstimator.TRANSIENT_START]; 
     399                        double dataStart      = results[CursorEstimator.DATA_START]; 
     400                        double transientStop  = results[CursorEstimator.TRANSIENT_STOP]; 
     401                        _fittingCursor.suspendNotifications(true); 
     402                        _fittingCursor.setPromptBaselineValue(promptBaseline); 
     403                        _fittingCursor.setPromptStartValue   (promptStart); 
     404                        _fittingCursor.setPromptStopValue    (promptStop); 
     405                        _fittingCursor.setTransientStartValue(transientStart); 
     406                        _fittingCursor.setDataStartValue     (dataStart); 
     407                        _fittingCursor.suspendNotifications(false); 
     408                        _fittingCursor.setTransientStopValue (transientStop); 
     409                    } 
     410                    else { 
     411                        //TODO ARG cursors still has that confusion between double and int! 
     412                        /* 
     413                        double[] results = CursorEstimator.estimateDecayCursors 
     414                                (xInc, decay); 
     415                        double transientStart = results[CursorEstimator.TRANSIENT_START]; 
     416                        double dataStart      = results[CursorEstimator.DATA_START]; 
     417                        double transientStop  = results[CursorEstimator.TRANSIENT_STOP]; 
     418                        _fittingCursor.setTransientStartValue(transientStart); 
     419                        _fittingCursor.setDataStartValue     (dataStart); 
     420                        _fittingCursor.suspendNotifications(false); 
     421                        _fittingCursor.setTransientStopValue (transientStop);*/ 
     422                    } 
     423                } 
    383424            } 
    384425        ); 
     
    407448            } 
    408449        ); 
     450        // get a correction factor for photon counts 
     451        m_minNonZeroPhotonCount = m_grayScaleImage.getMinNonZeroPhotonCount(); 
     452 
     453        // what is the brightest point in the image? 
     454        int[] brightestPoint = m_grayScaleImage.getBrightestPoint(); 
     455        m_x = brightestPoint[0]; 
     456        m_y = brightestPoint[1]; 
     457        uiPanel.setX(m_x); 
     458        uiPanel.setY(m_y); 
    409459 
    410460        // set start and stop for now; will be updated if we load an excitation curvce 
    411461        updateDecayCursors(uiPanel); 
     462         
     463        // fit on the brightest pixel 
     464        getFitSettings(m_grayScaleImage, uiPanel, _fittingCursor); 
     465        fitPixel(uiPanel, _fittingCursor);  
    412466 
    413467        // processing loop; waits for UI panel input 
     
    456510     */ 
    457511    private void updateDecayCursors(IUserInterfacePanel uiPanel) { 
    458         double[] decay = getSummedDecay(); 
    459         int[] results = CursorHelper.estimateDecayCursors(m_timeRange, decay); 
    460         int transientStart = results[CursorHelper.TRANSIENT_START]; 
    461         int dataStart = results[CursorHelper.DATA_START]; 
    462         int transientStop = results[CursorHelper.TRANSIENT_STOP]; 
     512        // get selected channel 
     513        int channel = 0; 
     514        if (null != m_grayScaleImage) { 
     515            channel = m_grayScaleImage.getChannel(); 
     516        } 
     517        double[] decay = new double[m_bins]; 
     518        for (int b = 0; b < m_bins; ++b) { 
     519            decay[b] = getData(m_cursor, channel, m_x, m_y, b); 
     520        } 
     521        int[] results = CursorEstimator.estimateDecayCursors(m_timeRange, decay); 
     522        int transientStart = results[CursorEstimator.TRANSIENT_START]; 
     523        int dataStart = results[CursorEstimator.DATA_START]; 
     524        int transientStop = results[CursorEstimator.TRANSIENT_STOP]; 
    463525 
    464526        // want to batch all of the fitting cursor notifications to listeners 
     
    469531        _fittingCursor.setTransientStopBin(transientStop); 
    470532    } 
    471      
     533 
     534    /** 
     535     * This method sums the decay for all channels of all pixels. 
     536     *  
     537     * @return  
     538     */ 
    472539    private double[] getSummedDecay() { 
    473540        double[] decay = new double[m_bins]; 
     
    494561            } 
    495562 
    496             // sum selected channel 
     563            // get selected channel 
    497564            int channel = 0; 
    498565            if (null != m_grayScaleImage) { 
     
    500567            } 
    501568            double[] decay = new double[m_bins]; 
    502             for (int i = 0; i < decay.length; ++i) { 
    503                 decay[i] = 0.0; 
    504             } 
    505             for (int y = 0; y < m_height; ++y) { 
    506                 for (int x = 0; x < m_width; ++x) { 
    507                     for (int b = 0; b < m_bins; ++b) { 
    508                         decay[b] += getData(m_cursor, channel, x, y, b); 
    509                     } 
    510                 } 
    511             } 
    512  
    513             double[] results = CursorHelper.estimateCursors(m_timeRange, excitation.getValues(), decay); 
     569            for (int b = 0; b < m_bins; ++b) { 
     570                decay[b] = getData(m_cursor, channel, m_x, m_y, b); 
     571            } 
     572 
     573            double chiSqTarget = uiPanel.getChiSquareTarget(); 
     574            double[] results = CursorEstimator.estimateCursors 
     575                    (m_timeRange, excitation.getValues(), decay, chiSqTarget); 
    514576             
    515577            // want all the fitting cursor listeners to get everything at once 
    516578            _fittingCursor.suspendNotifications(true); 
    517             _fittingCursor.setPromptStartBin   ((int) results[CursorHelper.PROMPT_START]); 
    518             _fittingCursor.setPromptStopBin    ((int) results[CursorHelper.PROMPT_STOP]); 
    519             _fittingCursor.setPromptBaselineValue    (results[CursorHelper.PROMPT_BASELINE]); 
    520             _fittingCursor.setTransientStartBin((int) results[CursorHelper.TRANSIENT_START]); 
    521             _fittingCursor.setDataStartBin     ((int) results[CursorHelper.DATA_START]); 
     579            _fittingCursor.setPromptStartBin   ((int) results[CursorEstimator.PROMPT_START]); 
     580            _fittingCursor.setPromptStopBin    ((int) results[CursorEstimator.PROMPT_STOP]); 
     581            _fittingCursor.setPromptBaselineValue    (results[CursorEstimator.PROMPT_BASELINE]); 
     582            _fittingCursor.setTransientStartBin((int) results[CursorEstimator.TRANSIENT_START]); 
     583            _fittingCursor.setDataStartBin     ((int) results[CursorEstimator.DATA_START]); 
    522584            _fittingCursor.suspendNotifications(false); 
    523             _fittingCursor.setTransientStopBin ((int) results[CursorHelper.TRANSIENT_STOP]); 
    524  
    525             m_excitationPanel = new ExcitationPanel(excitation, _fittingCursor); 
     585            _fittingCursor.setTransientStopBin ((int) results[CursorEstimator.TRANSIENT_STOP]); 
     586 
     587            m_excitationPanel = new ExcitationPanel(excitation, _fittingCursor); //TODO ARG excitation cursor change refit problem here; get new values before excitation ready for refit 
    526588 
    527589            success = true; 
     
    550612 
    551613    /** 
    552      * Prompts for a .sdt file. 
     614     * Prompts for a FLIM file. 
    553615     * 
    554616     * @param defaultFile 
     
    557619    private boolean showFileDialog(String[] defaultPathAndFile) { 
    558620        OpenDialog dialog = new OpenDialog("Load Data", m_path, m_file); 
    559         //if (dialog.wasCanceled()) return false; 
    560621        m_path = dialog.getDirectory(); 
    561622        m_file = dialog.getFileName(); 
     
    581642            System.out.println("imageOpener returned null image"); 
    582643        } 
     644 
     645        // Open the file again, just to get metadata 
     646        ImageReader imageReader = new ImageReader(); 
     647        try { 
     648            imageReader.setId(path + file); 
     649            m_globalMetadata = imageReader.getGlobalMetadata(); 
     650            imageReader.close(); 
     651        } 
     652        catch (IOException e) {        
     653        } 
     654        catch (FormatException e) {  
     655        } 
     656         
    583657        return image; 
    584658    } 
     
    615689        System.out.println("width " + m_width + " height " + m_height + " timeBins " + m_bins + " channels " + m_channels); 
    616690        m_cursor = image.createLocalizableByDimCursor(); 
    617         /* 
    618         int index = 0; 
    619         xIndex = index++; 
    620         yIndex = index++; 
    621         lifetimeIndex = index++; 
    622         if (m_channels > 1) { 
    623             channelIndex = index; 
    624         } 
    625         else { 
    626             channelIndex = null; 
    627         } 
    628  
    629  
    630         m_data = new int[m_channels][m_height][m_width][m_timeBins]; 
    631         final LocalizableByDimCursor<T> cursor = image.createLocalizableByDimCursor(); 
    632         int x, y, bin, channel; 
    633         for (channel = 0; channel < m_channels; ++channel) { 
    634             if (null != channelIndex) { 
    635                 dimensions[channelIndex] = channel; 
    636             } 
    637             for (y = 0; y < m_height; ++y) { 
    638                 dimensions[yIndex] = y; 
    639                 for (x = 0; x < m_width; ++x) { 
    640                     dimensions[xIndex] = x; 
    641                     for (bin = 0; bin < m_timeBins; ++bin) { 
    642                         dimensions[lifetimeIndex] = bin; 
    643                         cursor.moveTo(dimensions); 
    644                         m_data[channel][y][x][bin] = (int) cursor.getType().getRealFloat(); 
    645                         //TODO don't do this, screws up low photon count images...  m_data[channel][y][x][bin] /= 10.0f; //TODO in accordance with TRI2; HOLY COW!!!  ALSO int vs float??? why? 
    646                     } 
    647                 } 
    648             } 
    649         } 
    650         cursor.close();*/ 
    651         // print out some useful information about the image 
    652         //System.out.println(image); 
    653         //final Cursor<T> cursor = image.createCursor(); 
    654         //cursor.fwd(); 
    655         //System.out.println("\tType = " + cursor.getType().getClass().getName()); 
    656         //cursor.close(); 
    657  
    658         //TODO from a former version: 
    659      //TODO won't compile with my version of the jar: Number timeBase = (Number) m_reader.getGlobalMetadata().get("time base"); 
    660      //TODO fix: 
    661          //   Number timeBase = null; 
    662          //   m_timeRange = timeBase == null ? Float.NaN : timeBase.floatValue(); 
    663          ////   if (m_timeRange != m_timeRange) m_timeRange = 10.0f; 
    664          //   m_minWave = 400; 
    665          //   m_waveStep = 10; 
    666             //m_binRadius = 3; 
    667  
    668  
    669         // patch things up 
    670         m_timeRange = 10.0f / 64.0f; //TODO ARG 2/13/12 was: 10.0f / 64.0f; //TODO ARG this patches things up in accord with TRI2 for brian/gpl1.sdt; very odd value here NOTE this was with photon counts all divided by 10.0f above! might have cancelled out. 
    671                    //TODO the patch above worked when I was also dividing the photon count by 10.0f!!  should be 1/64? 
    672         m_minWave = 400; 
    673         m_waveStep = 10; 
    674  
     691         
     692        m_timeRange = 10.0f; 
     693        if (null != m_globalMetadata) { 
     694            Number timeBase = (Number) m_globalMetadata.get("time base"); 
     695            if (null != timeBase) { 
     696                m_timeRange = timeBase.floatValue(); 
     697            } 
     698        } 
     699        m_timeRange /= m_bins; 
     700 
     701        //TODO ARG debugging 
     702        if (null != m_globalMetadata) { 
     703            java.util.Set<String> keySet = m_globalMetadata.keySet(); 
     704            for (String key : keySet) { 
     705                System.out.println("key: " + key + " value:" + m_globalMetadata.get(key)); 
     706            }  
     707        } 
    675708        return true; 
    676709    } 
     
    10521085                // these lines give TRI2 compatible fit results 
    10531086                int estimateStartIndex = 
    1054                         CursorHelper.getEstimateStartIndex 
     1087                        CursorEstimator.getEstimateStartIndex 
    10551088                            (yCount, m_startBin, m_stopBin); 
    10561089                curveFitData.setTransEstimateStartIndex(estimateStartIndex); 
     
    11311164                    // these lines give TRI2 compatible fit results 
    11321165                    int estimateStartIndex = 
    1133                             CursorHelper.getEstimateStartIndex 
     1166                            CursorEstimator.getEstimateStartIndex 
    11341167                                (yCount, m_startBin, m_stopBin); 
    11351168                    curveFitData.setTransEstimateStartIndex(estimateStartIndex); 
     
    12511284            yCount = new double[m_bins]; 
    12521285            for (int b = 0; b < m_bins; ++b) { 
    1253                 yCount[b] = getData(m_cursor, channel, x, y, b) / 10.0; //TODO ARG 2/13/12 lowest value was 10.0, s/b 1.0 
     1286                yCount[b] = getData(m_cursor, channel, x, y, b); 
    12541287            } 
    12551288            int photons = 0; 
     
    12581291            } 
    12591292            System.out.println("PHOTONS " + photons); 
     1293 
     1294//TODO ARG 3/12             
     1295int transStartIndex = _fittingCursor.getTransientStartBin(); 
     1296int dataStartIndex = _fittingCursor.getDataStartBin(); 
     1297int transStopIndex = _fittingCursor.getTransientStopBin(); 
     1298             
     1299           
     1300             
     1301             
     1302             
     1303             
     1304             
    12601305            curveFitData.setYCount(yCount); 
    1261             curveFitData.setTransStartIndex(0); 
    1262             curveFitData.setTransFitStartIndex(m_startBin); 
    1263             curveFitData.setTransEndIndex(m_stopBin); 
     1306            curveFitData.setTransStartIndex(transStartIndex); //TODO ARG 0); 
     1307            curveFitData.setTransFitStartIndex(dataStartIndex); //TODO ARG m_startBin); 
     1308            curveFitData.setTransEndIndex(transStopIndex); //TODO ARG m_stopBin); 
    12641309            System.out.println("uiPanel.getFunction is " + uiPanel.getAlgorithm() + " SLIMCURVE_RLD_LMA is " + FitAlgorithm.SLIMCURVE_RLD_LMA); 
    12651310            if (FitAlgorithm.SLIMCURVE_RLD_LMA.equals(uiPanel.getAlgorithm())) { 
    12661311                // these lines give TRI2 compatible fit results 
    12671312                int estimateStartIndex = 
    1268                         CursorHelper.getEstimateStartIndex 
     1313                        CursorEstimator.getEstimateStartIndex 
    12691314                            (yCount, m_startBin, m_stopBin); 
    12701315                System.out.append("m_startBin was " + m_startBin + " now estimageStartIndex is " + estimateStartIndex); 
     
    13281373            cursor.getType().set(Double.NaN); 
    13291374        } 
    1330     } 
    1331  
    1332     static int s_avgIndex; 
    1333     static ArrayList<Long> s_list = new ArrayList<Long>(); 
    1334  
    1335     private void showRunningAverage(long elapsed) { 
    1336         s_list.add(elapsed); 
    1337         long total = 0; 
    1338         for (long time : s_list) { 
    1339             total += time; 
    1340         } 
    1341         total /= s_list.size(); 
    1342         System.out.println("average " + total + " after " + s_list.size() + " trials"); 
    13431375    } 
    13441376 
     
    14181450        } 
    14191451        cursor.moveTo(dim); 
    1420         return cursor.getType().getRealFloat(); 
     1452        return cursor.getType().getRealFloat() / m_minNonZeroPhotonCount; 
    14211453    } 
    14221454 
     
    14851517        m_fittedImage = null; 
    14861518        m_fittedParameterCount = 0; 
    1487     } 
    1488  
    1489     /** 
    1490      * Visibly processes a batch of pixels. 
    1491      * 
    1492      * @param dataColorizer automatically sets colorization range and updates colorized image 
    1493      * @param height passed in to fix a vertical orientation problem 
    1494      * @channel current channel 
    1495      * @param data list of data corresponding to pixels to be fitted 
    1496      * @param pixels parallel list of rectangles with which to draw the fitted pixel 
    1497      */ 
    1498     void colorizePixels(DataColorizer2 dataColorizer, int channel, ICurveFitData data[], ChunkyPixel pixels[]) { 
    1499  
    1500         // draw as you go; 'chunky' pixels get smaller as the overall fit progresses 
    1501         for (int i = 0; i < pixels.length; ++i) { 
    1502             ChunkyPixel pixel = pixels[i]; 
    1503             //TODO tau is 3, 1 is C double lifetime = data[i].getParams()[1]; 
    1504             double lifetime = data[i].getParams()[3]; 
    1505  
    1506             //TODO quick fix 
    1507             if (lifetime < 0.0) { 
    1508                 System.out.println("negative lifetime " + lifetime + " at " + pixel.getX() + " " + pixel.getY()); 
    1509                 return; 
    1510             } 
    1511  
    1512             //TODO debugging: 
    1513             //if (lifetime > 2 * m_param[1]) { 
    1514             //    System.out.println("BAD FIT??? x " + pixel.getX() + " y " + pixel.getY() + " fitted lifetime " + lifetime); 
    1515             //} 
    1516  
    1517             //TODO BUG: 
    1518             // With the table as is, you can get 
    1519             //   x   y   w   h 
    1520             //   12  15  2   1 
    1521             //   14  15  2   1 
    1522             // all within the same drawing cycle. 
    1523             // So it looks like a 4x1 slice gets drawn (it 
    1524             // is composed of two adjacent 2x1 slices with 
    1525             // potentially two different colors). 
    1526             //if (pixel.getWidth() == 2) { 
    1527             //    System.out.println("x " + pixel.getX() + " y " + pixel.getY() + " w " + pixel.getWidth() + " h " + pixel.getHeight()); 
    1528             //} 
    1529             //System.out.println("w " + pixel.getWidth() + " h " + pixel.getHeight()); 
    1530             //System.out.println("lifetime is " + lifetime); 
    1531             //Color color = lifetimeColorMap(MAXIMUM_LIFETIME, lifetime); 
    1532             //imageProcessor.setColor(color); 
    1533             boolean firstTime = true; 
    1534             for (int x = pixel.getX(); x < pixel.getX() + pixel.getWidth(); ++x) { 
    1535                 for (int y = pixel.getY(); y < pixel.getY() + pixel.getHeight(); ++y) { 
    1536                     if (wantFitted(channel, x, y)) { 
    1537                         dataColorizer.setData(firstTime, x, y , lifetime); 
    1538                         firstTime = false; 
    1539                     } 
    1540                 } 
    1541             } 
    1542         } 
    1543         dataColorizer.update(); 
    1544     } 
    1545      
    1546     void colorizePixelsII(DataColorizer2 dataColorizer, int channel, double[] lifetime, ChunkyPixel pixels[]) { 
    1547  
    1548         // draw as you go; 'chunky' pixels get smaller as the overall fit progresses 
    1549         for (int i = 0; i < pixels.length; ++i) { 
    1550             ChunkyPixel pixel = pixels[i]; 
    1551             //TODO tau is 3, 1 is C double lifetime = data[i].getParams()[1]; 
    1552  
    1553  
    1554             //TODO quick fix 
    1555             if (lifetime[i] < 0.0) { 
    1556                 System.out.println("negative lifetime " + lifetime + " at " + pixel.getX() + " " + pixel.getY()); 
    1557                 return; 
    1558             } 
    1559  
    1560             //TODO debugging: 
    1561             //if (lifetime > 2 * m_param[1]) { 
    1562             //    System.out.println("BAD FIT??? x " + pixel.getX() + " y " + pixel.getY() + " fitted lifetime " + lifetime); 
    1563             //} 
    1564  
    1565             //TODO BUG: 
    1566             // With the table as is, you can get 
    1567             //   x   y   w   h 
    1568             //   12  15  2   1 
    1569             //   14  15  2   1 
    1570             // all within the same drawing cycle. 
    1571             // So it looks like a 4x1 slice gets drawn (it 
    1572             // is composed of two adjacent 2x1 slices with 
    1573             // potentially two different colors). 
    1574             //if (pixel.getWidth() == 2) { 
    1575             //    System.out.println("x " + pixel.getX() + " y " + pixel.getY() + " w " + pixel.getWidth() + " h " + pixel.getHeight()); 
    1576             //} 
    1577             //System.out.println("w " + pixel.getWidth() + " h " + pixel.getHeight()); 
    1578             //System.out.println("lifetime is " + lifetime); 
    1579             //Color color = lifetimeColorMap(MAXIMUM_LIFETIME, lifetime); 
    1580             //imageProcessor.setColor(color); 
    1581             boolean firstTime = true; 
    1582             for (int x = pixel.getX(); x < pixel.getX() + pixel.getWidth(); ++x) { 
    1583                 for (int y = pixel.getY(); y < pixel.getY() + pixel.getHeight(); ++y) { 
    1584                     if (wantFitted(channel, x, y)) { 
    1585                         dataColorizer.setData(firstTime, x, y , lifetime[i]); 
    1586                         firstTime = false; 
    1587                     } 
    1588                 } 
    1589             } 
    1590         } 
    1591         dataColorizer.update(); 
    1592     } 
    1593      
    1594     /** 
    1595      * Checks criterion for whether this pixel needs to get fitted or drawn. 
    1596      * 
    1597      * @param channel 
    1598      * @param x 
    1599      * @param y 
    1600      * @return whether to include or ignore this pixel 
    1601      */ 
    1602     boolean wantFitted(int channel, int x, int y) { 
    1603         return (aboveThreshold(channel, x, y) & isInROIs(x, y)); 
    1604     } 
    1605  
    1606     /** 
    1607      * Checks whether a given pixel is above threshold photon count value. 
    1608      * 
    1609      * @param channel 
    1610      * @param x 
    1611      * @param y 
    1612      * @return whether above threshold 
    1613      */ 
    1614     boolean aboveThreshold(int channel, int x, int y) { 
    1615         return (m_threshold <= m_grayScaleImage.getPixel(channel, x, y)); 
    16161519    } 
    16171520 
     
    19001803            if (refit) { 
    19011804                System.out.println("REFIT"); 
     1805                fitPixel(m_uiPanel, _fittingCursor); 
    19021806            } 
    19031807        } 
  • trunk/projects/slim-plugin/src/main/java/loci/slim/fitting/callable/FittingEngineCallable.java

    r7892 r7922  
    3939import loci.slim.fitting.params.IGlobalFitParams; 
    4040import loci.slim.fitting.params.IFitResults; 
    41 import loci.slim.heuristics.CursorHelper; 
     41import loci.slim.heuristics.CursorEstimator; 
    4242 
    4343import loci.curvefitter.CurveFitData; 
     
    8989                // these lines give TRI2 compatible fit results 
    9090                int estimateStartIndex = 
    91                         CursorHelper.getEstimateStartIndex 
     91                        CursorEstimator.getEstimateStartIndex 
    9292                            (_localParams.getY(), _localParams.getFitStart(), _localParams.getFitStop()); 
    9393                curveFitData.setTransEstimateStartIndex(estimateStartIndex); 
  • trunk/projects/slim-plugin/src/main/java/loci/slim/heuristics/CursorEstimator.java

    r7910 r7922  
    5151 * @author aivar 
    5252 */ 
    53 public class CursorHelper { 
     53public class CursorEstimator { 
    5454    public static final int PROMPT_START        = 0; 
    5555    public static final int PROMPT_STOP         = 1; 
     
    5959    public static final int TRANSIENT_STOP      = 5; 
    6060    private static final int ATTEMPTS = 10; 
     61    // This is the value I get for unitialized floats in Visual Studio 2008; 
     62    // used to debug & compare SLIM Plugin and TRI2 in marginal situations. 
     63    private static final double C_UNITIALIZED = -1.0737418E8; 
    6164 
    6265    public static double[] estimateExcitationCursors(double[] excitation) { 
     
    131134    } 
    132135 
     136    /** 
     137     * Provides estimation of decay cursors. 
     138     *  
     139     * Note that TRI2 does not support this.  There is no "Estimate Cursors" 
     140     * button if you don't have a prompt.  TRI2 saves and restores the decay 
     141     * cursor values even if you switch to a new image. 
     142     *  
     143     * @param xInc 
     144     * @param decay 
     145     * @return  
     146     */ 
    133147    public static int[] estimateDecayCursors(double xInc, double[] decay) { 
    134148        int maxIndex = findMax(decay); 
     
    158172    } 
    159173 
    160     public static double[] estimateCursors(double xInc, double[] prompt, double[] decay) { 
     174    public static double[] estimateCursors(double xInc, double[] prompt, 
     175            double[] decay, double chiSqTarget) { 
    161176        double[] returnValue = new double[6]; 
    162177        double baseline; 
     
    276291 
    277292        System.out.println("prompt " + prompt.length + " decay " + decay.length); 
     293         
     294        double[] adjustedPrompt = adjustPrompt(prompt, startp*xInc, endp*xInc, baseline, xInc); 
    278295 
    279296        for (i = 0; i < 2 * ATTEMPTS + 1; ++i, ++transStartIndex) { 
     
    282299            System.out.println("transStartIndex " + transStartIndex + " transFitStartIndex " + transFitStartIndex + " transEndIndex " + transEndIndex); 
    283300 
    284             int fitStart = transFitStartIndex - transStartIndex; 
     301            int fitStart = transFitStartIndex - transStartIndex; // e.g. always zero 
    285302            int fitStop = transEndIndex - transStartIndex; 
    286303            int nData = transEndIndex - transStartIndex; 
     
    288305 
    289306            CurveFitData curveFitData = new CurveFitData(); 
     307            param[1] = param[2] = param[3] = C_UNITIALIZED;               
    290308            curveFitData.setParams(param); //TODO param has random values!! 
    291             curveFitData.setYCount(decay); 
     309                         
     310            double[] adjustedDecay = adjustDecay(decay, transStartIndex); 
     311            curveFitData.setYCount(adjustedDecay); 
    292312            curveFitData.setTransStartIndex(0); 
    293313            curveFitData.setTransFitStartIndex(fitStart); 
    294             curveFitData.setTransEstimateStartIndex(fitStart); 
     314            curveFitData.setTransEstimateStartIndex(fitStart); //TODO ARG this shit has to go; was an early way to handle TRI2 quirkiness; w/b better to call quirky estimator routines from SLIMCurveFitter rather than having these oddball variables to kludge in quirkiness 
    295315            curveFitData.setTransEndIndex(fitStop);             
    296    
     316            curveFitData.setChiSquareTarget(chiSqTarget); 
    297317            curveFitData.setSig(null); 
    298318            curveFitData.setYFitted(yFitted); 
    299319            CurveFitData[] data = new CurveFitData[] { curveFitData }; 
    300  
     320             
    301321            SLIMCurveFitter curveFitter = new SLIMCurveFitter(); 
    302             curveFitter.setFitAlgorithm(FitAlgorithm.SLIMCURVE_RLD_LMA); 
     322            curveFitter.setFitAlgorithm(FitAlgorithm.SLIMCURVE_RLD); 
    303323            curveFitter.setXInc(xInc); 
    304324            curveFitter.setFree(free); 
    305             curveFitter.setInstrumentResponse(decay); 
    306             curveFitter.setNoiseModel(NoiseModel.POISSON_DATA); 
    307  
     325            curveFitter.setInstrumentResponse(adjustedPrompt); 
     326            curveFitter.setNoiseModel(NoiseModel.POISSON_FIT);  
     327             
    308328            int ret = curveFitter.fitData(data); 
     329             
     330            if (ret < 0) { 
     331                param[1] = 0.0; 
     332                int j = findMax(decay, transFitStartIndex, transEndIndex); 
     333                param[2] = decay[j]; 
     334                param[3] = 2.0; 
     335            } 
     336             
     337            System.out.println("i " + i + " Z " + param[1] + " A " + param[2] + " T " + param[3]); 
     338             
     339            curveFitter.setFitAlgorithm(FitAlgorithm.SLIMCURVE_LMA); 
     340 
     341            ret = curveFitter.fitData(data); 
    309342 
    310343            if (ret >= 0) { 
    311344                System.out.println("for start " + fitStart + " stop " + fitStop + " chiSq is " + data[0].getChiSquare()); 
    312                 chiSqTable[i] = data[0].getChiSquare(); 
     345                chiSqTable[i] = data[0].getParams()[0]; //TODO ARG s/b same or better yet not kept in two places: data[0].getChiSquare(); 
    313346            } 
    314347            else { 
     
    320353        // "Find the minimum chisq in this range" 
    321354        index = findMin(chiSqTable, 2 * ATTEMPTS + 1); 
     355        System.out.println("min chisq index is " + index + " value " + chiSqTable[index]); 
     356         
    322357        if (chiSqTable[index] > 9e9f) {  // "no luck here..." 
    323358            System.out.println("no luck here return"); 
     
    351386        returnValue[TRANSIENT_STOP]  = transEndIndex; 
    352387        return returnValue; 
     388    } 
     389 
     390    /** 
     391     * Based on TRI2 TRCursor.c UpdatePrompt 
     392     *  
     393     * @param prompt 
     394     * @param start 
     395     * @param stop 
     396     * @param baseline 
     397     * @param inc 
     398     * @return  
     399     */ 
     400    private static double[] adjustPrompt(double[] prompt, double start, double stop, 
     401            double baseline, double inc) 
     402    { 
     403        double[] adjusted = null; 
     404        int startIndex = (int) Math.ceil(start / inc); 
     405        int stopIndex = (int) Math.floor(stop / inc) + 1; 
     406        System.out.println("stop is " + stop + " stopIndex " + stopIndex); 
     407        int length = stopIndex - startIndex; 
     408        if (length <= 0) { 
     409            return adjusted; 
     410        } 
     411        double scaling = 0.0; 
     412        for (int i = startIndex; i < stopIndex; ++i) { 
     413            if (i < prompt.length) { 
     414                scaling += prompt[i]; 
     415            } 
     416        } 
     417        if (0.0 == scaling) { 
     418            return adjusted; 
     419        } 
     420        adjusted = new double[length]; 
     421        for (int i = startIndex; i < stopIndex; ++i) { 
     422            adjusted[i - startIndex] = (prompt[i] - baseline) / scaling; 
     423        } 
     424        System.out.println("adjusted " + adjusted[0] + " " + adjusted[1] + " " + adjusted[2]); 
     425        return adjusted; 
     426    } 
     427     
     428    private static double[] adjustDecay(double[] decay, int startIndex) { 
     429        int size = decay.length - startIndex; 
     430        double[] adjusted = new double[size]; 
     431        for (int i = 0; i < size; ++i) { 
     432            adjusted[i] = decay[i + startIndex]; 
     433        } 
     434        return adjusted; 
    353435    } 
    354436     
     
    427509        return new double[] { z, a, t }; 
    428510    } 
     511  
     512    /** 
     513     * Convert time-based value to a bin number. 
     514     * 
     515     * Based on TRI2.  Note that 'valueToBin' and 'binToValue' won't round-trip. 
     516     * 
     517     * @param upper 
     518     * @param value 
     519     * @param inc 
     520     * @param max 
     521     * @return  
     522     */ 
     523    public static int valueToBin(boolean upper, double value, double inc, 
     524            int max) 
     525    { 
     526        int intValue = 0; 
     527        if (upper) { 
     528            intValue = (int) Math.ceil(value / inc) + 1; 
     529        } 
     530        else { 
     531            intValue = (int) Math.floor(value / inc); 
     532        } 
     533        // constrain within limits 
     534        if (intValue < 0) { 
     535            intValue = 0; 
     536        } 
     537        if (intValue > max) { 
     538            intValue = max; 
     539        } 
     540        return intValue; 
     541    } 
     542 
     543    /** 
     544     * Convert bin number to time-based value. 
     545     *  
     546     * Based on TRI2.  Note that 'binToValue' and 'valueToBin' won't round-trip. 
     547     *  
     548     * The 'upper' and 'max' parameters are not utilized in this implementation. 
     549     *  
     550     * @param upper 
     551     * @param bin 
     552     * @param inc 
     553     * @param max 
     554     * @return  
     555     */ 
     556    public static double binToValue(boolean upper, int bin, double inc, 
     557            double max) { 
     558        return bin * inc; 
     559    } 
    429560 
    430561    private static int findMax(double[] values) { 
  • trunk/projects/slim-plugin/src/main/java/loci/slim/ui/IUserInterfacePanelListener.java

    r7804 r7922  
    7171 
    7272    /** 
    73      * Creates an excitation curve from currrent X, Y and saves to file. 
     73     * Creates an excitation curve from current X, Y and saves to file. 
    7474     * 
    7575     * @param fileName 
     
    8080    /** 
    8181     * Cancels the current excitation curve, if any. 
    82      * 
    8382     */ 
    8483    public void cancelExcitation(); 
     84 
     85    /** 
     86     * Estimates the prompt and decay cursors. 
     87     */ 
     88    public void estimateCursors(); 
    8589} 
  • trunk/projects/slim-plugin/src/main/java/loci/slim/ui/UserInterfacePanel.java

    r7915 r7922  
    6969 
    7070import ij.gui.GenericDialog; 
     71import ij.io.OpenDialog; 
     72import ij.io.SaveDialog; 
    7173 
    7274import loci.curvefitter.ICurveFitter.FitAlgorithm; 
     
    657659                    } 
    658660                    else if (EXCITATION_FILE.equals(selectedItem)) { 
    659                         String fileName = getFileName("Load Excitation File", ""); 
    660                         if (null != fileName && null != m_listener) { 
     661                        OpenDialog dialog = new OpenDialog("Load Excitation File", ""); 
     662                        String fileName = dialog.getDirectory() + dialog.getFileName(); 
     663                        System.out.println("filename is >" + fileName + "<"); 
     664                        if (null != fileName && !fileName.equals("") && null != m_listener) { 
    661665                            isExcitationLoaded = m_listener.loadExcitation(fileName); 
    662666                        } 
    663667                    } 
    664668                    else if (EXCITATION_CREATE.equals(selectedItem)) { 
    665                         String fileName = getFileName("Save Excitation File", ""); 
    666                         if (null != fileName && null != m_listener) { 
     669                        SaveDialog dialog = new SaveDialog("Save Excitation File", "", ""); 
     670                        String fileName = dialog.getDirectory() + dialog.getFileName(); 
     671                        System.out.println("filename is >" + fileName + "<"); 
     672                        if (null != fileName && !fileName.equals("") && null != m_listener) { 
    667673                            isExcitationLoaded = m_listener.createExcitation(fileName); 
    668674                        } 
     
    690696        cursorPanel.add(dummyLabel); 
    691697        m_estimateCursorsButton = new JButton("Estimate Cursors"); 
     698        m_estimateCursorsButton.addActionListener( 
     699            new ActionListener() { 
     700                public void actionPerformed(ActionEvent e) { 
     701                    if (null != m_listener) { 
     702                        m_listener.estimateCursors(); 
     703                    } 
     704                } 
     705            } 
     706        ); 
    692707        cursorPanel.add(m_estimateCursorsButton); 
    693708 
     
    17751790        m_startParam4.setEnabled(enable); 
    17761791    } 
    1777      
    1778     private String getFileName(String title, String defaultFileName) { 
    1779         GenericDialog dialog = new GenericDialog(title); 
    1780         //TODO works with GenericDialogPlus, dialog.addFileField("File:", defaultFile, 24); 
    1781         dialog.addStringField("File", defaultFileName); 
    1782         dialog.showDialog(); 
    1783         if (dialog.wasCanceled()) { 
    1784             return null; 
    1785         } 
    1786  
    1787         return dialog.getNextString(); 
     1792//        OpenDialog dialog = new OpenDialog("Load Data", m_path, m_file);     
     1793    private String getFileName(String title) { 
     1794        OpenDialog dialog = new OpenDialog(title, ""); 
     1795        return dialog.getDirectory() + dialog.getFileName(); 
    17881796    } 
    17891797} 
Note: See TracChangeset for help on using the changeset viewer.