Before I attempt to knock out a javacv widget for the frc smart dashboard i have a couple of questions about some things. In many examples i look at there are many variables that are specified and i was wondering where these come from or what they mean. My next question is what are the x and y coordinates for and what do you do with them to adjust the robots position for lining up. What should the x and y be when lined up? How do you calculate distance with javacv and what else should I know about such an application.
“x” and “y” coordinates usually refer to the location of a pixel in the camera image. There are different systems for the coordinate system, but usually “x” is horizontal (so it counts the number of columns) and starts with 0 at the left edge, and (image width-1) at the right edge. “y” is vertical (so it counts the number of rows) and usually starts with 0 at the top, and (image height-1) at the bottom.
Thus the origin (0,0) is usually in the top left of the camera image for computer graphics and computer vision applications (though some times you’ll find code with the origin in the lower left).
Let’s say your camera is mounted on your shooter, and the shooter is amazingly well calibrated. It always shoots discs straight down the middle of the camera image. If your image has a resolution of 640x480 (width x height), then your shooter is aiming at about (320, 240) for (x,y).
Now, if you detect that the center of the goal is to the left of the shooter - say, (100, 240) - then you know you need to turn the robot to the left to aim. If you can get the detected center of the goal in (close to) the exact same spot that your shooter fires, you know you’ll have a high chance of making the shot.
Calculating distance is a little bit tougher. It will involve doing some trigonometry, since a standard RGB camera does not give you distance information directly. One way to do it (which we did to great effect in 2012) is to use the “y” component of the center of the goal. If you know your camera’s height off the ground, the camera’s angle with respect to the ground, the height of the goal, and the “y” component of the goal center, you can set up an inverse trigonometry problem to obtain the missing sides of a triangle. There are other ways to do it too (multiple cameras for stereo vision, or using the size of the goal to figure out distance), but I contend that using trigonometry is the most robust way for FRC (short of using a Kinect). Luckily, most frisbee shooters have a pretty flat arc, so you may not need to do this at all!
For your questions on variables, it depends which examples you are looking at. Here is an example I posted last year (gee, maybe I should update it with some new features from our 2013 version?): http://www.chiefdelphi.com/media/papers/2676? Feel free to ask away about anything in particular.
Ok so in your code i see the part where you constructed constants. How would you tune them. What do they do because i see them in other codes as well.
Yes!
Sorry for the belated reply…
kNearlyHorizontalSlope and kNearlyVerticalSlope were limits we had on how oblique of an angle we would allow in order to count the edge of a target as a vertical or horizontal line. (We would of course expect a rectangular target to have 2 vertical lines and 2 horizontal lines). We tuned them by trial and error, allowing for some misalignment relative to the target, but still throwing out images that were clearly not the goal.
kMinWidth and kMaxWidth were the widths of the vision target from the closest and furthest ranges we would ever see based on our test images.
kRangeOffset is a global value that adds/subtracts to the desired RPM we are commanding (useful if we find that every single shot is too low, for example).
kHoleClosingIterations was found through trial and error on a test set of images. It is a parameter to the OpenCV function cvMorphologyEx.
kShooterOffsetDeg was found by firing our shooter and seeing where in the camera frame the shot went. As you can see, our shooter was consistently about a degree and a half to the left of center of the camera.
kHorizontalFOVDeg is the camera field of view, which is 47 degrees according to the manufacturer. kVerticalFOVDeg is the same.
kCameraHeightIn and kCameraPitchDeg are the height and angle of the camera relative to the floor, respectively. Measured based on our robot.
kTopTargetHeightIn is the height off the floor of the center of the top vision target.
In the constructor, you see a bunch of numbers put into a TreeMap. This map takes a range in inches (first number) and a desired RPM (second number) and basically lets us look up the best RPM for any given range. All of this was driven by shooting on a practice field and recording the optimal RPM for different ranges.
On lines 182-189, you see a few more magic numbers. These were all tweaked in order to find the right color (green) and saturation/value for the target. Driven by taking test images and using MS Paint (or similar) eyedropper to check the values of pixels on the target.
Line 216 is a ratio check…we expect a ratio of height/width between 0.5 and 1.0 (so wider than it is tall). On line 218, the “20” is a parameter to the approxPolygon function, which we found to work well when using test images.
I think that is all of the constants in there (other than things like “4” being the number of sides in a rectangle, and Pi, etc.). Hope this helps. Note that we DEFINITELY could have done a better job of reducing “magic numbers” in our code (and we did in 2013), but this is what you get in 6 weeks
Kinda what you are not looking for, but, do you know some resources where I can learn OpenCV/JavaCV?
One of the best things to do to understand this is to look at Team 341’s DaisyCV, and uncomment out where they display intermediate results. Seeing how the successive operations pull out the hue, saturation, and brightness, threshold them, find the contours, polygons, etc, was very instructional, especially when you read the docs while reading the code.