View Javadoc
1   package com.github.celldynamics.quimp.plugin.binaryseg;
2   
3   import java.awt.Choice;
4   import java.awt.Dimension;
5   import java.awt.event.ActionListener;
6   import java.awt.event.ItemListener;
7   import java.awt.event.WindowAdapter;
8   import java.awt.event.WindowEvent;
9   import java.awt.event.WindowFocusListener;
10  
11  import javax.swing.JButton;
12  
13  import org.slf4j.Logger;
14  import org.slf4j.LoggerFactory;
15  
16  import com.github.celldynamics.quimp.BOA_;
17  import com.github.celldynamics.quimp.plugin.ParamList;
18  import com.github.celldynamics.quimp.plugin.utils.QWindowBuilder;
19  
20  import ij.WindowManager;
21  
22  /**
23   * Show UI for segmentation from masks and run it.
24   * 
25   * <p>Modifies provided Nest reference on Apply. Update BOA screen on Apply button.
26   * 
27   * <p>This is front end of {@link BinarySegmentation} used in BOA.
28   * 
29   * @author p.baniukiewicz
30   * @see com.github.celldynamics.quimp.plugin.utils.QWindowBuilder
31   * @see BinarySegmentation_
32   */
33  public class BinarySegmentationView extends QWindowBuilder {
34  
35    // these fields code names of UI elements are are related to BinarySegmentationOptions#options
36    static final String NAME = "name";
37    static final String RESTORE_SNAKE = "Restore_Snake";
38    static final String CLEAR_NEST = "Clear_nest";
39    static final String SMOOTHING2 = "smoothing";
40    static final String STEP2 = "step";
41    static final String SELECT_MASK = "select_mask";
42    static final String SELECT_ORIGINAL_IMAGE = "select_original";
43    static final String LOAD_MASK = "load_mask";
44    // this is not part of UI, just store name for BOA (only ParamList by getPluginConfig() is stored
45    // in QCONF)
46    static final String LOADED_FILE = "loaded_file";
47  
48    /**
49     * The Constant LOGGER.
50     */
51    static final Logger LOGGER = LoggerFactory.getLogger(BinarySegmentationView.class.getName());
52  
53    // default parameters
54    private int step = 1; // discretization step
55    private boolean smoothing = false; // use smoothing?
56    private boolean clearnest = true; // clear nest before adding next outline
57    private boolean restoreFields = true; // if true internal Snake fields will be restored
58  
59    private ParamList uiDefinition; // window definition
60  
61    /**
62     * Construct object.
63     * 
64     * @see com.github.celldynamics.quimp.plugin.utils.QWindowBuilder
65     */
66    public BinarySegmentationView() {
67      // define window controls (selecter filled in buildWindow
68      uiDefinition = new ParamList(); // will hold ui definitions
69      uiDefinition.put(NAME, "BinarySegmentation"); // name of window
70      uiDefinition.put(LOAD_MASK, "button: Load mask");
71      uiDefinition.put(SELECT_MASK, "choice:" + BOA_.NONE);
72      uiDefinition.put(SELECT_ORIGINAL_IMAGE, "choice:" + BOA_.NONE);
73      // start, end, step, default
74      uiDefinition.put(STEP2, "spinner: 1: 10001: 1:" + Integer.toString(step));
75      // name
76      uiDefinition.put(SMOOTHING2, "checkbox: interpolation:" + Boolean.toString(smoothing));
77      // clear nest
78      uiDefinition.put(CLEAR_NEST, "checkbox: clear:" + Boolean.toString(clearnest));
79      // restore
80      uiDefinition.put(RESTORE_SNAKE, "checkbox: restore:" + Boolean.toString(restoreFields));
81      // use http://www.freeformatter.com/java-dotnet-escape.html#ad-output for escaping
82      //!>
83      uiDefinition.put("help", "<font size=\"3\">If you use this plugin in standalone mode"
84              + " (run from QuimP Toolbar, not from BOA), make sure that frame interval and pixel "
85              + "scale are correct"
86              + "<p><strong>Load Mask</strong> - Load mask file. "
87              + "It should be 8-bit image of size of original stack with <span style=\"color:"
88              + " #ffffff; background-color: #000000;\">black background</span> and"
89              + " grayscale objects. If specified image is binary, cells will be tracked by testing "
90              + "overlapping between frames. For grayscale images plugin will use gray levels to "
91              + "assign cells to the same tracks."  
92              + "</p>\r\n<p><strong>Select Mask</strong> - Select mask already opened in"
93              + " ImageJ."
94              + " Alternative to <em>Load Mask</em>, will override loaded file.</p>\r\n<p>"
95              + "<strong>Select Original</strong> - Ignore this field if you run plugin"
96              + " within BOA. Otherwise you need to set here original image "
97              + "(matching the mask) which will be used for computing statistics and produce complete"
98              + " QCONF file.</p>\r\n<p>"
99              + "<strong>step</strong> - stand for discretisation density, 1.0 means that every"
100             + " pixel of the outline will be mapped to Snake node.</p>"
101             + "\r\n<p><strong>smoothing</strong>&nbsp;"
102             + "- add extra Spline interpolation to the shape</p>"
103             + "\r\n<p><strong>Clear nest</strong>&nbsp;"
104             + "- Delete all other snakes from view. If disabled, each use of <i>Apply</i> "
105             + "will create new snake "
106             + "\r\n<p><strong>Restore Snake</strong>&nbsp;"
107             + "- Try to compute some internal data stored in Snake which are ususally obtained"
108             + " if regular Active Contour method is used. Current AC options are used."
109             + "</p></font>");
110     //!<
111     buildWindow(uiDefinition);
112   }
113 
114   /**
115    * Add listener to apply button.
116    * 
117    * @param action listener
118    * @see QWindowBuilder
119    */
120   void addApplyListener(ActionListener action) {
121     applyB.addActionListener(action);
122   }
123 
124   /**
125    * Add listener to load mask button.
126    * 
127    * @param action listener
128    */
129   void addLoadMaskListener(ActionListener action) {
130     ((JButton) ui.get(LOAD_MASK)).addActionListener(action);
131   }
132 
133   /**
134    * Add listener to image selector.
135    * 
136    * @param action listener
137    */
138   void addSelectImageListener(ItemListener action) {
139     ((Choice) ui.get(SELECT_MASK)).addItemListener(action);
140   }
141 
142   /*
143    * (non-Javadoc)
144    * 
145    * @see QWindowBuilder#buildWindow(com.github.celldynamics.quimp.
146    * plugin.ParamList)
147    */
148   @Override
149   public void buildWindow(ParamList def) {
150     super.buildWindow(def);
151     // add preffered size to this window
152     pluginWnd.setPreferredSize(new Dimension(450, 450));
153     pluginWnd.pack();
154     pluginWnd.setVisible(false);
155     // Destroy window on exit
156     pluginWnd.addWindowListener(new WindowAdapter() {
157       /*
158        * (non-Javadoc)
159        * 
160        * @see java.awt.event.WindowAdapter#windowClosing(java.awt.event.WindowEvent)
161        */
162       @Override
163       public void windowClosing(WindowEvent we) {
164         LOGGER.debug("Window closed");
165         pluginWnd.dispose();
166       }
167     }); // close not hide
168     // update selector
169     pluginWnd.addWindowFocusListener(new WindowFocusListener() {
170       private Choice getImage = (Choice) ui.get(SELECT_MASK);
171       private Choice getOrgImage = (Choice) ui.get(SELECT_ORIGINAL_IMAGE);
172       private String lastSelected = "";
173       private String lastOrgSelected = "";
174 
175       @Override
176       public void windowLostFocus(WindowEvent e) {
177         lastSelected = getImage.getSelectedItem(); // remember on defocus. Will be restored on focus
178         lastOrgSelected = getOrgImage.getSelectedItem();
179       }
180 
181       @Override
182       public void windowGainedFocus(WindowEvent e) {
183         String[] str = WindowManager.getImageTitles(); // get opened windows
184         getImage.removeAll();
185         getOrgImage.removeAll();
186         getImage.add(BOA_.NONE); // add default position
187         getOrgImage.add(BOA_.NONE);
188         for (String s : str) {
189           getImage.add(s);
190           getOrgImage.add(s);
191         }
192         getImage.select(lastSelected); // restore previous. If not available already, 0 position is
193         getOrgImage.select(lastOrgSelected);
194       }
195     });
196 
197   }
198 }