001/**
002 * Copyright (c) 2011, The University of Southampton and the individual contributors.
003 * All rights reserved.
004 *
005 * Redistribution and use in source and binary forms, with or without modification,
006 * are permitted provided that the following conditions are met:
007 *
008 *   *  Redistributions of source code must retain the above copyright notice,
009 *      this list of conditions and the following disclaimer.
010 *
011 *   *  Redistributions in binary form must reproduce the above copyright notice,
012 *      this list of conditions and the following disclaimer in the documentation
013 *      and/or other materials provided with the distribution.
014 *
015 *   *  Neither the name of the University of Southampton nor the names of its
016 *      contributors may be used to endorse or promote products derived from this
017 *      software without specific prior written permission.
018 *
019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029 */
030/**
031 * 
032 */
033package org.openimaj.image.feature.local.detector.mser.gui;
034
035import java.awt.Color;
036import java.awt.GridBagConstraints;
037import java.awt.GridBagLayout;
038import java.awt.Insets;
039import java.awt.event.ActionEvent;
040import java.awt.event.ActionListener;
041import java.awt.event.WindowAdapter;
042import java.awt.event.WindowEvent;
043import java.awt.image.BufferedImage;
044import java.io.File;
045import java.io.IOException;
046import java.util.List;
047
048import javax.swing.BorderFactory;
049import javax.swing.JFileChooser;
050import javax.swing.JFrame;
051import javax.swing.JLabel;
052import javax.swing.JMenu;
053import javax.swing.JMenuBar;
054import javax.swing.JMenuItem;
055import javax.swing.JPanel;
056import javax.swing.JSlider;
057import javax.swing.border.BevelBorder;
058import javax.swing.event.ChangeEvent;
059import javax.swing.event.ChangeListener;
060
061import org.openimaj.image.ImageUtilities;
062import org.openimaj.image.MBFImage;
063import org.openimaj.image.analysis.watershed.Component;
064import org.openimaj.image.analysis.watershed.MergeTreeBuilder;
065import org.openimaj.image.analysis.watershed.feature.PixelsFeature;
066import org.openimaj.image.colour.Transforms;
067import org.openimaj.image.feature.local.detector.mser.MSERFeatureGenerator;
068import org.openimaj.image.feature.local.detector.mser.MSERFeatureGenerator.MSERDirection;
069import org.openimaj.image.feature.local.detector.mser.gui.ImageUtils.ImagePanel;
070
071/**
072 * Test GUI for the MSER extractor
073 * 
074 * @author David Dupplaw (dpd@ecs.soton.ac.uk)
075 * 
076 * 
077 */
078public class TestGUI extends JFrame
079{
080        private static final long serialVersionUID = 1L;
081
082        private JPanel jContentPane = null;
083
084        private JMenuBar jJMenuBar = null;
085
086        private JMenu jFileMenu = null;
087
088        private JMenuItem jOpenMenuItem = null;
089
090        private ImagePanel jImagePanel = null;
091
092        private JPanel jControlsPanel = null;
093        
094        private List<MergeTreeBuilder> mergeTrees = null;
095
096        protected MBFImage img;
097
098        private JLabel jDeltaLabel = null;
099
100        private JSlider jDeltaSlider = null;
101
102        private JLabel jMaxAreaLabel = null;
103
104        private JSlider jMaxAreaSlider = null;
105
106        private JLabel jMinAreaLabel = null;
107
108        private JSlider jMinAreaSlider1 = null;
109
110        private JLabel jMaxVariationLabel = null;
111
112        private JSlider jMaxVariationSlider1 = null;
113
114        private JLabel jMinDiversityLabel = null;
115
116        private JSlider jMinDiversitySlider = null;
117
118
119        /**
120         * This is the default constructor
121         */
122        public TestGUI()
123        {
124                super();
125                initialize();
126        }
127
128        /**
129         * This method initializes this
130         */
131        private void initialize()
132        {
133                this.setSize(768, 541);
134                this.setJMenuBar(getJJMenuBar());
135                this.setContentPane(getJContentPane());
136                this.setTitle( "MSER Test Harness" );
137                
138                this.addWindowListener( new WindowAdapter(){
139                        @Override
140                        public void windowClosing( WindowEvent e )
141                        {
142                                super.windowClosing( e );
143                                System.exit( 1 );
144                        }
145                });
146        }
147
148        /**
149         * This method initializes jContentPane
150         * 
151         * @return javax.swing.JPanel
152         */
153        private JPanel getJContentPane()
154        {
155                if( jContentPane == null )
156                {
157                        GridBagConstraints gridBagConstraints1 = new GridBagConstraints();
158                        gridBagConstraints1.gridx = 1;
159                        gridBagConstraints1.fill = GridBagConstraints.VERTICAL;
160                        gridBagConstraints1.insets = new Insets(4, 4, 4, 4);
161                        gridBagConstraints1.weighty = 1.0D;
162                        gridBagConstraints1.gridy = 0;
163                        GridBagConstraints gridBagConstraints = new GridBagConstraints();
164                        gridBagConstraints.gridx = 0;
165                        gridBagConstraints.weightx = 1.0D;
166                        gridBagConstraints.weighty = 1.0D;
167                        gridBagConstraints.fill = GridBagConstraints.BOTH;
168                        gridBagConstraints.gridy = 0;
169                        jImagePanel = new ImagePanel();
170                        jContentPane = new JPanel();
171                        jContentPane.setLayout(new GridBagLayout());
172                        jContentPane.add(jImagePanel, gridBagConstraints );                     
173                        jContentPane.add(getJControlsPanel(), gridBagConstraints1);
174                }
175                return jContentPane;
176        }
177
178        /**
179         * This method initializes jJMenuBar    
180         *      
181         * @return javax.swing.JMenuBar 
182         */
183        private JMenuBar getJJMenuBar()
184        {
185                if( jJMenuBar == null )
186                {
187                        jJMenuBar = new JMenuBar();
188                        jJMenuBar.add(getJFileMenu());
189                }
190                return jJMenuBar;
191        }
192
193        /**
194         * This method initializes jFileMenu    
195         *      
196         * @return javax.swing.JMenu    
197         */
198        private JMenu getJFileMenu()
199        {
200                if( jFileMenu == null )
201                {
202                        jFileMenu = new JMenu();
203                        jFileMenu.setText("File");
204                        jFileMenu.add(getJOpenMenuItem());
205                }
206                return jFileMenu;
207        }
208
209        /**
210         * This method initializes jOpenMenuItem        
211         *      
212         * @return javax.swing.JMenuItem        
213         */
214        private JMenuItem getJOpenMenuItem()
215        {
216                if( jOpenMenuItem == null )
217                {
218                        jOpenMenuItem = new JMenuItem();
219                        jOpenMenuItem.setText("Open");
220                        jOpenMenuItem.addActionListener( new ActionListener(){
221
222                                @Override
223                                public void actionPerformed( ActionEvent e )
224                                {
225                                        JFileChooser jfc = new JFileChooser();
226                                        int retValue = jfc.showOpenDialog( TestGUI.this );
227                                        if( retValue == JFileChooser.APPROVE_OPTION )
228                                        {
229                                                File f = jfc.getSelectedFile();
230                                                try {
231                                                        loadFile( f );
232                                                } catch (IOException e1) {
233                                                        e1.printStackTrace();
234                                                }
235                                        }
236                                }                               
237                        });
238                }
239                return jOpenMenuItem;
240        }
241
242        private void loadFile( File f ) throws IOException
243        {
244                // Load the image
245                System.out.println("Analysing "+f );
246                TestGUI.this.img = ImageUtilities.readMBF( f );
247                System.out.println("Image Dimensions: "+TestGUI.this.img.getWidth()+"x"+TestGUI.this.img.getHeight() );
248                
249                long start = System.currentTimeMillis();
250                
251                @SuppressWarnings("unchecked")
252                MSERFeatureGenerator mser = new MSERFeatureGenerator( 1, 1, 1, 0f, 0.7f, PixelsFeature.class);
253                
254                TestGUI.this.mergeTrees = mser.performWatershed( Transforms.calculateIntensityNTSC(img) );
255                long end = System.currentTimeMillis();
256
257                // Show some stats
258                long timeTaken = end - start;
259                System.out.println("--------------------------------------------" );
260                System.out.println("Time taken: "+timeTaken+" milliseconds" );
261                System.out.println("Number of pixels: "+img.getWidth()*img.getHeight() );
262                System.out.println("Pixels per second: "+(img.getWidth()*img.getHeight())/(timeTaken/(double)1000) );
263                System.out.println("--------------------------------------------" );
264                
265                updateMSER();
266        }
267        
268        /**
269         * 
270         */
271        private void updateMSER()
272        {
273                System.out.println("Delta: "+jDeltaSlider.getValue() );
274                System.out.println("Max Area: "+jMaxAreaSlider.getValue() );
275                System.out.println("Min Area: "+jMinAreaSlider1.getValue() );
276                System.out.println("Max Variation: "+jMaxVariationSlider1.getValue()/100f );
277                System.out.println("Min Diversity: "+jMinDiversitySlider.getValue()/100f );
278                
279                long start = System.currentTimeMillis();
280                @SuppressWarnings("unchecked")
281                MSERFeatureGenerator mser = new MSERFeatureGenerator( 
282                                jDeltaSlider.getValue(),
283                                jMaxAreaSlider.getValue(),
284                                jMinAreaSlider1.getValue(),
285                                jMaxVariationSlider1.getValue()/100f,
286                                jMinDiversitySlider.getValue()/100f,
287                                PixelsFeature.class);
288                List<Component> up_regions = mser.performMSERDetection( this.mergeTrees, MSERDirection.Up );
289                List<Component> down_regions = mser.performMSERDetection( this.mergeTrees, MSERDirection.Down );
290                long end = System.currentTimeMillis();
291
292                // Show some stats
293                long timeTaken = end - start;
294                System.out.println("--------------------------------------------" );
295                System.out.println("Time taken: "+timeTaken+" milliseconds" );
296                System.out.println("Detected "+(up_regions.size() + down_regions.size()) +" regions" );
297                System.out.println("--------------------------------------------" );            
298                
299                BufferedImage bimg = ComponentUtils.plotComponentList( up_regions, ImageUtils.copyImage(ImageUtilities.createBufferedImage(img)), Color.yellow );
300                bimg = ComponentUtils.plotComponentList( down_regions, bimg, Color.blue);
301                jImagePanel.setImage( bimg );
302        }
303
304        /**
305         * This method initializes jControlsPanel       
306         *      
307         * @return javax.swing.JPanel   
308         */
309        private JPanel getJControlsPanel()
310        {
311                if( jControlsPanel == null )
312                {
313                        GridBagConstraints gridBagConstraints11 = new GridBagConstraints();
314                        gridBagConstraints11.fill = GridBagConstraints.VERTICAL;
315                        gridBagConstraints11.gridy = 9;
316                        gridBagConstraints11.weightx = 1.0;
317                        gridBagConstraints11.gridx = 0;
318                        GridBagConstraints gridBagConstraints10 = new GridBagConstraints();
319                        gridBagConstraints10.gridx = 0;
320                        gridBagConstraints10.fill = GridBagConstraints.HORIZONTAL;
321                        gridBagConstraints10.gridy = 8;
322                        jMinDiversityLabel = new JLabel();
323                        jMinDiversityLabel.setText("Minimum Diversity");
324                        GridBagConstraints gridBagConstraints9 = new GridBagConstraints();
325                        gridBagConstraints9.fill = GridBagConstraints.HORIZONTAL;
326                        gridBagConstraints9.gridy = 7;
327                        gridBagConstraints9.weightx = 1.0;
328                        gridBagConstraints9.gridx = 0;
329                        GridBagConstraints gridBagConstraints8 = new GridBagConstraints();
330                        gridBagConstraints8.gridx = 0;
331                        gridBagConstraints8.fill = GridBagConstraints.HORIZONTAL;
332                        gridBagConstraints8.gridy = 6;
333                        jMaxVariationLabel = new JLabel();
334                        jMaxVariationLabel.setText("Maximum Variation");
335                        GridBagConstraints gridBagConstraints7 = new GridBagConstraints();
336                        gridBagConstraints7.fill = GridBagConstraints.HORIZONTAL;
337                        gridBagConstraints7.gridy = 5;
338                        gridBagConstraints7.weightx = 1.0;
339                        gridBagConstraints7.gridx = 0;
340                        GridBagConstraints gridBagConstraints6 = new GridBagConstraints();
341                        gridBagConstraints6.gridx = 0;
342                        gridBagConstraints6.fill = GridBagConstraints.HORIZONTAL;
343                        gridBagConstraints6.gridy = 4;
344                        jMinAreaLabel = new JLabel();
345                        jMinAreaLabel.setText("Minimum Area");
346                        GridBagConstraints gridBagConstraints5 = new GridBagConstraints();
347                        gridBagConstraints5.fill = GridBagConstraints.HORIZONTAL;
348                        gridBagConstraints5.gridy = 3;
349                        gridBagConstraints5.weightx = 1.0;
350                        gridBagConstraints5.gridx = 0;
351                        GridBagConstraints gridBagConstraints4 = new GridBagConstraints();
352                        gridBagConstraints4.gridx = 0;
353                        gridBagConstraints4.fill = GridBagConstraints.HORIZONTAL;
354                        gridBagConstraints4.gridy = 2;
355                        jMaxAreaLabel = new JLabel();
356                        jMaxAreaLabel.setText("Maximum Area");
357                        GridBagConstraints gridBagConstraints3 = new GridBagConstraints();
358                        gridBagConstraints3.gridx = 0;
359                        gridBagConstraints3.fill = GridBagConstraints.HORIZONTAL;
360                        gridBagConstraints3.gridy = 0;
361                        GridBagConstraints gridBagConstraints2 = new GridBagConstraints();
362                        gridBagConstraints2.fill = GridBagConstraints.HORIZONTAL;
363                        gridBagConstraints2.gridy = 1;
364                        gridBagConstraints2.weightx = 1.0;
365                        gridBagConstraints2.gridx = 0;
366                        jDeltaLabel = new JLabel();
367                        jDeltaLabel.setText("Delta");
368                        jControlsPanel = new JPanel();
369                        jControlsPanel.setLayout(new GridBagLayout());
370                        jControlsPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
371                        jControlsPanel.add(jDeltaLabel, gridBagConstraints3);
372                        jControlsPanel.add(getJDeltaSlider(), gridBagConstraints2);
373                        jControlsPanel.add(jMaxAreaLabel, gridBagConstraints4);
374                        jControlsPanel.add(getJMaxAreaSlider(), gridBagConstraints5);
375                        jControlsPanel.add(jMinAreaLabel, gridBagConstraints6);
376                        jControlsPanel.add(getJMinAreaSlider1(), gridBagConstraints7);
377                        jControlsPanel.add(jMaxVariationLabel, gridBagConstraints8);
378                        jControlsPanel.add(getJMaxVariationSlider1(), gridBagConstraints9);
379                        jControlsPanel.add(jMinDiversityLabel, gridBagConstraints10);
380                        jControlsPanel.add(getJMinDiversitySlider(), gridBagConstraints11);
381                }
382                return jControlsPanel;
383        }
384
385        /**
386         * This method initializes jDeltaSlider 
387         *      
388         * @return javax.swing.JSlider  
389         */
390        private JSlider getJDeltaSlider()
391        {
392                if( jDeltaSlider == null )
393                {
394                        jDeltaSlider = new JSlider();
395                        jDeltaSlider.setMaximum(255);
396                        jDeltaSlider.setValue(10);
397                        jDeltaSlider.setMajorTickSpacing(50);
398                        jDeltaSlider.setPaintTicks(true);
399                        jDeltaSlider.setPaintLabels(true);
400                        jDeltaSlider.setMinorTickSpacing(10);
401                        jDeltaSlider.setMinimum(0);
402                        jDeltaSlider.addChangeListener( new ChangeListener(){
403                                @Override
404                                public void stateChanged( ChangeEvent e )
405                                {
406                                        if( !jDeltaSlider.getValueIsAdjusting() )
407                                                updateMSER();
408                                }                               
409                        });
410                }
411                return jDeltaSlider;
412        }
413
414        /**
415         * This method initializes jMaxAreaSlider       
416         *      
417         * @return javax.swing.JSlider  
418         */
419        private JSlider getJMaxAreaSlider()
420        {
421                if( jMaxAreaSlider == null )
422                {
423                        jMaxAreaSlider = new JSlider();
424                        jMaxAreaSlider.setPaintTicks(true);
425                        jMaxAreaSlider.setMaximum(100000);
426                        jMaxAreaSlider.setMajorTickSpacing(50000);
427                        jMaxAreaSlider.setMinorTickSpacing(5000);
428                        jMaxAreaSlider.setValue(10000);
429                        jMaxAreaSlider.setPaintLabels(true);
430                        jMaxAreaSlider.addChangeListener( new ChangeListener(){
431                                @Override
432                                public void stateChanged( ChangeEvent e )
433                                {
434                                        if( !jMaxAreaSlider.getValueIsAdjusting() )
435                                                updateMSER();
436                                }                               
437                        });
438                }
439                return jMaxAreaSlider;
440        }
441
442        /**
443         * This method initializes jMinAreaSlider1      
444         *      
445         * @return javax.swing.JSlider  
446         */
447        private JSlider getJMinAreaSlider1()
448        {
449                if( jMinAreaSlider1 == null )
450                {
451                        jMinAreaSlider1 = new JSlider();
452                        jMinAreaSlider1.setMajorTickSpacing(200);
453                        jMinAreaSlider1.setPaintTicks(true);
454                        jMinAreaSlider1.setMaximum(1000);
455                        jMinAreaSlider1.setValue(1);
456                        jMinAreaSlider1.setPaintLabels(true);
457                        jMinAreaSlider1.addChangeListener( new ChangeListener(){
458                                @Override
459                                public void stateChanged( ChangeEvent e )
460                                {
461                                        if( !jMinAreaSlider1.getValueIsAdjusting() )
462                                                updateMSER();
463                                }                               
464                        });
465                }
466                return jMinAreaSlider1;
467        }
468
469        /**
470         * This method initializes jMaxVariationSlider1 
471         *      
472         * @return javax.swing.JSlider  
473         */
474        private JSlider getJMaxVariationSlider1()
475        {
476                if( jMaxVariationSlider1 == null )
477                {
478                        jMaxVariationSlider1 = new JSlider();
479                        jMaxVariationSlider1.setMaximum(1000);
480                        jMaxVariationSlider1.setPaintLabels(true);
481                        jMaxVariationSlider1.setPaintTicks(true);
482                        jMaxVariationSlider1.setValue(1000);
483                        jMaxVariationSlider1.setMajorTickSpacing(200);
484                        jMaxVariationSlider1.addChangeListener( new ChangeListener(){
485                                @Override
486                                public void stateChanged( ChangeEvent e )
487                                {
488                                        if( !jMaxVariationSlider1.getValueIsAdjusting() )
489                                                updateMSER();
490                                }                               
491                        });
492                }
493                return jMaxVariationSlider1;
494        }
495
496        /**
497         * This method initializes jMinDiversitySlider  
498         *      
499         * @return javax.swing.JSlider  
500         */
501        private JSlider getJMinDiversitySlider()
502        {
503                if( jMinDiversitySlider == null )
504                {
505                        jMinDiversitySlider = new JSlider();
506                        jMinDiversitySlider.setMajorTickSpacing(20);
507                        jMinDiversitySlider.setPaintTicks(true);
508                        jMinDiversitySlider.setEnabled(true);
509                        jMinDiversitySlider.setPaintLabels(true);
510                        jMinDiversitySlider.addChangeListener( new ChangeListener(){
511                                @Override
512                                public void stateChanged( ChangeEvent e )
513                                {
514                                        if( !jMinDiversitySlider.getValueIsAdjusting() )
515                                                updateMSER();
516                                }                               
517                        });
518                }
519                return jMinDiversitySlider;
520        }
521
522        /**
523         * 
524         *      @param args
525         * @throws IOException 
526         */
527        public static void main( String[] args ) throws IOException
528        {
529                TestGUI t = new TestGUI();
530                t.setVisible( true );
531                 t.loadFile( new File("test-images/spotty-cat.jpg") );
532//              t.loadFile( new File("test-images/grey-patch.png") );
533        }
534}  //  @jve:decl-index=0:visual-constraint="10,10"