blob: c231743a896e80badec385aa9b036cfdda1f8cdf [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;
6import java.io.File;
7import java.io.IOException;
8
9import javax.imageio.ImageIO;
jerrymcd2c3322013-02-18 08:49:01 +000010import javax.swing.JPanel;
11import javax.swing.JSlider;
jerrymcb7a06a2013-02-17 22:32:29 +000012import javax.swing.WindowConstants;
jerrymcd2c3322013-02-18 08:49:01 +000013import javax.swing.event.ChangeEvent;
14import javax.swing.event.ChangeListener;
jerrymcb7a06a2013-02-17 22:32:29 +000015
16import com.googlecode.javacv.CanvasFrame;
17
18import edu.wpi.first.wpijavacv.WPIColorImage;
jerrym6ebe6452013-02-18 03:00:31 +000019import edu.wpi.first.wpijavacv.WPIImage;
jerrymcb7a06a2013-02-17 22:32:29 +000020
21/* REQUIRED JAVA LIBRARIES:
jerrym38d8af12013-02-18 06:54:13 +000022 * external_jars/
23 * javacpp.jar
24 * javacv-YOUR_OS.jar
25 * javacv.jar
26 * WPIJavaCV.jar
jerrymcb7a06a2013-02-17 22:32:29 +000027 *
jerrym38d8af12013-02-18 06:54:13 +000028 * REQUIRED NATIVE CODE LIBRARIES ON $PATH:
29 * Program Files/WPIJavaCV/ [for example]
jerrymcb7a06a2013-02-17 22:32:29 +000030 * JavaCV_2.2.0/javacv-bin/javacv-YOUR_OS.jar
31 * OpenCV_2.2.0/bin/*
jerrym38d8af12013-02-18 06:54:13 +000032 *
33 * The native libraries and javacv-YOUR_OS.jar must match the 32 vs. 64-bit JVM.
jerrymcb7a06a2013-02-17 22:32:29 +000034 */
35/**
36 * FRC 2013 vision-target recognizer tuner app.
37 *
jerrymf96c32c2013-02-18 19:30:45 +000038 * <p>
39 * See {@link #processEvents()} for the keystroke commands.
40 *
jerrymcb7a06a2013-02-17 22:32:29 +000041 * @author jerry
42 */
43public class VisionTuner {
44 private String[] testImageFilenames;
45 private WPIColorImage[] testImages;
jerrymcb7a06a2013-02-17 22:32:29 +000046 private int currentIndex = 0;
jerrym6ebe6452013-02-18 03:00:31 +000047 private Recognizer recognizer = new Recognizer2013();
jerrymcb7a06a2013-02-17 22:32:29 +000048
jerrymcd2c3322013-02-18 08:49:01 +000049 private final CanvasFrame cameraFrame = new CanvasFrame("Camera");
50 private final JPanel panel = new JPanel();
51 private final JSlider hueMinSlider = new JSlider();
52 private final JSlider hueMaxSlider = new JSlider();
53 private final JSlider satMinSlider = new JSlider();
54 private final JSlider valMinSlider = new JSlider();
55
jerrymf96c32c2013-02-18 19:30:45 +000056 private int totalFrames;
57 private double totalMsec;
58 private double minMsec = Double.MAX_VALUE;
59 private double maxMsec;
jerryma1cd68d2013-02-18 09:16:19 +000060
jerrymcb7a06a2013-02-17 22:32:29 +000061 public VisionTuner(String[] imageFilenames) {
62 cameraFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jerrymcb7a06a2013-02-17 22:32:29 +000063
64 loadTestImages(imageFilenames);
jerrymf96c32c2013-02-18 19:30:45 +000065 recognizer.showIntermediateStages(true);
jerrymcd2c3322013-02-18 08:49:01 +000066
67 cameraFrame.getContentPane().add(panel, BorderLayout.SOUTH);
68 panel.setLayout(new GridLayout(0, 2, 0, 0));
69
70 ChangeListener sliderListener = new ChangeListener() {
71 @Override
jerrymdda60132013-02-18 09:25:03 +000072 public void stateChanged(ChangeEvent e) {
73 System.out.println("New HSV range ["
74 + hueMinSlider.getValue() + " .. "
75 + hueMaxSlider.getValue() + "], ["
76 + satMinSlider.getValue() + " .. 255], ["
77 + valMinSlider.getValue() + " .. 255]");
78 recognizer.setHSVRange(
79 hueMinSlider.getValue(), hueMaxSlider.getValue(),
80 satMinSlider.getValue(),
81 valMinSlider.getValue());
82 processCurrentImage();
jerrymcd2c3322013-02-18 08:49:01 +000083 }
84 };
85
86 hueMinSlider.setValue(recognizer.getHueMin());
87 hueMinSlider.setToolTipText("minimum HSV hue");
88 hueMinSlider.setMaximum(255);
89 panel.add(hueMinSlider);
90
91 hueMaxSlider.setValue(recognizer.getHueMax());
92 hueMaxSlider.setToolTipText("maximum HSV hue");
93 hueMaxSlider.setMaximum(255);
94 panel.add(hueMaxSlider);
95
96 satMinSlider.setValue(recognizer.getSatMin());
97 satMinSlider.setToolTipText("minimum HSV color saturation");
98 satMinSlider.setMaximum(255);
99 panel.add(satMinSlider);
100
101 valMinSlider.setValue(recognizer.getValMin());
102 valMinSlider.setToolTipText("minimum HSV brightness value");
103 valMinSlider.setMaximum(255);
104 panel.add(valMinSlider);
105
106 hueMinSlider.addChangeListener(sliderListener);
107 hueMaxSlider.addChangeListener(sliderListener);
108 satMinSlider.addChangeListener(sliderListener);
109 valMinSlider.addChangeListener(sliderListener);
jerrymcb7a06a2013-02-17 22:32:29 +0000110 }
111
jerrymcb7a06a2013-02-17 22:32:29 +0000112 /**
113 * Loads the named test image files.
114 * Sets testImageFilenames and testImages.
115 */
116 private void loadTestImages(String[] imageFilenames) {
jerrymdda60132013-02-18 09:25:03 +0000117 testImageFilenames = imageFilenames;
118 testImages = new WPIColorImage[testImageFilenames.length];
119 currentIndex = 0;
jerrymcb7a06a2013-02-17 22:32:29 +0000120
jerrymdda60132013-02-18 09:25:03 +0000121 for (int i = 0; i < testImageFilenames.length; i++) {
jerrymcb7a06a2013-02-17 22:32:29 +0000122 String imageFilename = testImageFilenames[i];
123
124 System.out.println("Loading image file: " + imageFilename);
125 WPIColorImage rawImage = null;
126 try {
jerrym6ebe6452013-02-18 03:00:31 +0000127 rawImage = new WPIColorImage(ImageIO.read(
jerrymdda60132013-02-18 09:25:03 +0000128 new File(imageFilename)));
jerrymcb7a06a2013-02-17 22:32:29 +0000129 } catch (IOException e) {
jerrym6ebe6452013-02-18 03:00:31 +0000130 System.err.println("Couldn't load image file: " + imageFilename
jerrymdda60132013-02-18 09:25:03 +0000131 + ": " + e.getMessage());
jerrymcb7a06a2013-02-17 22:32:29 +0000132 System.exit(1);
133 return;
134 }
135 testImages[i] = rawImage;
jerrymdda60132013-02-18 09:25:03 +0000136 }
jerrymcb7a06a2013-02-17 22:32:29 +0000137 }
138
139 private void processCurrentImage() {
jerrym6ebe6452013-02-18 03:00:31 +0000140 WPIColorImage cameraImage = testImages[currentIndex];
jerrymcb7a06a2013-02-17 22:32:29 +0000141 cameraFrame.setTitle(testImageFilenames[currentIndex]);
jerrym6ebe6452013-02-18 03:00:31 +0000142
jerryma1cd68d2013-02-18 09:16:19 +0000143 long startTime = System.nanoTime();
jerrym6ebe6452013-02-18 03:00:31 +0000144 WPIImage processedImage = recognizer.processImage(cameraImage);
jerryma1cd68d2013-02-18 09:16:19 +0000145 long endTime = System.nanoTime();
146
jerrym6ebe6452013-02-18 03:00:31 +0000147 cameraFrame.showImage(processedImage.getBufferedImage());
jerryma1cd68d2013-02-18 09:16:19 +0000148
149 double milliseconds = (endTime - startTime) / 1e6;
150 ++totalFrames;
151 totalMsec += milliseconds;
jerrymf96c32c2013-02-18 19:30:45 +0000152 minMsec = Math.min(minMsec, milliseconds);
153 maxMsec = Math.max(maxMsec, milliseconds);
154 System.out.format("The recognizer took %.2f ms, %.2f fps, %.2f avg%n",
jerrymdda60132013-02-18 09:25:03 +0000155 milliseconds, 1000 / milliseconds,
156 1000 * totalFrames / totalMsec);
jerrymcb7a06a2013-02-17 22:32:29 +0000157 }
158
159 private void previousImage() {
jerrymdda60132013-02-18 09:25:03 +0000160 if (currentIndex > 0) {
161 --currentIndex;
162 }
163 processCurrentImage();
jerrymcb7a06a2013-02-17 22:32:29 +0000164 }
165
166 private void nextImage() {
jerrymdda60132013-02-18 09:25:03 +0000167 if (currentIndex + 1 < testImages.length) {
168 ++currentIndex;
169 }
170 processCurrentImage();
jerrymcb7a06a2013-02-17 22:32:29 +0000171 }
172
173 private void processEvents() {
jerrymdda60132013-02-18 09:25:03 +0000174 KeyEvent e = cameraFrame.waitKey();
jerrymcb7a06a2013-02-17 22:32:29 +0000175
jerrymdda60132013-02-18 09:25:03 +0000176 switch (e.getKeyCode()) {
jerrymf96c32c2013-02-18 19:30:45 +0000177 case KeyEvent.VK_LEFT: // left arrow key: go to previous image
jerrymdda60132013-02-18 09:25:03 +0000178 previousImage();
179 break;
jerrymf96c32c2013-02-18 19:30:45 +0000180 case KeyEvent.VK_RIGHT: // right arrow key: go to next image
jerrymdda60132013-02-18 09:25:03 +0000181 nextImage();
182 break;
jerrymf96c32c2013-02-18 19:30:45 +0000183 case KeyEvent.VK_Q: // Q: print time measurements then quit
184 System.out.format("The recognizer took %.2f ms avg, %.2f min,"
185 + " %.2f max, %.2f fps avg%n",
186 totalMsec / totalFrames,
187 minMsec, maxMsec,
188 1000 * totalFrames / totalMsec);
189 System.exit(0);
jerrymdda60132013-02-18 09:25:03 +0000190 }
jerrymcb7a06a2013-02-17 22:32:29 +0000191 }
192
193 public static void main(final String[] args) {
194 if (args.length == 0) {
195 System.err.println("Usage: " + VisionTuner.class.getName()
jerrymdda60132013-02-18 09:25:03 +0000196 + " test image filenames...");
jerrymcb7a06a2013-02-17 22:32:29 +0000197 System.exit(1);
198 }
199
200 VisionTuner tuner = new VisionTuner(args);
201 tuner.processCurrentImage();
202
203 for (;;) {
204 tuner.processEvents();
205 }
206 }
207
208}