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"