blob: 4d062dc468bedefef5c7c2467d48745f3586fd97 [file] [log] [blame]
jerrymcb7a06a2013-02-17 22:32:29 +00001package org.frc971;
2
jerrymcd2c3322013-02-18 08:49:01 +00003import java.awt.BorderLayout;
4import java.awt.GridLayout;
jerrymcb7a06a2013-02-17 22:32:29 +00005import java.awt.event.KeyEvent;
danielp54e997e2013-02-21 01:54:23 +00006
danielp4a35a7a2013-02-20 20:45:39 +00007import java.util.Arrays;
danielp54e997e2013-02-21 01:54:23 +00008import java.util.logging.Level;
9import java.util.logging.Logger;
10
11import java.io.FileNotFoundException;
jerrymcb7a06a2013-02-17 22:32:29 +000012
jerrymcd2c3322013-02-18 08:49:01 +000013import javax.swing.JPanel;
14import javax.swing.JSlider;
jerrymcb7a06a2013-02-17 22:32:29 +000015import javax.swing.WindowConstants;
jerrymcd2c3322013-02-18 08:49:01 +000016import javax.swing.event.ChangeEvent;
17import javax.swing.event.ChangeListener;
jerrymcb7a06a2013-02-17 22:32:29 +000018
19import com.googlecode.javacv.CanvasFrame;
jerrymcb7a06a2013-02-17 22:32:29 +000020import edu.wpi.first.wpijavacv.WPIColorImage;
jerrym6ebe6452013-02-18 03:00:31 +000021import edu.wpi.first.wpijavacv.WPIImage;
jerrymcb7a06a2013-02-17 22:32:29 +000022
23/* REQUIRED JAVA LIBRARIES:
jerrym38d8af12013-02-18 06:54:13 +000024 * external_jars/
25 * javacpp.jar
26 * javacv-YOUR_OS.jar
27 * javacv.jar
28 * WPIJavaCV.jar
jerrymcb7a06a2013-02-17 22:32:29 +000029 *
jerrym38d8af12013-02-18 06:54:13 +000030 * REQUIRED NATIVE CODE LIBRARIES ON $PATH:
31 * Program Files/WPIJavaCV/ [for example]
jerrymcb7a06a2013-02-17 22:32:29 +000032 * JavaCV_2.2.0/javacv-bin/javacv-YOUR_OS.jar
33 * OpenCV_2.2.0/bin/*
jerrym38d8af12013-02-18 06:54:13 +000034 *
35 * The native libraries and javacv-YOUR_OS.jar must match the 32 vs. 64-bit JVM.
jerrymcb7a06a2013-02-17 22:32:29 +000036 */
37/**
38 * FRC 2013 vision-target recognizer tuner app.
39 *
jerrymf96c32c2013-02-18 19:30:45 +000040 * <p>
41 * See {@link #processEvents()} for the keystroke commands.
42 *
jerrymcb7a06a2013-02-17 22:32:29 +000043 * @author jerry
danielp4a35a7a2013-02-20 20:45:39 +000044 * @author daniel
jerrymcb7a06a2013-02-17 22:32:29 +000045 */
46public class VisionTuner {
jerrym6ebe6452013-02-18 03:00:31 +000047 private Recognizer recognizer = new Recognizer2013();
jerrymcb7a06a2013-02-17 22:32:29 +000048
danielp54e997e2013-02-21 01:54:23 +000049 private final static Logger LOG = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
50
jerrymcd2c3322013-02-18 08:49:01 +000051 private final CanvasFrame cameraFrame = new CanvasFrame("Camera");
52 private final JPanel panel = new JPanel();
53 private final JSlider hueMinSlider = new JSlider();
54 private final JSlider hueMaxSlider = new JSlider();
55 private final JSlider satMinSlider = new JSlider();
56 private final JSlider valMinSlider = new JSlider();
57
jerrymf0c84552013-02-19 00:51:20 +000058 private int totalFrames = -1; // don't count the first (warmup) frame
jerrymf96c32c2013-02-18 19:30:45 +000059 private double totalMsec;
60 private double minMsec = Double.MAX_VALUE;
61 private double maxMsec;
danielp4a35a7a2013-02-20 20:45:39 +000062
63 private TestImageGetter getter;
jerryma1cd68d2013-02-18 09:16:19 +000064
danielp4a35a7a2013-02-20 20:45:39 +000065 public VisionTuner() {
danielp54e997e2013-02-21 01:54:23 +000066 //set logger to log everything
67 LOG.setLevel(Level.ALL);
68 try {
69 LogHandler handler = new LogHandler("../src/org/frc971/ds_vision.log");
70 TimeFormatter formatter = new TimeFormatter();
71 handler.setFormatter(formatter);
72 LOG.addHandler(handler);
73 }
74 catch (FileNotFoundException e) {
75 System.err.println("Warning: Logging initialization failed.");
76 }
77
jerrymcb7a06a2013-02-17 22:32:29 +000078 cameraFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jerrymcb7a06a2013-02-17 22:32:29 +000079
jerrymf96c32c2013-02-18 19:30:45 +000080 recognizer.showIntermediateStages(true);
jerrymcd2c3322013-02-18 08:49:01 +000081
82 cameraFrame.getContentPane().add(panel, BorderLayout.SOUTH);
83 panel.setLayout(new GridLayout(0, 2, 0, 0));
84
85 ChangeListener sliderListener = new ChangeListener() {
86 @Override
jerrymdda60132013-02-18 09:25:03 +000087 public void stateChanged(ChangeEvent e) {
danielp54e997e2013-02-21 01:54:23 +000088 LOG.fine("New HSV range ["
jerrymdda60132013-02-18 09:25:03 +000089 + hueMinSlider.getValue() + " .. "
jerrymcd2469c2013-02-18 20:15:28 +000090 + hueMaxSlider.getValue() + "] "
91 + satMinSlider.getValue() + "+ "
92 + valMinSlider.getValue() + "+");
jerrymdda60132013-02-18 09:25:03 +000093 recognizer.setHSVRange(
94 hueMinSlider.getValue(), hueMaxSlider.getValue(),
95 satMinSlider.getValue(),
96 valMinSlider.getValue());
danielp4a35a7a2013-02-20 20:45:39 +000097 processImage(getter.GetCurrent());
jerrymcd2c3322013-02-18 08:49:01 +000098 }
99 };
100
jerrymcd2c3322013-02-18 08:49:01 +0000101 hueMinSlider.setToolTipText("minimum HSV hue");
102 hueMinSlider.setMaximum(255);
jerrymcd2469c2013-02-18 20:15:28 +0000103 hueMinSlider.setValue(recognizer.getHueMin());
jerrymcd2c3322013-02-18 08:49:01 +0000104 panel.add(hueMinSlider);
105
jerrymcd2c3322013-02-18 08:49:01 +0000106 hueMaxSlider.setToolTipText("maximum HSV hue");
107 hueMaxSlider.setMaximum(255);
jerrymcd2469c2013-02-18 20:15:28 +0000108 hueMaxSlider.setValue(recognizer.getHueMax());
jerrymcd2c3322013-02-18 08:49:01 +0000109 panel.add(hueMaxSlider);
110
jerrymcd2c3322013-02-18 08:49:01 +0000111 satMinSlider.setToolTipText("minimum HSV color saturation");
112 satMinSlider.setMaximum(255);
jerrymcd2469c2013-02-18 20:15:28 +0000113 satMinSlider.setValue(recognizer.getSatMin());
jerrymcd2c3322013-02-18 08:49:01 +0000114 panel.add(satMinSlider);
115
jerrymcd2c3322013-02-18 08:49:01 +0000116 valMinSlider.setToolTipText("minimum HSV brightness value");
117 valMinSlider.setMaximum(255);
jerrymcd2469c2013-02-18 20:15:28 +0000118 valMinSlider.setValue(recognizer.getValMin());
jerrymcd2c3322013-02-18 08:49:01 +0000119 panel.add(valMinSlider);
120
danielp54e997e2013-02-21 01:54:23 +0000121 LOG.fine("Initial HSV range ["
jerrymcd2469c2013-02-18 20:15:28 +0000122 + hueMinSlider.getValue() + " .. "
123 + hueMaxSlider.getValue() + "] "
124 + satMinSlider.getValue() + "+ "
125 + valMinSlider.getValue() + "+");
126
jerrymcd2c3322013-02-18 08:49:01 +0000127 hueMinSlider.addChangeListener(sliderListener);
128 hueMaxSlider.addChangeListener(sliderListener);
129 satMinSlider.addChangeListener(sliderListener);
130 valMinSlider.addChangeListener(sliderListener);
jerrymcb7a06a2013-02-17 22:32:29 +0000131 }
132
jerrymcb7a06a2013-02-17 22:32:29 +0000133 /**
134 * Loads the named test image files.
135 * Sets testImageFilenames and testImages.
136 */
jerrymcb7a06a2013-02-17 22:32:29 +0000137
danielp4a35a7a2013-02-20 20:45:39 +0000138 private void processImage(WPIColorImage cameraImage) {
danielp54e997e2013-02-21 01:54:23 +0000139 cameraFrame.setTitle("Input:");
jerrym6ebe6452013-02-18 03:00:31 +0000140
jerryma1cd68d2013-02-18 09:16:19 +0000141 long startTime = System.nanoTime();
jerrym6ebe6452013-02-18 03:00:31 +0000142 WPIImage processedImage = recognizer.processImage(cameraImage);
jerryma1cd68d2013-02-18 09:16:19 +0000143 long endTime = System.nanoTime();
144
jerrym6ebe6452013-02-18 03:00:31 +0000145 cameraFrame.showImage(processedImage.getBufferedImage());
jerryma1cd68d2013-02-18 09:16:19 +0000146
147 double milliseconds = (endTime - startTime) / 1e6;
jerrymf0c84552013-02-19 00:51:20 +0000148 if (++totalFrames > 0) {
149 totalMsec += milliseconds;
150 minMsec = Math.min(minMsec, milliseconds);
151 maxMsec = Math.max(maxMsec, milliseconds);
danielp54e997e2013-02-21 01:54:23 +0000152 LOG.fine("The recognizer took " + milliseconds + " ms, " +
153 (1000 * totalFrames / totalMsec) + " fps, %.2f avg");
jerrymf0c84552013-02-19 00:51:20 +0000154 }
jerrymcb7a06a2013-02-17 22:32:29 +0000155 }
156
157 private void previousImage() {
danielp4a35a7a2013-02-20 20:45:39 +0000158 WPIColorImage to_process = getter.GetPrev();
159 if (to_process != null)
160 processImage(to_process);
jerrymcb7a06a2013-02-17 22:32:29 +0000161 }
162
163 private void nextImage() {
danielp4a35a7a2013-02-20 20:45:39 +0000164 WPIColorImage to_process = getter.GetNext();
165 if (to_process != null)
166 processImage(to_process);
jerrymcb7a06a2013-02-17 22:32:29 +0000167 }
168
169 private void processEvents() {
jerrymdda60132013-02-18 09:25:03 +0000170 KeyEvent e = cameraFrame.waitKey();
jerrymcb7a06a2013-02-17 22:32:29 +0000171
jerrymdda60132013-02-18 09:25:03 +0000172 switch (e.getKeyCode()) {
jerrymf96c32c2013-02-18 19:30:45 +0000173 case KeyEvent.VK_LEFT: // left arrow key: go to previous image
jerrymdda60132013-02-18 09:25:03 +0000174 previousImage();
175 break;
jerrymf96c32c2013-02-18 19:30:45 +0000176 case KeyEvent.VK_RIGHT: // right arrow key: go to next image
jerrymdda60132013-02-18 09:25:03 +0000177 nextImage();
178 break;
jerrymf96c32c2013-02-18 19:30:45 +0000179 case KeyEvent.VK_Q: // Q: print time measurements then quit
danielp54e997e2013-02-21 01:54:23 +0000180 LOG.fine("The recognizer took " + (totalMsec / totalFrames) + "ms avg, " + minMsec +" min,"
181 + maxMsec + " max, " + (1000 * totalFrames / totalMsec) + " fps avg");
jerrymf96c32c2013-02-18 19:30:45 +0000182 System.exit(0);
jerrymdda60132013-02-18 09:25:03 +0000183 }
jerrymcb7a06a2013-02-17 22:32:29 +0000184 }
185
186 public static void main(final String[] args) {
danielp4a35a7a2013-02-20 20:45:39 +0000187 VisionTuner tuner = new VisionTuner();
188 if (Arrays.asList(args).contains("-debug")) {
189 //debug mode has been requested
190 tuner.getter = new TestImageGetter(".");
191 WPIColorImage to_process = tuner.getter.GetNext();
danielp54e997e2013-02-21 01:54:23 +0000192 if (to_process != null) {
danielp4a35a7a2013-02-20 20:45:39 +0000193 tuner.processImage(to_process);
danielp54e997e2013-02-21 01:54:23 +0000194 for (;;) {
195 tuner.processEvents();
196 }
197 }
danielp4a35a7a2013-02-20 20:45:39 +0000198 else
danielp54e997e2013-02-21 01:54:23 +0000199 LOG.severe("Cannot find test images.");
jerrymcb7a06a2013-02-17 22:32:29 +0000200 }
danielp4a35a7a2013-02-20 20:45:39 +0000201 else {
202 HTTPClient client = new HTTPClient();
203 for (;;) {
204 ImageWithTimestamp to_process = client.GetFrame();
205 if (to_process.image != null) {
206 tuner.processImage(to_process.image);
danielp54e997e2013-02-21 01:54:23 +0000207 LOG.fine("Captured time: " + Double.toString(to_process.timestamp));
danielp4a35a7a2013-02-20 20:45:39 +0000208 }
209 }
jerrymcb7a06a2013-02-17 22:32:29 +0000210 }
211 }
212
213}