1 package org
.usfirst
.frc
.team3501
.robot
.subsystems
;
3 import java
.util
.ArrayList
;
4 import java
.util
.Iterator
;
6 import org
.opencv
.core
.Core
;
7 import org
.opencv
.core
.Mat
;
8 import org
.opencv
.core
.MatOfPoint
;
9 import org
.opencv
.core
.Point
;
10 import org
.opencv
.core
.Rect
;
11 import org
.opencv
.core
.Scalar
;
12 import org
.opencv
.core
.Size
;
13 import org
.opencv
.imgcodecs
.Imgcodecs
;
14 import org
.opencv
.imgproc
.Imgproc
;
15 import org
.opencv
.videoio
.VideoCapture
;
17 import edu
.wpi
.first
.wpilibj
.networktables
.NetworkTable
;
25 * @author Elijah Kaufman
27 * @description Uses opencv and network table 3.0 to detect the vision targets
30 public class TowerTracker
{
33 * static method to load opencv and networkTables
36 System
.loadLibrary(Core
.NATIVE_LIBRARY_NAME
);
37 NetworkTable
.setClientMode();
38 NetworkTable
.setIPAddress("roborio-3019.local");
40 // constants for the color rbg values
41 public static final Scalar
42 RED
= new Scalar(0, 0, 255),
43 BLUE
= new Scalar(255, 0, 0),
44 GREEN
= new Scalar(0, 255, 0),
45 BLACK
= new Scalar(0, 0, 0),
46 YELLOW
= new Scalar(0, 255, 255),
47 // these are the threshold values in order
48 LOWER_BOUNDS
= new Scalar(58, 0, 109),
49 UPPER_BOUNDS
= new Scalar(93, 255, 240);
51 // the size for resing the image
52 public static final Size resize
= new Size(320, 240);
55 public static VideoCapture videoCapture
;
56 public static Mat matOriginal
, matHSV
, matThresh
, clusters
, matHeirarchy
;
58 // Constants for known variables
59 // the height to the top of the target in first stronghold is 97 inches
60 public static final int TOP_TARGET_HEIGHT
= 97;
61 // the physical height of the camera lens
62 public static final int TOP_CAMERA_HEIGHT
= 32;
64 // camera details, can usually be found on the datasheets of the camera
65 public static final double VERTICAL_FOV
= 51;
66 public static final double HORIZONTAL_FOV
= 67;
67 public static final double CAMERA_ANGLE
= 10;
69 public static boolean shouldRun
= true;
74 * command line arguments
75 * just the main loop for the program and the entry points
77 public static void main(String
[] args
) {
78 // TODO Auto-generated method stub
79 matOriginal
= new Mat();
81 matThresh
= new Mat();
83 matHeirarchy
= new Mat();
84 NetworkTable table
= NetworkTable
.getTable("SmartDashboard");
85 // main loop of the program
88 // opens up the camera stream and tries to load it
89 videoCapture
= new VideoCapture();
90 // replaces the ##.## with your team number
91 videoCapture
.open("http://10.##.##.11/mjpg/video.mjpg");
93 // cap.open("http://10.30.19.11/mjpg/video.mjpg");
94 // wait until it is opened
95 while (!videoCapture
.isOpened()) {
97 // time to actually process the acquired images
99 } catch (Exception e
) {
104 // make sure the java process quits when the loop finishes
105 videoCapture
.release();
111 * reads an image from a live image capture and outputs information to the
112 * SmartDashboard or a file
114 public static void processImage() {
115 ArrayList
<MatOfPoint
> contours
= new ArrayList
<MatOfPoint
>();
116 double x
, y
, targetX
, targetY
, distance
, azimuth
;
119 long before
= System
.currentTimeMillis();
120 // only run for the specified time
121 while (FrameCount
< 100) {
123 // capture from the axis camera
124 videoCapture
.read(matOriginal
);
125 // captures from a static file for testing
126 // matOriginal = Imgcodecs.imread("someFile.png");
127 Imgproc
.cvtColor(matOriginal
, matHSV
, Imgproc
.COLOR_BGR2HSV
);
128 Core
.inRange(matHSV
, LOWER_BOUNDS
, UPPER_BOUNDS
, matThresh
);
129 Imgproc
.findContours(matThresh
, contours
, matHeirarchy
,
130 Imgproc
.RETR_EXTERNAL
,
131 Imgproc
.CHAIN_APPROX_SIMPLE
);
132 // make sure the contours that are detected are at least 20x20
133 // pixels with an area of 400 and an aspect ration greater then 1
134 for (Iterator
<MatOfPoint
> iterator
= contours
.iterator(); iterator
136 MatOfPoint matOfPoint
= iterator
.next();
137 Rect rec
= Imgproc
.boundingRect(matOfPoint
);
138 if (rec
.height
< 25 || rec
.width
< 25) {
142 float aspect
= (float) rec
.width
/ (float) rec
.height
;
144 iterator
.remove(); // remove contour if width < height
146 for (MatOfPoint mop
: contours
) {
147 Rect rec
= Imgproc
.boundingRect(mop
);
148 Imgproc
.rectangle(matOriginal
, rec
.br(), rec
.tl(), BLACK
);
150 // if there is only 1 target, then we have found the target we want
151 if (contours
.size() == 1) {
152 Rect rec
= Imgproc
.boundingRect(contours
.get(0));
153 // "fun" math brought to you by miss daisy (team 341)!
154 y
= rec
.br().y
+ rec
.height
/ 2;
155 y
= -((2 * (y
/ matOriginal
.height())) - 1);
156 distance
= (TOP_TARGET_HEIGHT
- TOP_CAMERA_HEIGHT
) /
157 Math
.tan((y
* VERTICAL_FOV
/ 2.0 + CAMERA_ANGLE
) * Math
.PI
/ 180);
158 // angle to target...would not rely on this
159 targetX
= rec
.tl().x
+ rec
.width
/ 2;
160 targetX
= (2 * (targetX
/ matOriginal
.width())) - 1;
161 azimuth
= normalize360(targetX
* HORIZONTAL_FOV
/ 2.0 + 0);
162 // drawing info on target
163 Point center
= new Point(rec
.br().x
- rec
.width
/ 2 - 15, rec
.br().y
165 Point centerw
= new Point(rec
.br().x
- rec
.width
/ 2 - 15, rec
.br().y
166 - rec
.height
/ 2 - 20);
167 Imgproc
.putText(matOriginal
, "" + (int) distance
, center
,
168 Core
.FONT_HERSHEY_PLAIN
, 1, BLACK
);
169 Imgproc
.putText(matOriginal
, "" + (int) azimuth
, centerw
,
170 Core
.FONT_HERSHEY_PLAIN
, 1, BLACK
);
172 // output an image for debugging
173 Imgcodecs
.imwrite("output.png", matOriginal
);
181 * a nonnormalized angle
183 public static double normalize360(double angle
) {
184 while (angle
>= 360.0)