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"