blob: 4aba589c15382ad6be55760f89e6022187807966 [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;
danielp64c4e052013-02-23 07:21:41 +000012import java.io.IOException;
jerrymcb7a06a2013-02-17 22:32:29 +000013
jerrymcd2c3322013-02-18 08:49:01 +000014import javax.swing.JPanel;
15import javax.swing.JSlider;
jerrymcb7a06a2013-02-17 22:32:29 +000016import javax.swing.WindowConstants;
jerrymcd2c3322013-02-18 08:49:01 +000017import javax.swing.event.ChangeEvent;
18import javax.swing.event.ChangeListener;
jerrymcb7a06a2013-02-17 22:32:29 +000019
20import com.googlecode.javacv.CanvasFrame;
jerrymcb7a06a2013-02-17 22:32:29 +000021import edu.wpi.first.wpijavacv.WPIColorImage;
jerrym6ebe6452013-02-18 03:00:31 +000022import edu.wpi.first.wpijavacv.WPIImage;
jerrymcb7a06a2013-02-17 22:32:29 +000023
24/* REQUIRED JAVA LIBRARIES:
jerrym38d8af12013-02-18 06:54:13 +000025 * external_jars/
26 * javacpp.jar
27 * javacv-YOUR_OS.jar
28 * javacv.jar
29 * WPIJavaCV.jar
jerrymcb7a06a2013-02-17 22:32:29 +000030 *
jerrym38d8af12013-02-18 06:54:13 +000031 * REQUIRED NATIVE CODE LIBRARIES ON $PATH:
32 * Program Files/WPIJavaCV/ [for example]
jerrymcb7a06a2013-02-17 22:32:29 +000033 * JavaCV_2.2.0/javacv-bin/javacv-YOUR_OS.jar
34 * OpenCV_2.2.0/bin/*
jerrym38d8af12013-02-18 06:54:13 +000035 *
36 * The native libraries and javacv-YOUR_OS.jar must match the 32 vs. 64-bit JVM.
jerrymcb7a06a2013-02-17 22:32:29 +000037 */
38/**
39 * FRC 2013 vision-target recognizer tuner app.
40 *
jerrymf96c32c2013-02-18 19:30:45 +000041 * <p>
42 * See {@link #processEvents()} for the keystroke commands.
43 *
jerrymcb7a06a2013-02-17 22:32:29 +000044 * @author jerry
danielp4a35a7a2013-02-20 20:45:39 +000045 * @author daniel
jerrymcb7a06a2013-02-17 22:32:29 +000046 */
47public class VisionTuner {
jerrym6ebe6452013-02-18 03:00:31 +000048 private Recognizer recognizer = new Recognizer2013();
jerrymcb7a06a2013-02-17 22:32:29 +000049
danielp54e997e2013-02-21 01:54:23 +000050 private final static Logger LOG = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);
51
jerrymcd2c3322013-02-18 08:49:01 +000052 private final CanvasFrame cameraFrame = new CanvasFrame("Camera");
53 private final JPanel panel = new JPanel();
54 private final JSlider hueMinSlider = new JSlider();
55 private final JSlider hueMaxSlider = new JSlider();
56 private final JSlider satMinSlider = new JSlider();
57 private final JSlider valMinSlider = new JSlider();
danielp64c4e052013-02-23 07:21:41 +000058
59 private ResultSender sender;
jerrymcd2c3322013-02-18 08:49:01 +000060
jerrymf0c84552013-02-19 00:51:20 +000061 private int totalFrames = -1; // don't count the first (warmup) frame
jerrymf96c32c2013-02-18 19:30:45 +000062 private double totalMsec;
63 private double minMsec = Double.MAX_VALUE;
64 private double maxMsec;
danielp4a35a7a2013-02-20 20:45:39 +000065
66 private TestImageGetter getter;
danielpb3d24ee2013-02-22 19:47:11 +000067
68 private WPIColorImage current;
jerryma1cd68d2013-02-18 09:16:19 +000069
danielp4a35a7a2013-02-20 20:45:39 +000070 public VisionTuner() {
danielp54e997e2013-02-21 01:54:23 +000071 //set logger to log everything
72 LOG.setLevel(Level.ALL);
73 try {
74 LogHandler handler = new LogHandler("../src/org/frc971/ds_vision.log");
75 TimeFormatter formatter = new TimeFormatter();
76 handler.setFormatter(formatter);
77 LOG.addHandler(handler);
78 }
79 catch (FileNotFoundException e) {
80 System.err.println("Warning: Logging initialization failed.");
81 }
82
danielp64c4e052013-02-23 07:21:41 +000083 //initialize result sender
84 try {
85 sender = new ResultSender();
86 }
87 catch (IOException e) {
88 LOG.severe("Server initialization failed: " + e.getMessage() + " Result reporting disabled.");
89 }
jerrymcb7a06a2013-02-17 22:32:29 +000090 cameraFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jerrymcb7a06a2013-02-17 22:32:29 +000091
jerrymf96c32c2013-02-18 19:30:45 +000092 recognizer.showIntermediateStages(true);
jerrymcd2c3322013-02-18 08:49:01 +000093
94 cameraFrame.getContentPane().add(panel, BorderLayout.SOUTH);
95 panel.setLayout(new GridLayout(0, 2, 0, 0));
96
97 ChangeListener sliderListener = new ChangeListener() {
98 @Override
jerrymdda60132013-02-18 09:25:03 +000099 public void stateChanged(ChangeEvent e) {
danielp54e997e2013-02-21 01:54:23 +0000100 LOG.fine("New HSV range ["
jerrymdda60132013-02-18 09:25:03 +0000101 + hueMinSlider.getValue() + " .. "
jerrymcd2469c2013-02-18 20:15:28 +0000102 + hueMaxSlider.getValue() + "] "
103 + satMinSlider.getValue() + "+ "
104 + valMinSlider.getValue() + "+");
jerrymdda60132013-02-18 09:25:03 +0000105 recognizer.setHSVRange(
106 hueMinSlider.getValue(), hueMaxSlider.getValue(),
107 satMinSlider.getValue(),
108 valMinSlider.getValue());
danielpb3d24ee2013-02-22 19:47:11 +0000109 processImage(current);
jerrymcd2c3322013-02-18 08:49:01 +0000110 }
111 };
112
jerrymcd2c3322013-02-18 08:49:01 +0000113 hueMinSlider.setToolTipText("minimum HSV hue");
114 hueMinSlider.setMaximum(255);
jerrymcd2469c2013-02-18 20:15:28 +0000115 hueMinSlider.setValue(recognizer.getHueMin());
jerrymcd2c3322013-02-18 08:49:01 +0000116 panel.add(hueMinSlider);
117
jerrymcd2c3322013-02-18 08:49:01 +0000118 hueMaxSlider.setToolTipText("maximum HSV hue");
119 hueMaxSlider.setMaximum(255);
jerrymcd2469c2013-02-18 20:15:28 +0000120 hueMaxSlider.setValue(recognizer.getHueMax());
jerrymcd2c3322013-02-18 08:49:01 +0000121 panel.add(hueMaxSlider);
122
jerrymcd2c3322013-02-18 08:49:01 +0000123 satMinSlider.setToolTipText("minimum HSV color saturation");
124 satMinSlider.setMaximum(255);
jerrymcd2469c2013-02-18 20:15:28 +0000125 satMinSlider.setValue(recognizer.getSatMin());
jerrymcd2c3322013-02-18 08:49:01 +0000126 panel.add(satMinSlider);
127
jerrymcd2c3322013-02-18 08:49:01 +0000128 valMinSlider.setToolTipText("minimum HSV brightness value");
129 valMinSlider.setMaximum(255);
jerrymcd2469c2013-02-18 20:15:28 +0000130 valMinSlider.setValue(recognizer.getValMin());
jerrymcd2c3322013-02-18 08:49:01 +0000131 panel.add(valMinSlider);
132
danielp54e997e2013-02-21 01:54:23 +0000133 LOG.fine("Initial HSV range ["
jerrymcd2469c2013-02-18 20:15:28 +0000134 + hueMinSlider.getValue() + " .. "
135 + hueMaxSlider.getValue() + "] "
136 + satMinSlider.getValue() + "+ "
137 + valMinSlider.getValue() + "+");
138
jerrymcd2c3322013-02-18 08:49:01 +0000139 hueMinSlider.addChangeListener(sliderListener);
140 hueMaxSlider.addChangeListener(sliderListener);
141 satMinSlider.addChangeListener(sliderListener);
142 valMinSlider.addChangeListener(sliderListener);
jerrymcb7a06a2013-02-17 22:32:29 +0000143 }
144
jerrymcb7a06a2013-02-17 22:32:29 +0000145 /**
146 * Loads the named test image files.
147 * Sets testImageFilenames and testImages.
148 */
jerrymcb7a06a2013-02-17 22:32:29 +0000149
danielp4a35a7a2013-02-20 20:45:39 +0000150 private void processImage(WPIColorImage cameraImage) {
danielpb3d24ee2013-02-22 19:47:11 +0000151 current = cameraImage;
danielp54e997e2013-02-21 01:54:23 +0000152 cameraFrame.setTitle("Input:");
jerrym6ebe6452013-02-18 03:00:31 +0000153
jerryma1cd68d2013-02-18 09:16:19 +0000154 long startTime = System.nanoTime();
jerrym6ebe6452013-02-18 03:00:31 +0000155 WPIImage processedImage = recognizer.processImage(cameraImage);
jerryma1cd68d2013-02-18 09:16:19 +0000156 long endTime = System.nanoTime();
157
jerrym6ebe6452013-02-18 03:00:31 +0000158 cameraFrame.showImage(processedImage.getBufferedImage());
jerryma1cd68d2013-02-18 09:16:19 +0000159
160 double milliseconds = (endTime - startTime) / 1e6;
jerrymf0c84552013-02-19 00:51:20 +0000161 if (++totalFrames > 0) {
162 totalMsec += milliseconds;
163 minMsec = Math.min(minMsec, milliseconds);
164 maxMsec = Math.max(maxMsec, milliseconds);
danielp54e997e2013-02-21 01:54:23 +0000165 LOG.fine("The recognizer took " + milliseconds + " ms, " +
166 (1000 * totalFrames / totalMsec) + " fps, %.2f avg");
jerrymf0c84552013-02-19 00:51:20 +0000167 }
danielp64c4e052013-02-23 07:21:41 +0000168
169 //send results to atom. (and any connected clients)
170
jerrymcb7a06a2013-02-17 22:32:29 +0000171 }
172
173 private void previousImage() {
danielp4a35a7a2013-02-20 20:45:39 +0000174 WPIColorImage to_process = getter.GetPrev();
175 if (to_process != null)
176 processImage(to_process);
jerrymcb7a06a2013-02-17 22:32:29 +0000177 }
178
179 private void nextImage() {
danielp4a35a7a2013-02-20 20:45:39 +0000180 WPIColorImage to_process = getter.GetNext();
181 if (to_process != null)
182 processImage(to_process);
jerrymcb7a06a2013-02-17 22:32:29 +0000183 }
184
185 private void processEvents() {
jerrymdda60132013-02-18 09:25:03 +0000186 KeyEvent e = cameraFrame.waitKey();
jerrymcb7a06a2013-02-17 22:32:29 +0000187
jerrymdda60132013-02-18 09:25:03 +0000188 switch (e.getKeyCode()) {
jerrymf96c32c2013-02-18 19:30:45 +0000189 case KeyEvent.VK_LEFT: // left arrow key: go to previous image
jerrymdda60132013-02-18 09:25:03 +0000190 previousImage();
191 break;
jerrymf96c32c2013-02-18 19:30:45 +0000192 case KeyEvent.VK_RIGHT: // right arrow key: go to next image
jerrymdda60132013-02-18 09:25:03 +0000193 nextImage();
194 break;
jerrymf96c32c2013-02-18 19:30:45 +0000195 case KeyEvent.VK_Q: // Q: print time measurements then quit
danielp54e997e2013-02-21 01:54:23 +0000196 LOG.fine("The recognizer took " + (totalMsec / totalFrames) + "ms avg, " + minMsec +" min,"
197 + maxMsec + " max, " + (1000 * totalFrames / totalMsec) + " fps avg");
jerrymf96c32c2013-02-18 19:30:45 +0000198 System.exit(0);
jerrymdda60132013-02-18 09:25:03 +0000199 }
jerrymcb7a06a2013-02-17 22:32:29 +0000200 }
201
202 public static void main(final String[] args) {
danielp4a35a7a2013-02-20 20:45:39 +0000203 VisionTuner tuner = new VisionTuner();
204 if (Arrays.asList(args).contains("-debug")) {
205 //debug mode has been requested
206 tuner.getter = new TestImageGetter(".");
207 WPIColorImage to_process = tuner.getter.GetNext();
danielp54e997e2013-02-21 01:54:23 +0000208 if (to_process != null) {
danielp4a35a7a2013-02-20 20:45:39 +0000209 tuner.processImage(to_process);
danielp54e997e2013-02-21 01:54:23 +0000210 for (;;) {
211 tuner.processEvents();
212 }
213 }
danielp4a35a7a2013-02-20 20:45:39 +0000214 else
danielp54e997e2013-02-21 01:54:23 +0000215 LOG.severe("Cannot find test images.");
jerrymcb7a06a2013-02-17 22:32:29 +0000216 }
danielp4a35a7a2013-02-20 20:45:39 +0000217 else {
danielp64c4e052013-02-23 07:21:41 +0000218 try {
219 HTTPClient client = new HTTPClient();
220 for (;;) {
221 ImageWithTimestamp to_process = client.GetFrame();
222 if (to_process.image != null) {
223 tuner.processImage(to_process.image);
224 LOG.fine("Captured time: " + Double.toString(to_process.timestamp));
225 }
226 }
227 }
228 catch (IOException e) {
229 LOG.severe("Client initialization failed.");
danielp4a35a7a2013-02-20 20:45:39 +0000230 }
jerrymcb7a06a2013-02-17 22:32:29 +0000231 }
232 }
233
234}