All Downloads are FREE. Search and download functionalities are using the official Maven repository.

boofcv.gui.SelectAlgorithmAndInputPanel Maven / Gradle / Ivy

Go to download

BoofCV is an open source Java library for real-time computer vision and robotics applications.

The newest version!
/*
 * Copyright (c) 2011-2016, Peter Abeles. All Rights Reserved.
 *
 * This file is part of BoofCV (http://boofcv.org).
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package boofcv.gui;

import boofcv.gui.image.ImagePanel;
import boofcv.io.MediaManager;
import boofcv.io.PathLabel;
import boofcv.io.wrapper.DefaultMediaManager;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.util.ArrayList;
import java.util.List;


/**
 * Provides pull a menubar for selecting the input source and which algorithm to use
 *
 * @author Peter Abeles
 */
public abstract class SelectAlgorithmAndInputPanel extends JPanel
		implements ActionListener, VisualizeApp
{
	JToolBar toolbar;
	// each combo box is used to select different algorithms
	JComboBox algBoxes[];
	// used to select the input image
	JComboBox imageBox;
	// when selected it shows the original image
	protected JCheckBox originalCheck;
	List algCookies[];
	// list of input names and where to get the inputs
	protected List inputRefs;
	protected String baseDirectory="";

	// components which had been externally added
	List addedComponents = new ArrayList<>();

	// what the original image was before any processing
	protected BufferedImage inputImage;
	// panel used for displaying the original image
	ImagePanel origPanel = new ImagePanel();
	// the main GUI being displayed
	Component gui;
	// should it post algorithm change events yet?
	boolean postAlgorithmEvents = false;

	// abstract way of reading in media
	protected MediaManager media = DefaultMediaManager.INSTANCE;

	public SelectAlgorithmAndInputPanel(int numAlgFamilies) {
		super(new BorderLayout());
		toolbar = new JToolBar();

		imageBox = new JComboBox();
		toolbar.add(imageBox);
		imageBox.addActionListener(this);
		imageBox.setMaximumSize(imageBox.getPreferredSize());

		algBoxes = new JComboBox[numAlgFamilies];
		algCookies = new List[numAlgFamilies];
		for( int i = 0; i < numAlgFamilies; i++ ) {
			JComboBox b = algBoxes[i] = new JComboBox();
			toolbar.add( b);
			b.addActionListener(this);
			b.setMaximumSize(b.getPreferredSize());
			algCookies[i] = new ArrayList<>();
		}

		toolbar.add(Box.createHorizontalGlue());
		
		originalCheck = new JCheckBox("Show Input");
		toolbar.add(originalCheck);
		originalCheck.addActionListener(this);

		originalCheck.setEnabled(false);

		add(toolbar, BorderLayout.PAGE_START);
	}

	/**
	 * Loads a standardized file for input references
	 *
	 * @param fileName path to config file
	 */
	@Override
	public void loadInputData(String fileName) {
		Reader r = media.openFile(fileName);

		List refs = new ArrayList<>();
		try {
			BufferedReader reader = new BufferedReader(r);

			String line;
			while( (line = reader.readLine()) != null ) {

				String[]z = line.split(":");
				String[] names = new String[z.length-1];
				for( int i = 1; i < z.length; i++ ) {
					names[i-1] = baseDirectory+z[i];
				}

				refs.add(new PathLabel(z[0],names));
			}

			setInputList(refs);

		} catch (IOException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * Sets the directory that relative references are relative too
	 */
	public void setBaseDirectory(String baseDirectory) {
		this.baseDirectory = baseDirectory;
	}

	/**
	 * Adds a new component into the toolbar.
	 *
	 * @param comp The component being added
	 */
	public void addToToolbar( JComponent comp ) {
		toolbar.add(comp,1+algBoxes.length);
		toolbar.revalidate();
		addedComponents.add(comp);
	}

	public void removeFromToolbar( JComponent comp ) {
		toolbar.remove(comp);
		toolbar.revalidate();
		addedComponents.remove(comp);
	}

	/**
	 * Used to add the main GUI to this panel.   Must use this function.
	 * Algorithm change events will not be posted until this function has been set.
	 *
	 * @param gui The main GUI being displayed.
	 */
	public void setMainGUI( final Component gui ) {
		postAlgorithmEvents = true;
		this.gui = gui;
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				add(gui,BorderLayout.CENTER);
			}});
	}

	/**
	 * Specifies an image which contains the original input image.  After this has been called the
	 * view input image widget is activated and when selected this image will be displayed instead
	 * of the main GUI.  This functionality is optional.
	 *
	 * @param image Original input image.
	 */
	public void setInputImage( BufferedImage image ) {
		inputImage = image;
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				if( inputImage == null ) {
					originalCheck.setEnabled(false);
				} else {
					originalCheck.setEnabled(true);
					origPanel.setBufferedImage(inputImage);
					origPanel.setPreferredSize(new Dimension(inputImage.getWidth(),inputImage.getHeight()));
					origPanel.repaint();
				}
			}});
	}

	/**
	 * Specifies a list of images to use as input and loads them
	 *
	 * @param inputRefs Name of input and where to get it
	 */
	public void setInputList(final List inputRefs) {
		this.inputRefs = inputRefs;
		
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				for( int i = 0; i < inputRefs.size(); i++ ) {
					imageBox.addItem(inputRefs.get(i).getLabel());
				}
			}});
	}


	public void addAlgorithm(final int indexFamily, final String name, Object cookie) {
		algCookies[indexFamily].add(cookie);
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				algBoxes[indexFamily].addItem(name);
			}});
	}

	/**
	 * Grabs the currently selected algorithm, passes information to GUI for updating, toggles GUI
	 * being active/not.  refreshAll() is called in a new thread.
	 *
	 */
	public void doRefreshAll() {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				// collect the current state inside the GUI thread
				final Object state[] = new Object[ algCookies.length ];
				for( int i = 0; i < state.length; i++ ) {
					state[i] = algCookies[i].get(algBoxes[i].getSelectedIndex());
				}
				// create a new thread to process this change
				new Thread() {
					public void run() {
						setActiveGUI(false);
						refreshAll(state);
						setActiveGUI(true);
					}
				}.start();
			}});
	}

	/**
	 * Enables/disables the ability to interact with the algorithms GUI.
	 */
	private void setActiveGUI( final boolean isEnabled ) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				toolbar.setEnabled(isEnabled);
				for( JComboBox b : algBoxes ) {
					b.setEnabled(isEnabled);
				}
				for( JComponent b : addedComponents ) {
					b.setEnabled(isEnabled);
				}
				imageBox.setEnabled(isEnabled);
			}
		});
	}

	/**
	 * Returns the cookie associated with the specified algorithm family.
	 */
	protected  T getAlgorithmCookie( int indexFamily ) {
		return (T)algCookies[indexFamily].get( algBoxes[indexFamily].getSelectedIndex() );
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		for( int i = 0; i < algBoxes.length; i++ ) {
			if( algBoxes[i] == e.getSource() ) {
				// see if its ready to start posting these events
				if( !postAlgorithmEvents )
					return;

				// notify the main GUI to change the input algorithm
				final Object cookie = algCookies[i].get(algBoxes[i].getSelectedIndex());
				final String name = (String)algBoxes[i].getSelectedItem();
				final int indexFamily = i;

				new Thread() {
					public void run() {
						performSetAlgorithm(indexFamily,name, cookie);
					}
				}.start();
				return;
			}
		}

		if( e.getSource() == imageBox ) {
			// notify the main GUI to change the input image
			final String name = (String)imageBox.getSelectedItem();
			new Thread() {
				public void run() {
					performChangeInput(name, imageBox.getSelectedIndex());
				}
			}.start();
		} else if( e.getSource() == originalCheck ) {
			origPanel.setSize(gui.getWidth(),gui.getHeight());
			// swap the main GUI with a picture of the original input image
			if( originalCheck.isSelected() ) {
				remove(gui);
				add(origPanel);
			} else {
				remove(origPanel);
				add(gui);
			}
			validate();
			repaint();
		}
	}

	private void performSetAlgorithm( int indexFamily , String name, Object cookie) {
		setActiveGUI(false);
		setActiveAlgorithm(indexFamily, name , cookie );
		setActiveGUI(true);
	}

	private void performChangeInput(String name, int index) {
		setActiveGUI(false);
		changeInput(name, index);
		setActiveGUI(true);
	}

	@Override
	public void setMediaManager( MediaManager manager) {
		this.media = manager;
	}

	/**
	 * Provides the current state of all selected algorithms.
	 *
	 * @param cookies state of each selected algorithm.
	 */
	public abstract void refreshAll( Object[] cookies );

	/**
	 * A request has been made to change the processing algorithm.  NOT called from a GUI thread.
	 *
	 * @param indexFamily
	 * @param name Display name of the algorithm.
	 * @param cookie Reference to user defined data.
	 */
	public abstract void setActiveAlgorithm(int indexFamily, String name, Object cookie);

	/**
	 * A request to change the input image has been made.  The input image's label and its index in the
	 * manager are returned.
	 *
	 * @param name Display name of the image.
	 * @param index Which image in the list.
	 */
	public abstract void changeInput(String name, int index);
}