-Changed application to display image source at the top of the window.
-Removed the extra windows to show intermediate stages when not in debug mode.
Interestingly, this improved performance significantly.
-Modified slider listener so that it (hopefully) doesn't cause any more segfaults.
-Hid all the calibration controls away in a separate calibration window.
They are accessed by a button on the main display.
I also added labels to each of the sliders.
-Application now takes the IP address of the atom as a command-line argument.
-Code now actually uses result sender, which I had forgot to do last time.
-I made a small modification to Brian's code which reduced the application's
average consumption of RAM from two gigabytes to eight hundred megabytes.
git-svn-id: https://robotics.mvla.net/svn/frc971/2013/trunk/src@4151 f308d9b7-e957-4cde-b6ac-9a88185e7312
diff --git a/971CV/src/org/frc971/VisionTuner.java b/971CV/src/org/frc971/VisionTuner.java
index 4aba589..357b58f 100644
--- a/971CV/src/org/frc971/VisionTuner.java
+++ b/971CV/src/org/frc971/VisionTuner.java
@@ -2,6 +2,8 @@
import java.awt.BorderLayout;
import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.Arrays;
@@ -11,6 +13,8 @@
import java.io.FileNotFoundException;
import java.io.IOException;
+import javax.swing.JButton;
+import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.WindowConstants;
@@ -55,10 +59,11 @@
private final JSlider hueMaxSlider = new JSlider();
private final JSlider satMinSlider = new JSlider();
private final JSlider valMinSlider = new JSlider();
+ private final JButton showCalibration = new JButton("Calibrate");
- private ResultSender sender;
+ private ResultSender sender = null;
- private int totalFrames = -1; // don't count the first (warmup) frame
+ private int totalFrames = -1; // don't count the first (warm-up) frame
private double totalMsec;
private double minMsec = Double.MAX_VALUE;
private double maxMsec;
@@ -66,18 +71,22 @@
private TestImageGetter getter;
private WPIColorImage current;
+
+ private String currentWindowTitle;
+
+ private boolean debug = false;
public VisionTuner() {
//set logger to log everything
LOG.setLevel(Level.ALL);
try {
- LogHandler handler = new LogHandler("../src/org/frc971/ds_vision.log");
+ LogHandler handler = new LogHandler("ds_vision.log");
TimeFormatter formatter = new TimeFormatter();
handler.setFormatter(formatter);
LOG.addHandler(handler);
}
catch (FileNotFoundException e) {
- System.err.println("Warning: Logging initialization failed.");
+ Messages.warning("Logging initialization failed.");
}
//initialize result sender
@@ -85,15 +94,73 @@
sender = new ResultSender();
}
catch (IOException e) {
- LOG.severe("Server initialization failed: " + e.getMessage() + " Result reporting disabled.");
+ LOG.severe("Server initialization failed: " + e.getMessage() + ". Result reporting disabled.");
}
cameraFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
- recognizer.showIntermediateStages(true);
-
cameraFrame.getContentPane().add(panel, BorderLayout.SOUTH);
- panel.setLayout(new GridLayout(0, 2, 0, 0));
+ panel.setLayout(new GridLayout(0, 1, 0, 0));
+
+ showCalibration.setToolTipText("Click here if the system is not finding targets well enough.");
+ panel.add(showCalibration);
+ showCalibration.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ showCalibrationWindow();
+ }
+ });
+ LOG.fine("Initial HSV range ["
+ + hueMinSlider.getValue() + " .. "
+ + hueMaxSlider.getValue() + "] "
+ + satMinSlider.getValue() + "+ "
+ + valMinSlider.getValue() + "+");
+ }
+
+ /** Shows a calibration window when the user clicks the Calibrate button. */
+ private void showCalibrationWindow() {
+ final CanvasFrame calibrationWindow = new CanvasFrame("Calibration");
+ calibrationWindow.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
+
+ final JPanel panel = new JPanel();
+ calibrationWindow.getContentPane().add(panel, BorderLayout.SOUTH);
+ panel.setLayout(new GridLayout(3, 3, 0, 0));
+
+ hueMinSlider.setToolTipText("minimum HSV hue");
+ hueMinSlider.setMaximum(255);
+ hueMinSlider.setValue(recognizer.getHueMin());
+ panel.add(hueMinSlider);
+
+ panel.add(new JLabel("min hue max hue"));
+
+ hueMaxSlider.setToolTipText("maximum HSV hue");
+ hueMaxSlider.setMaximum(255);
+ hueMaxSlider.setValue(recognizer.getHueMax());
+ panel.add(hueMaxSlider);
+
+ satMinSlider.setToolTipText("minimum HSV color saturation");
+ satMinSlider.setMaximum(255);
+ satMinSlider.setValue(recognizer.getSatMin());
+ panel.add(satMinSlider);
+
+ panel.add(new JLabel("min saturation max saturation"));
+
+ valMinSlider.setToolTipText("minimum HSV brightness value");
+ valMinSlider.setMaximum(255);
+ valMinSlider.setValue(recognizer.getValMin());
+ panel.add(valMinSlider);
+
+ panel.add(new JLabel("")); //empty cells can cause problems
+
+ final JButton done = new JButton("Done");
+ panel.add(done);
+ done.addActionListener(new ActionListener() {
+ public void actionPerformed(ActionEvent e) {
+ calibrationWindow.dispose();
+ }
+ });
+
+ panel.add(new JLabel("")); //empty cells can cause problems
+
ChangeListener sliderListener = new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
@@ -106,53 +173,37 @@
hueMinSlider.getValue(), hueMaxSlider.getValue(),
satMinSlider.getValue(),
valMinSlider.getValue());
- processImage(current);
+ if (debug) {
+ processImage(current, null);
+ }
}
};
-
- hueMinSlider.setToolTipText("minimum HSV hue");
- hueMinSlider.setMaximum(255);
- hueMinSlider.setValue(recognizer.getHueMin());
- panel.add(hueMinSlider);
-
- hueMaxSlider.setToolTipText("maximum HSV hue");
- hueMaxSlider.setMaximum(255);
- hueMaxSlider.setValue(recognizer.getHueMax());
- panel.add(hueMaxSlider);
-
- satMinSlider.setToolTipText("minimum HSV color saturation");
- satMinSlider.setMaximum(255);
- satMinSlider.setValue(recognizer.getSatMin());
- panel.add(satMinSlider);
-
- valMinSlider.setToolTipText("minimum HSV brightness value");
- valMinSlider.setMaximum(255);
- valMinSlider.setValue(recognizer.getValMin());
- panel.add(valMinSlider);
-
- LOG.fine("Initial HSV range ["
- + hueMinSlider.getValue() + " .. "
- + hueMaxSlider.getValue() + "] "
- + satMinSlider.getValue() + "+ "
- + valMinSlider.getValue() + "+");
-
+
hueMinSlider.addChangeListener(sliderListener);
hueMaxSlider.addChangeListener(sliderListener);
satMinSlider.addChangeListener(sliderListener);
valMinSlider.addChangeListener(sliderListener);
+
+ calibrationWindow.pack();
+
}
/**
* Loads the named test image files.
* Sets testImageFilenames and testImages.
*/
-
- private void processImage(WPIColorImage cameraImage) {
+ private void processImage(WPIColorImage cameraImage, String title) {
current = cameraImage;
- cameraFrame.setTitle("Input:");
+
+ //set window title if it needs to be changed
+ if (title != null && !title.equals(currentWindowTitle)) {
+ cameraFrame.setTitle(title);
+ currentWindowTitle = title;
+ }
long startTime = System.nanoTime();
- WPIImage processedImage = recognizer.processImage(cameraImage);
+ Target target = recognizer.processImage(cameraImage);
+ WPIImage processedImage = target.editedPicture;
long endTime = System.nanoTime();
cameraFrame.showImage(processedImage.getBufferedImage());
@@ -167,19 +218,22 @@
}
//send results to atom. (and any connected clients)
+ if (sender != null) {
+ sender.send(target.azimuth, target.elevation, target.range);
+ }
}
private void previousImage() {
WPIColorImage to_process = getter.GetPrev();
if (to_process != null)
- processImage(to_process);
+ processImage(to_process, getter.GetName());
}
private void nextImage() {
WPIColorImage to_process = getter.GetNext();
if (to_process != null)
- processImage(to_process);
+ processImage(to_process, getter.GetName());
}
private void processEvents() {
@@ -201,32 +255,51 @@
public static void main(final String[] args) {
VisionTuner tuner = new VisionTuner();
+ Messages.SetWindow(tuner.cameraFrame);
+
+ String atomIP = null;
+ try {
+ atomIP = args[0];
+ }
+ catch (ArrayIndexOutOfBoundsException e) {
+ System.out.println("Usage: VisionTuner [atom ip]");
+ System.exit(0);
+ }
+
if (Arrays.asList(args).contains("-debug")) {
//debug mode has been requested
+ tuner.debug = true;
+
+ //show debugging windows
+ tuner.recognizer.showIntermediateStages(true);
+
tuner.getter = new TestImageGetter(".");
WPIColorImage to_process = tuner.getter.GetNext();
if (to_process != null) {
- tuner.processImage(to_process);
+ tuner.processImage(to_process, tuner.getter.GetName());
for (;;) {
tuner.processEvents();
}
}
- else
- LOG.severe("Cannot find test images.");
+ else {
+ LOG.severe("Could not load test images.");
+ Messages.severe("Could not load test images.");
+ }
}
else {
try {
- HTTPClient client = new HTTPClient();
+ HTTPClient client = new HTTPClient(atomIP);
for (;;) {
ImageWithTimestamp to_process = client.GetFrame();
if (to_process.image != null) {
- tuner.processImage(to_process.image);
+ tuner.processImage(to_process.image, client.GetName());
LOG.fine("Captured time: " + Double.toString(to_process.timestamp));
}
}
}
catch (IOException e) {
- LOG.severe("Client initialization failed.");
+ LOG.severe("Client initialization failed: " + e.getMessage() + ".");
+ Messages.severe("Client initialization failed: " + e.getMessage() + ".");
}
}
}