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         * This is the default constructor
120         */
121        public TestGUI()
122        {
123                super();
124                initialize();
125        }
126
127        /**
128         * This method initializes this
129         */
130        private void initialize()
131        {
132                this.setSize(768, 541);
133                this.setJMenuBar(getJJMenuBar());
134                this.setContentPane(getJContentPane());
135                this.setTitle("MSER Test Harness");
136
137                this.addWindowListener(new WindowAdapter() {
138                        @Override
139                        public void windowClosing(WindowEvent e)
140                        {
141                                super.windowClosing(e);
142                                System.exit(1);
143                        }
144                });
145        }
146
147        /**
148         * This method initializes jContentPane
149         *
150         * @return javax.swing.JPanel
151         */
152        private JPanel getJContentPane()
153        {
154                if (jContentPane == null)
155                {
156                        final GridBagConstraints gridBagConstraints1 = new GridBagConstraints();
157                        gridBagConstraints1.gridx = 1;
158                        gridBagConstraints1.fill = GridBagConstraints.VERTICAL;
159                        gridBagConstraints1.insets = new Insets(4, 4, 4, 4);
160                        gridBagConstraints1.weighty = 1.0D;
161                        gridBagConstraints1.gridy = 0;
162                        final GridBagConstraints gridBagConstraints = new GridBagConstraints();
163                        gridBagConstraints.gridx = 0;
164                        gridBagConstraints.weightx = 1.0D;
165                        gridBagConstraints.weighty = 1.0D;
166                        gridBagConstraints.fill = GridBagConstraints.BOTH;
167                        gridBagConstraints.gridy = 0;
168                        jImagePanel = new ImagePanel();
169                        jContentPane = new JPanel();
170                        jContentPane.setLayout(new GridBagLayout());
171                        jContentPane.add(jImagePanel, gridBagConstraints);
172                        jContentPane.add(getJControlsPanel(), gridBagConstraints1);
173                }
174                return jContentPane;
175        }
176
177        /**
178         * This method initializes jJMenuBar
179         *
180         * @return javax.swing.JMenuBar
181         */
182        private JMenuBar getJJMenuBar()
183        {
184                if (jJMenuBar == null)
185                {
186                        jJMenuBar = new JMenuBar();
187                        jJMenuBar.add(getJFileMenu());
188                }
189                return jJMenuBar;
190        }
191
192        /**
193         * This method initializes jFileMenu
194         *
195         * @return javax.swing.JMenu
196         */
197        private JMenu getJFileMenu()
198        {
199                if (jFileMenu == null)
200                {
201                        jFileMenu = new JMenu();
202                        jFileMenu.setText("File");
203                        jFileMenu.add(getJOpenMenuItem());
204                }
205                return jFileMenu;
206        }
207
208        /**
209         * This method initializes jOpenMenuItem
210         *
211         * @return javax.swing.JMenuItem
212         */
213        private JMenuItem getJOpenMenuItem()
214        {
215                if (jOpenMenuItem == null)
216                {
217                        jOpenMenuItem = new JMenuItem();
218                        jOpenMenuItem.setText("Open");
219                        jOpenMenuItem.addActionListener(new ActionListener() {
220
221                                @Override
222                                public void actionPerformed(ActionEvent e)
223                                {
224                                        final JFileChooser jfc = new JFileChooser();
225                                        final int retValue = jfc.showOpenDialog(TestGUI.this);
226                                        if (retValue == JFileChooser.APPROVE_OPTION)
227                                        {
228                                                final File f = jfc.getSelectedFile();
229                                                try {
230                                                        loadFile(f);
231                                                } catch (final IOException e1) {
232                                                        e1.printStackTrace();
233                                                }
234                                        }
235                                }
236                        });
237                }
238                return jOpenMenuItem;
239        }
240
241        private void loadFile(File f) throws IOException
242        {
243                // Load the image
244                System.out.println("Analysing " + f);
245                TestGUI.this.img = ImageUtilities.readMBF(f);
246                System.out.println("Image Dimensions: " + TestGUI.this.img.getWidth() + "x" + TestGUI.this.img.getHeight());
247
248                final long start = System.currentTimeMillis();
249
250                final MSERFeatureGenerator mser = new MSERFeatureGenerator(1, 1, 1, 0f, 0.7f, PixelsFeature.class);
251
252                TestGUI.this.mergeTrees = mser.performWatershed(Transforms.calculateIntensityNTSC(img));
253                final long end = System.currentTimeMillis();
254
255                // Show some stats
256                final long timeTaken = end - start;
257                System.out.println("--------------------------------------------");
258                System.out.println("Time taken: " + timeTaken + " milliseconds");
259                System.out.println("Number of pixels: " + img.getWidth() * img.getHeight());
260                System.out.println("Pixels per second: " + (img.getWidth() * img.getHeight()) / (timeTaken / (double) 1000));
261                System.out.println("--------------------------------------------");
262
263                updateMSER();
264        }
265
266        /**
267         *
268         */
269        private void updateMSER()
270        {
271                System.out.println("Delta: " + jDeltaSlider.getValue());
272                System.out.println("Max Area: " + jMaxAreaSlider.getValue());
273                System.out.println("Min Area: " + jMinAreaSlider1.getValue());
274                System.out.println("Max Variation: " + jMaxVariationSlider1.getValue() / 100f);
275                System.out.println("Min Diversity: " + jMinDiversitySlider.getValue() / 100f);
276
277                final long start = System.currentTimeMillis();
278                final MSERFeatureGenerator mser = new MSERFeatureGenerator(
279                                jDeltaSlider.getValue(),
280                                jMaxAreaSlider.getValue(),
281                                jMinAreaSlider1.getValue(),
282                                jMaxVariationSlider1.getValue() / 100f,
283                                jMinDiversitySlider.getValue() / 100f,
284                                PixelsFeature.class);
285                final List<Component> up_regions = mser.performMSERDetection(this.mergeTrees, MSERDirection.Up);
286                final List<Component> down_regions = mser.performMSERDetection(this.mergeTrees, MSERDirection.Down);
287                final long end = System.currentTimeMillis();
288
289                // Show some stats
290                final long timeTaken = end - start;
291                System.out.println("--------------------------------------------");
292                System.out.println("Time taken: " + timeTaken + " milliseconds");
293                System.out.println("Detected " + (up_regions.size() + down_regions.size()) + " regions");
294                System.out.println("--------------------------------------------");
295
296                BufferedImage bimg = ComponentUtils.plotComponentList(up_regions,
297                                ImageUtils.copyImage(ImageUtilities.createBufferedImage(img)), Color.yellow);
298                bimg = ComponentUtils.plotComponentList(down_regions, bimg, Color.blue);
299                jImagePanel.setImage(bimg);
300        }
301
302        /**
303         * This method initializes jControlsPanel
304         *
305         * @return javax.swing.JPanel
306         */
307        private JPanel getJControlsPanel()
308        {
309                if (jControlsPanel == null)
310                {
311                        final GridBagConstraints gridBagConstraints11 = new GridBagConstraints();
312                        gridBagConstraints11.fill = GridBagConstraints.VERTICAL;
313                        gridBagConstraints11.gridy = 9;
314                        gridBagConstraints11.weightx = 1.0;
315                        gridBagConstraints11.gridx = 0;
316                        final GridBagConstraints gridBagConstraints10 = new GridBagConstraints();
317                        gridBagConstraints10.gridx = 0;
318                        gridBagConstraints10.fill = GridBagConstraints.HORIZONTAL;
319                        gridBagConstraints10.gridy = 8;
320                        jMinDiversityLabel = new JLabel();
321                        jMinDiversityLabel.setText("Minimum Diversity");
322                        final GridBagConstraints gridBagConstraints9 = new GridBagConstraints();
323                        gridBagConstraints9.fill = GridBagConstraints.HORIZONTAL;
324                        gridBagConstraints9.gridy = 7;
325                        gridBagConstraints9.weightx = 1.0;
326                        gridBagConstraints9.gridx = 0;
327                        final GridBagConstraints gridBagConstraints8 = new GridBagConstraints();
328                        gridBagConstraints8.gridx = 0;
329                        gridBagConstraints8.fill = GridBagConstraints.HORIZONTAL;
330                        gridBagConstraints8.gridy = 6;
331                        jMaxVariationLabel = new JLabel();
332                        jMaxVariationLabel.setText("Maximum Variation");
333                        final GridBagConstraints gridBagConstraints7 = new GridBagConstraints();
334                        gridBagConstraints7.fill = GridBagConstraints.HORIZONTAL;
335                        gridBagConstraints7.gridy = 5;
336                        gridBagConstraints7.weightx = 1.0;
337                        gridBagConstraints7.gridx = 0;
338                        final GridBagConstraints gridBagConstraints6 = new GridBagConstraints();
339                        gridBagConstraints6.gridx = 0;
340                        gridBagConstraints6.fill = GridBagConstraints.HORIZONTAL;
341                        gridBagConstraints6.gridy = 4;
342                        jMinAreaLabel = new JLabel();
343                        jMinAreaLabel.setText("Minimum Area");
344                        final GridBagConstraints gridBagConstraints5 = new GridBagConstraints();
345                        gridBagConstraints5.fill = GridBagConstraints.HORIZONTAL;
346                        gridBagConstraints5.gridy = 3;
347                        gridBagConstraints5.weightx = 1.0;
348                        gridBagConstraints5.gridx = 0;
349                        final GridBagConstraints gridBagConstraints4 = new GridBagConstraints();
350                        gridBagConstraints4.gridx = 0;
351                        gridBagConstraints4.fill = GridBagConstraints.HORIZONTAL;
352                        gridBagConstraints4.gridy = 2;
353                        jMaxAreaLabel = new JLabel();
354                        jMaxAreaLabel.setText("Maximum Area");
355                        final GridBagConstraints gridBagConstraints3 = new GridBagConstraints();
356                        gridBagConstraints3.gridx = 0;
357                        gridBagConstraints3.fill = GridBagConstraints.HORIZONTAL;
358                        gridBagConstraints3.gridy = 0;
359                        final GridBagConstraints gridBagConstraints2 = new GridBagConstraints();
360                        gridBagConstraints2.fill = GridBagConstraints.HORIZONTAL;
361                        gridBagConstraints2.gridy = 1;
362                        gridBagConstraints2.weightx = 1.0;
363                        gridBagConstraints2.gridx = 0;
364                        jDeltaLabel = new JLabel();
365                        jDeltaLabel.setText("Delta");
366                        jControlsPanel = new JPanel();
367                        jControlsPanel.setLayout(new GridBagLayout());
368                        jControlsPanel.setBorder(BorderFactory.createBevelBorder(BevelBorder.RAISED));
369                        jControlsPanel.add(jDeltaLabel, gridBagConstraints3);
370                        jControlsPanel.add(getJDeltaSlider(), gridBagConstraints2);
371                        jControlsPanel.add(jMaxAreaLabel, gridBagConstraints4);
372                        jControlsPanel.add(getJMaxAreaSlider(), gridBagConstraints5);
373                        jControlsPanel.add(jMinAreaLabel, gridBagConstraints6);
374                        jControlsPanel.add(getJMinAreaSlider1(), gridBagConstraints7);
375                        jControlsPanel.add(jMaxVariationLabel, gridBagConstraints8);
376                        jControlsPanel.add(getJMaxVariationSlider1(), gridBagConstraints9);
377                        jControlsPanel.add(jMinDiversityLabel, gridBagConstraints10);
378                        jControlsPanel.add(getJMinDiversitySlider(), gridBagConstraints11);
379                }
380                return jControlsPanel;
381        }
382
383        /**
384         * This method initializes jDeltaSlider
385         *
386         * @return javax.swing.JSlider
387         */
388        private JSlider getJDeltaSlider()
389        {
390                if (jDeltaSlider == null)
391                {
392                        jDeltaSlider = new JSlider();
393                        jDeltaSlider.setMaximum(255);
394                        jDeltaSlider.setValue(10);
395                        jDeltaSlider.setMajorTickSpacing(50);
396                        jDeltaSlider.setPaintTicks(true);
397                        jDeltaSlider.setPaintLabels(true);
398                        jDeltaSlider.setMinorTickSpacing(10);
399                        jDeltaSlider.setMinimum(0);
400                        jDeltaSlider.addChangeListener(new ChangeListener() {
401                                @Override
402                                public void stateChanged(ChangeEvent e)
403                                {
404                                        if (!jDeltaSlider.getValueIsAdjusting())
405                                                updateMSER();
406                                }
407                        });
408                }
409                return jDeltaSlider;
410        }
411
412        /**
413         * This method initializes jMaxAreaSlider
414         *
415         * @return javax.swing.JSlider
416         */
417        private JSlider getJMaxAreaSlider()
418        {
419                if (jMaxAreaSlider == null)
420                {
421                        jMaxAreaSlider = new JSlider();
422                        jMaxAreaSlider.setPaintTicks(true);
423                        jMaxAreaSlider.setMaximum(100000);
424                        jMaxAreaSlider.setMajorTickSpacing(50000);
425                        jMaxAreaSlider.setMinorTickSpacing(5000);
426                        jMaxAreaSlider.setValue(10000);
427                        jMaxAreaSlider.setPaintLabels(true);
428                        jMaxAreaSlider.addChangeListener(new ChangeListener() {
429                                @Override
430                                public void stateChanged(ChangeEvent e)
431                                {
432                                        if (!jMaxAreaSlider.getValueIsAdjusting())
433                                                updateMSER();
434                                }
435                        });
436                }
437                return jMaxAreaSlider;
438        }
439
440        /**
441         * This method initializes jMinAreaSlider1
442         *
443         * @return javax.swing.JSlider
444         */
445        private JSlider getJMinAreaSlider1()
446        {
447                if (jMinAreaSlider1 == null)
448                {
449                        jMinAreaSlider1 = new JSlider();
450                        jMinAreaSlider1.setMajorTickSpacing(200);
451                        jMinAreaSlider1.setPaintTicks(true);
452                        jMinAreaSlider1.setMaximum(1000);
453                        jMinAreaSlider1.setValue(1);
454                        jMinAreaSlider1.setPaintLabels(true);
455                        jMinAreaSlider1.addChangeListener(new ChangeListener() {
456                                @Override
457                                public void stateChanged(ChangeEvent e)
458                                {
459                                        if (!jMinAreaSlider1.getValueIsAdjusting())
460                                                updateMSER();
461                                }
462                        });
463                }
464                return jMinAreaSlider1;
465        }
466
467        /**
468         * This method initializes jMaxVariationSlider1
469         *
470         * @return javax.swing.JSlider
471         */
472        private JSlider getJMaxVariationSlider1()
473        {
474                if (jMaxVariationSlider1 == null)
475                {
476                        jMaxVariationSlider1 = new JSlider();
477                        jMaxVariationSlider1.setMaximum(1000);
478                        jMaxVariationSlider1.setPaintLabels(true);
479                        jMaxVariationSlider1.setPaintTicks(true);
480                        jMaxVariationSlider1.setValue(1000);
481                        jMaxVariationSlider1.setMajorTickSpacing(200);
482                        jMaxVariationSlider1.addChangeListener(new ChangeListener() {
483                                @Override
484                                public void stateChanged(ChangeEvent e)
485                                {
486                                        if (!jMaxVariationSlider1.getValueIsAdjusting())
487                                                updateMSER();
488                                }
489                        });
490                }
491                return jMaxVariationSlider1;
492        }
493
494        /**
495         * This method initializes jMinDiversitySlider
496         *
497         * @return javax.swing.JSlider
498         */
499        private JSlider getJMinDiversitySlider()
500        {
501                if (jMinDiversitySlider == null)
502                {
503                        jMinDiversitySlider = new JSlider();
504                        jMinDiversitySlider.setMajorTickSpacing(20);
505                        jMinDiversitySlider.setPaintTicks(true);
506                        jMinDiversitySlider.setEnabled(true);
507                        jMinDiversitySlider.setPaintLabels(true);
508                        jMinDiversitySlider.addChangeListener(new ChangeListener() {
509                                @Override
510                                public void stateChanged(ChangeEvent e)
511                                {
512                                        if (!jMinDiversitySlider.getValueIsAdjusting())
513                                                updateMSER();
514                                }
515                        });
516                }
517                return jMinDiversitySlider;
518        }
519
520        /**
521         *
522         * @param args
523         * @throws IOException
524         */
525        public static void main(String[] args) throws IOException
526        {
527                final TestGUI t = new TestGUI();
528                t.setVisible(true);
529                t.loadFile(new File("test-images/spotty-cat.jpg"));
530                // t.loadFile( new File("test-images/grey-patch.png") );
531        }
532} // @jve:decl-index=0:visual-constraint="10,10"