/*
 * Copyright (c) 2011-2015, 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.demonstrations.shapes;

import boofcv.factory.shape.ConfigPolygonDetector;
import boofcv.factory.shape.ConfigRefinePolygonCornersToImage;
import boofcv.factory.shape.ConfigRefinePolygonLineToImage;
import boofcv.gui.StandardAlgConfigPanel;

import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;

/**
 * @author Peter Abeles
 */
public class DetectPolygonControlPanel extends StandardAlgConfigPanel
	implements ActionListener, ChangeListener
{
	DetectBlackPolygonApp owner;

	// selects which image to view
	JComboBox imageView;

	JSpinner selectZoom;

	JCheckBox showCorners;
	JCheckBox showLines;
	JCheckBox showContour;

	JComboBox refineChoice;

	int selectedView = 0;
	boolean bShowCorners = true;
	boolean bShowLines = true;
	boolean bShowContour = false;

	ThresholdControlPanel threshold;

	JSpinner spinnerMinContourSize;
	JSpinner spinnerMinSides;
	JSpinner spinnerMaxSides;
	JSpinner spinnerMinEdge;
	JCheckBox setConvex;
	JCheckBox setBorder;

	JSpinner spinnerContourSplit;
	JSpinner spinnerContourMinSplit;
	JSpinner spinnerContourIterations;
	JSpinner spinnerSplitPenalty;

	JSpinner spinnerLineSamples;
	JSpinner spinnerCornerOffset;
	JSpinner spinnerSampleRadius;
	JSpinner spinnerRefineMaxIterations;
	JSpinner spinnerConvergeTol;
	JSpinner spinnerMaxCornerChange;

	ConfigPolygonDetector config = new ConfigPolygonDetector(3,6);
	ConfigRefinePolygonLineToImage configLine = new ConfigRefinePolygonLineToImage();
	ConfigRefinePolygonCornersToImage configCorner = new ConfigRefinePolygonCornersToImage();
	PolygonRefineType refineType = PolygonRefineType.LINE;

	int minSides = 3;
	int maxSides = 6;

	double zoom = 1;

	public DetectPolygonControlPanel(DetectBlackPolygonApp owner) {
		this.owner = owner;

		imageView = new JComboBox();
		imageView.addItem("Input");
		imageView.addItem("Binary");
		imageView.addItem("Black");
		imageView.addActionListener(this);
		imageView.setMaximumSize(imageView.getPreferredSize());

		selectZoom = new JSpinner(new SpinnerNumberModel(1,0.1,50,1));
		selectZoom.addChangeListener(this);
		selectZoom.setMaximumSize(selectZoom.getPreferredSize());

		showCorners = new JCheckBox("Corners");
		showCorners.addActionListener(this);
		showCorners.setSelected(bShowCorners);
		showLines = new JCheckBox("Lines");
		showLines.setSelected(bShowLines);
		showLines.addActionListener(this);
		showContour = new JCheckBox("Contour");
		showContour.addActionListener(this);
		showContour.setSelected(bShowContour);

		threshold = new ThresholdControlPanel(owner);

		refineChoice = new JComboBox();
		for( PolygonRefineType n : PolygonRefineType.values() ) {
			refineChoice.addItem(n.name());
		}
		refineChoice.setSelectedIndex(refineType.ordinal());
		refineChoice.addActionListener(this);
		refineChoice.setMaximumSize(refineChoice.getPreferredSize());

		spinnerMinContourSize = new JSpinner(new SpinnerNumberModel(config.minContourImageWidthFraction,0.0,0.2,0.01));
		configureSpinnerFloat(spinnerMinContourSize);
		spinnerMinSides = new JSpinner(new SpinnerNumberModel(minSides, 3, 20, 1));
		spinnerMinSides.setMaximumSize(spinnerMinSides.getPreferredSize());
		spinnerMinSides.addChangeListener(this);
		spinnerMaxSides = new JSpinner(new SpinnerNumberModel(maxSides, 3, 20, 1));
		spinnerMaxSides.setMaximumSize(spinnerMaxSides.getPreferredSize());
		spinnerMaxSides.addChangeListener(this);

		spinnerMinEdge = new JSpinner(new SpinnerNumberModel(config.minimumEdgeIntensity,0.0,255.0,1.0));
		spinnerMinEdge.setMaximumSize(spinnerMinEdge.getPreferredSize());
		spinnerMinEdge.addChangeListener(this);
		spinnerContourSplit = new JSpinner(new SpinnerNumberModel(config.contour2Poly_splitFraction,0.0,1.0,0.01));
		configureSpinnerFloat(spinnerContourSplit);
		spinnerContourMinSplit = new JSpinner(new SpinnerNumberModel(config.contour2Poly_minimumSideFraction, 0.0, 1.0, 0.001));
		configureSpinnerFloat(spinnerContourMinSplit);
		spinnerContourSplit.addChangeListener(this);
		spinnerContourIterations = new JSpinner(new SpinnerNumberModel(config.contour2Poly_iterations, 1, 200, 1));
		spinnerContourIterations.setMaximumSize(spinnerContourIterations.getPreferredSize());
		spinnerContourIterations.addChangeListener(this);
		spinnerSplitPenalty = new JSpinner(new SpinnerNumberModel(config.splitPenalty, 0.0, 100.0, 1.0));
		configureSpinnerFloat(spinnerSplitPenalty);

		setConvex = new JCheckBox("Convex");
		setConvex.addActionListener(this);
		setConvex.setSelected(config.convex);
		setBorder = new JCheckBox("Image Border");
		setBorder.addActionListener(this);
		setBorder.setSelected(config.canTouchBorder);

		spinnerLineSamples = new JSpinner(new SpinnerNumberModel(configLine.lineSamples, 5, 100, 1));
		spinnerLineSamples.setMaximumSize(spinnerLineSamples.getPreferredSize());
		spinnerLineSamples.addChangeListener(this);
		spinnerCornerOffset = new JSpinner(new SpinnerNumberModel(configLine.cornerOffset, 0, 10, 1));
		spinnerCornerOffset.setMaximumSize(spinnerCornerOffset.getPreferredSize());
		spinnerCornerOffset.addChangeListener(this);
		spinnerSampleRadius = new JSpinner(new SpinnerNumberModel(configLine.sampleRadius, 0, 10, 1));
		spinnerSampleRadius.setMaximumSize(spinnerCornerOffset.getPreferredSize());
		spinnerSampleRadius.addChangeListener(this);
		spinnerRefineMaxIterations = new JSpinner(new SpinnerNumberModel(configLine.maxIterations, 0, 200, 1));
		spinnerRefineMaxIterations.setMaximumSize(spinnerRefineMaxIterations.getPreferredSize());
		spinnerRefineMaxIterations.addChangeListener(this);
		spinnerConvergeTol = new JSpinner(new SpinnerNumberModel(configLine.convergeTolPixels, 0.0, 2.0, 0.005));
		configureSpinnerFloat(spinnerConvergeTol);
		spinnerMaxCornerChange = new JSpinner(new SpinnerNumberModel(configLine.maxCornerChangePixel, 0.0, 50.0, 1.0));
		configureSpinnerFloat(spinnerMaxCornerChange);

		addLabeled(imageView, "View: ", this);
		addLabeled(selectZoom,"Zoom",this);
		addAlignLeft(showCorners, this);
		addAlignLeft(showLines, this);
		addAlignLeft(showContour, this);
		add(threshold);
		addLabeled(spinnerMinContourSize, "Min Contour Size: ", this);
		addLabeled(spinnerMinSides, "Minimum Sides: ", this);
		addLabeled(spinnerMaxSides, "Maximum Sides: ", this);
		addLabeled(spinnerMinEdge, "Edge Intensity: ", this);
		addAlignLeft(setConvex, this);
		addAlignLeft(setBorder, this);
		addCenterLabel("Contour", this);
		addLabeled(spinnerContourSplit, "Split Fraction: ", this);
		addLabeled(spinnerContourMinSplit, "Min Split: ", this);
		addLabeled(spinnerContourIterations, "Max Iterations: ", this);
		addLabeled(spinnerSplitPenalty, "Split Penalty: ", this);
		addCenterLabel("Refinement", this);
		addLabeled(refineChoice, "Refine: ", this);
		addLabeled(spinnerLineSamples, "Line Samples: ", this);
		addLabeled(spinnerCornerOffset, "Corner Offset: ", this);
		addLabeled(spinnerSampleRadius, "Sample Radius: ", this);
		addLabeled(spinnerRefineMaxIterations, "Iterations: ", this);
		addLabeled(spinnerConvergeTol, "Converge Tol Pixels: ", this);
		addLabeled(spinnerMaxCornerChange, "Max Corner Change: ", this);
		addVerticalGlue(this);
	}

	private void configureSpinnerFloat( JSpinner spinner ) {
		JSpinner.NumberEditor editor = (JSpinner.NumberEditor)spinner.getEditor();
		DecimalFormat format = editor.getFormat();
		format.setMinimumFractionDigits(3);
		format.setMinimumIntegerDigits(1);
		editor.getTextField().setHorizontalAlignment(SwingConstants.CENTER);
		Dimension d = spinner.getPreferredSize();
		d.width = 60;
		spinner.setPreferredSize(d);
		spinner.addChangeListener(this);
		spinner.setMaximumSize(d);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		if( e.getSource() == imageView ) {
			selectedView = imageView.getSelectedIndex();
			owner.viewUpdated();
		} else if( e.getSource() == showCorners ) {
			bShowCorners = showCorners.isSelected();
			owner.viewUpdated();
		} else if( e.getSource() == showLines ) {
			bShowLines = showLines.isSelected();
			owner.viewUpdated();
		} else if( e.getSource() == showContour ) {
			bShowContour = showContour.isSelected();
			owner.viewUpdated();
		} else if( e.getSource() == refineChoice ) {
			refineType = PolygonRefineType.values()[refineChoice.getSelectedIndex()];

			updateRefineSettings();
			owner.configUpdate();
		} else if( e.getSource() == setConvex ) {
			config.convex = setConvex.isSelected();
			owner.configUpdate();
		} else if( e.getSource() == setBorder ) {
			config.canTouchBorder = setBorder.isSelected();
			owner.configUpdate();
		}
	}

	@Override
	public void stateChanged(ChangeEvent e) {
		PolygonRefineType refine = PolygonRefineType.values()[refineChoice.getSelectedIndex()];

		if( e.getSource() == spinnerMinEdge) {
			config.minimumEdgeIntensity = ((Number) spinnerMinEdge.getValue()).doubleValue();
		} else if( e.getSource() == spinnerMinSides ) {
			minSides = ((Number) spinnerMinSides.getValue()).intValue();
			if( minSides > maxSides ) {
				maxSides = minSides;
				spinnerMaxSides.setValue(minSides);
			}
			updateSidesInConfig();
		} else if( e.getSource() == spinnerMaxSides ) {
			maxSides = ((Number) spinnerMaxSides.getValue()).intValue();
			if (maxSides < minSides) {
				minSides = maxSides;
				spinnerMinSides.setValue(minSides);
			}
			updateSidesInConfig();
		} else if( e.getSource() == selectZoom ) {
			zoom = ((Number) selectZoom.getValue()).doubleValue();
			owner.viewUpdated();
			return;
		} else if( e.getSource() == spinnerMinContourSize ) {
				config.minContourImageWidthFraction = ((Number) spinnerMinContourSize.getValue()).doubleValue();
		} else if( e.getSource() == spinnerContourSplit ) {
			config.contour2Poly_splitFraction = ((Number) spinnerContourSplit.getValue()).doubleValue();
		} else if( e.getSource() == spinnerContourMinSplit ) {
			config.contour2Poly_minimumSideFraction = ((Number) spinnerContourMinSplit.getValue()).doubleValue();
		} else if( e.getSource() == spinnerContourIterations ) {
			config.contour2Poly_iterations = ((Number) spinnerContourIterations.getValue()).intValue();
		} else if( e.getSource() == spinnerSplitPenalty ) {
			config.splitPenalty = ((Number) spinnerSplitPenalty.getValue()).doubleValue();
		} else if (e.getSource() == spinnerLineSamples) {
			if (refine == PolygonRefineType.LINE) {
				configLine.lineSamples = ((Number) spinnerLineSamples.getValue()).intValue();
			} else {
				configCorner.lineSamples = ((Number) spinnerLineSamples.getValue()).intValue();
			}
		} else if (e.getSource() == spinnerCornerOffset) {
			if (refine == PolygonRefineType.LINE) {
				configLine.cornerOffset = ((Number) spinnerCornerOffset.getValue()).intValue();
			} else {
				configCorner.cornerOffset = ((Number) spinnerCornerOffset.getValue()).intValue();
			}
		} else if (e.getSource() == spinnerSampleRadius) {
			if (refine == PolygonRefineType.LINE) {
				configLine.sampleRadius = ((Number) spinnerSampleRadius.getValue()).intValue();
			} else {
				configCorner.sampleRadius = ((Number) spinnerSampleRadius.getValue()).intValue();
			}
		} else if (e.getSource() == spinnerRefineMaxIterations) {
			if (refine == PolygonRefineType.LINE) {
				configLine.maxIterations = ((Number) spinnerRefineMaxIterations.getValue()).intValue();
			} else {
				configCorner.maxIterations = ((Number) spinnerRefineMaxIterations.getValue()).intValue();
			}
		} else if (e.getSource() == spinnerConvergeTol) {
			if (refine == PolygonRefineType.LINE) {
				configLine.convergeTolPixels = ((Number) spinnerConvergeTol.getValue()).doubleValue();
			} else {
				configCorner.convergeTolPixels = ((Number) spinnerConvergeTol.getValue()).doubleValue();
			}
		} else if (e.getSource() == spinnerMaxCornerChange) {
			if (refine == PolygonRefineType.LINE) {
				configLine.maxCornerChangePixel = ((Number) spinnerMaxCornerChange.getValue()).doubleValue();
			} else {
				configCorner.maxCornerChangePixel = ((Number) spinnerMaxCornerChange.getValue()).doubleValue();
			}
		}
		owner.configUpdate();
	}

	private void updateSidesInConfig() {
		config.minimumSides = minSides;
		config.maximumSides = maxSides;
	}

	private void updateRefineSettings() {

		spinnerLineSamples.removeChangeListener(this);
		spinnerCornerOffset.removeChangeListener(this);
		spinnerSampleRadius.removeChangeListener(this);
		spinnerRefineMaxIterations.removeChangeListener(this);
		spinnerConvergeTol.removeChangeListener(this);
		spinnerMaxCornerChange.removeChangeListener(this);

		if( refineType == PolygonRefineType.LINE ) {
			spinnerLineSamples.setValue(configLine.lineSamples);
			spinnerCornerOffset.setValue(configLine.cornerOffset);
			spinnerSampleRadius.setValue(configLine.sampleRadius);
			spinnerRefineMaxIterations.setValue(configLine.maxIterations);
			spinnerConvergeTol.setValue(configLine.convergeTolPixels);
			spinnerMaxCornerChange.setValue(configLine.maxCornerChangePixel);
		} else if( refineType == PolygonRefineType.CORNER ){
			spinnerLineSamples.setValue(configCorner.lineSamples);
			spinnerCornerOffset.setValue(configCorner.cornerOffset);
			spinnerSampleRadius.setValue(configCorner.sampleRadius);
			spinnerRefineMaxIterations.setValue(configCorner.maxIterations);
			spinnerConvergeTol.setValue(configCorner.convergeTolPixels);
			spinnerMaxCornerChange.setValue(configCorner.maxCornerChangePixel);
		}

		spinnerLineSamples.addChangeListener(this);
		spinnerCornerOffset.addChangeListener(this);
		spinnerSampleRadius.addChangeListener(this);
		spinnerRefineMaxIterations.addChangeListener(this);
		spinnerConvergeTol.addChangeListener(this);
		spinnerMaxCornerChange.addChangeListener(this);
	}

	public ThresholdControlPanel getThreshold() {
		return threshold;
	}

	public ConfigPolygonDetector getConfigPolygon() {
		return config;
	}

	public ConfigRefinePolygonLineToImage getConfigLine() {
		return configLine;
	}

	public ConfigRefinePolygonCornersToImage getConfigCorner() {
		return configCorner;
	}

	public PolygonRefineType getRefineType() {
		return refineType;
	}
}

 

Ads help maintain this website.