blob: a6f08c2f4ffff475a6b94125a2897565f67517e1 [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;
danielpb3d24ee2013-02-22 19:47:11 +000064
65 private WPIColorImage current;
jerryma1cd68d2013-02-18 09:16:19 +000066
danielp4a35a7a2013-02-20 20:45:39 +000067 public VisionTuner() {
danielp54e997e2013-02-21 01:54:23 +000068 //set logger to log everything
69 LOG.setLevel(Level.ALL);
70 try {
71 LogHandler handler = new LogHandler("../src/org/frc971/ds_vision.log");
72 TimeFormatter formatter = new TimeFormatter();
73 handler.setFormatter(formatter);
74 LOG.addHandler(handler);
75 }
76 catch (FileNotFoundException e) {
77 System.err.println("Warning: Logging initialization failed.");
78 }
79
jerrymcb7a06a2013-02-17 22:32:29 +000080 cameraFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jerrymcb7a06a2013-02-17 22:32:29 +000081
jerrymf96c32c2013-02-18 19:30:45 +000082 recognizer.showIntermediateStages(true);
jerrymcd2c3322013-02-18 08:49:01 +000083
84 cameraFrame.getContentPane().add(panel, BorderLayout.SOUTH);
85 panel.setLayout(new GridLayout(0, 2, 0, 0));
86
87 ChangeListener sliderListener = new ChangeListener() {
88 @Override
jerrymdda60132013-02-18 09:25:03 +000089 public void stateChanged(ChangeEvent e) {
danielp54e997e2013-02-21 01:54:23 +000090 LOG.fine("New HSV range ["
jerrymdda60132013-02-18 09:25:03 +000091 + hueMinSlider.getValue() + " .. "
jerrymcd2469c2013-02-18 20:15:28 +000092 + hueMaxSlider.getValue() + "] "
93 + satMinSlider.getValue() + "+ "
94 + valMinSlider.getValue() + "+");
jerrymdda60132013-02-18 09:25:03 +000095 recognizer.setHSVRange(
96 hueMinSlider.getValue(), hueMaxSlider.getValue(),
97 satMinSlider.getValue(),
98 valMinSlider.getValue());
danielpb3d24ee2013-02-22 19:47:11 +000099 processImage(current);
jerrymcd2c3322013-02-18 08:49:01 +0000100 }
101 };
102
jerrymcd2c3322013-02-18 08:49:01 +0000103 hueMinSlider.setToolTipText("minimum HSV hue");
104 hueMinSlider.setMaximum(255);
jerrymcd2469c2013-02-18 20:15:28 +0000105 hueMinSlider.setValue(recognizer.getHueMin());
jerrymcd2c3322013-02-18 08:49:01 +0000106 panel.add(hueMinSlider);
107
jerrymcd2c3322013-02-18 08:49:01 +0000108 hueMaxSlider.setToolTipText("maximum HSV hue");
109 hueMaxSlider.setMaximum(255);
jerrymcd2469c2013-02-18 20:15:28 +0000110 hueMaxSlider.setValue(recognizer.getHueMax());
jerrymcd2c3322013-02-18 08:49:01 +0000111 panel.add(hueMaxSlider);
112
jerrymcd2c3322013-02-18 08:49:01 +0000113 satMinSlider.setToolTipText("minimum HSV color saturation");
114 satMinSlider.setMaximum(255);
jerrymcd2469c2013-02-18 20:15:28 +0000115 satMinSlider.setValue(recognizer.getSatMin());
jerrymcd2c3322013-02-18 08:49:01 +0000116 panel.add(satMinSlider);
117
jerrymcd2c3322013-02-18 08:49:01 +0000118 valMinSlider.setToolTipText("minimum HSV brightness value");
119 valMinSlider.setMaximum(255);
jerrymcd2469c2013-02-18 20:15:28 +0000120 valMinSlider.setValue(recognizer.getValMin());
jerrymcd2c3322013-02-18 08:49:01 +0000121 panel.add(valMinSlider);
122
danielp54e997e2013-02-21 01:54:23 +0000123 LOG.fine("Initial HSV range ["
jerrymcd2469c2013-02-18 20:15:28 +0000124 + hueMinSlider.getValue() + " .. "
125 + hueMaxSlider.getValue() + "] "
126 + satMinSlider.getValue() + "+ "
127 + valMinSlider.getValue() + "+");
128
jerrymcd2c3322013-02-18 08:49:01 +0000129 hueMinSlider.addChangeListener(sliderListener);
130 hueMaxSlider.addChangeListener(sliderListener);
131 satMinSlider.addChangeListener(sliderListener);
132 valMinSlider.addChangeListener(sliderListener);
jerrymcb7a06a2013-02-17 22:32:29 +0000133 }
134
jerrymcb7a06a2013-02-17 22:32:29 +0000135 /**
136 * Loads the named test image files.
137 * Sets testImageFilenames and testImages.
138 */
jerrymcb7a06a2013-02-17 22:32:29 +0000139
danielp4a35a7a2013-02-20 20:45:39 +0000140 private void processImage(WPIColorImage cameraImage) {
danielpb3d24ee2013-02-22 19:47:11 +0000141 current = cameraImage;
danielp54e997e2013-02-21 01:54:23 +0000142 cameraFrame.setTitle("Input:");
jerrym6ebe6452013-02-18 03:00:31 +0000143
jerryma1cd68d2013-02-18 09:16:19 +0000144 long startTime = System.nanoTime();
jerrym6ebe6452013-02-18 03:00:31 +0000145 WPIImage processedImage = recognizer.processImage(cameraImage);
jerryma1cd68d2013-02-18 09:16:19 +0000146 long endTime = System.nanoTime();
147
jerrym6ebe6452013-02-18 03:00:31 +0000148 cameraFrame.showImage(processedImage.getBufferedImage());
jerryma1cd68d2013-02-18 09:16:19 +0000149
150 double milliseconds = (endTime - startTime) / 1e6;
jerrymf0c84552013-02-19 00:51:20 +0000151 if (++totalFrames > 0) {
152 totalMsec += milliseconds;
153 minMsec = Math.min(minMsec, milliseconds);
154 maxMsec = Math.max(maxMsec, milliseconds);
danielp54e997e2013-02-21 01:54:23 +0000155 LOG.fine("The recognizer took " + milliseconds + " ms, " +
156 (1000 * totalFrames / totalMsec) + " fps, %.2f avg");
jerrymf0c84552013-02-19 00:51:20 +0000157 }
jerrymcb7a06a2013-02-17 22:32:29 +0000158 }
159
160 private void previousImage() {
danielp4a35a7a2013-02-20 20:45:39 +0000161 WPIColorImage to_process = getter.GetPrev();
162 if (to_process != null)
163 processImage(to_process);
jerrymcb7a06a2013-02-17 22:32:29 +0000164 }
165
166 private void nextImage() {
danielp4a35a7a2013-02-20 20:45:39 +0000167 WPIColorImage to_process = getter.GetNext();
168 if (to_process != null)
169 processImage(to_process);
jerrymcb7a06a2013-02-17 22:32:29 +0000170 }
171
172 private void processEvents() {
jerrymdda60132013-02-18 09:25:03 +0000173 KeyEvent e = cameraFrame.waitKey();
jerrymcb7a06a2013-02-17 22:32:29 +0000174
jerrymdda60132013-02-18 09:25:03 +0000175 switch (e.getKeyCode()) {
jerrymf96c32c2013-02-18 19:30:45 +0000176 case KeyEvent.VK_LEFT: // left arrow key: go to previous image
jerrymdda60132013-02-18 09:25:03 +0000177 previousImage();
178 break;
jerrymf96c32c2013-02-18 19:30:45 +0000179 case KeyEvent.VK_RIGHT: // right arrow key: go to next image
jerrymdda60132013-02-18 09:25:03 +0000180 nextImage();
181 break;
jerrymf96c32c2013-02-18 19:30:45 +0000182 case KeyEvent.VK_Q: // Q: print time measurements then quit
danielp54e997e2013-02-21 01:54:23 +0000183 LOG.fine("The recognizer took " + (totalMsec / totalFrames) + "ms avg, " + minMsec +" min,"
184 + maxMsec + " max, " + (1000 * totalFrames / totalMsec) + " fps avg");
jerrymf96c32c2013-02-18 19:30:45 +0000185 System.exit(0);
jerrymdda60132013-02-18 09:25:03 +0000186 }
jerrymcb7a06a2013-02-17 22:32:29 +0000187 }
188
189 public static void main(final String[] args) {
danielp4a35a7a2013-02-20 20:45:39 +0000190 VisionTuner tuner = new VisionTuner();
191 if (Arrays.asList(args).contains("-debug")) {
192 //debug mode has been requested
193 tuner.getter = new TestImageGetter(".");
194 WPIColorImage to_process = tuner.getter.GetNext();
danielp54e997e2013-02-21 01:54:23 +0000195 if (to_process != null) {
danielp4a35a7a2013-02-20 20:45:39 +0000196 tuner.processImage(to_process);
danielp54e997e2013-02-21 01:54:23 +0000197 for (;;) {
198 tuner.processEvents();
199 }
200 }
danielp4a35a7a2013-02-20 20:45:39 +0000201 else
danielp54e997e2013-02-21 01:54:23 +0000202 LOG.severe("Cannot find test images.");
jerrymcb7a06a2013-02-17 22:32:29 +0000203 }
danielp4a35a7a2013-02-20 20:45:39 +0000204 else {
205 HTTPClient client = new HTTPClient();
206 for (;;) {
207 ImageWithTimestamp to_process = client.GetFrame();
208 if (to_process.image != null) {
209 tuner.processImage(to_process.image);
danielp54e997e2013-02-21 01:54:23 +0000210 LOG.fine("Captured time: " + Double.toString(to_process.timestamp));
danielp4a35a7a2013-02-20 20:45:39 +0000211 }
212 }
jerrymcb7a06a2013-02-17 22:32:29 +0000213 }
214 }
215
216}