Fix errors in Vision examples.

Change-Id: I752a99ff7b8872a0fc8926e3633c2b521383bbd0
This commit is contained in:
Kevin O'Connor
2015-01-16 14:38:24 -05:00
parent 081d7f7361
commit 9b7042a51a
50 changed files with 61 additions and 199 deletions

View File

@@ -20,12 +20,15 @@ import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
* To use a USB camera instead, see the SimpelVision and AdvancedVision examples for details
* on using the USB camera. To use an Axis Camera, see the AxisCamera example for details on
* using an Axis Camera.
*
* Sample omages can be found here: http://wp.wpi.edu/wpilib/2015/01/16/sample-images-for-vision-projects/
*/
public class Robot extends SampleRobot {
//A structure to hold measurements of a particle
public class ParticleReport implements Comparator<ParticleReport>, Comparable<ParticleReport>{
double PercentAreaToImageArea;
double Area;
double ConvexHullArea;
double BoundingRectLeft;
double BoundingRectTop;
double BoundingRectRight;
@@ -44,8 +47,10 @@ public class Robot extends SampleRobot {
//Structure to represent the scores for the various tests used for target identification
public class Scores {
double Area;
double Aspect;
double Trapezoid;
double LongAspect;
double ShortAspect;
double AreaToConvexHullArea;
};
//Images
@@ -54,9 +59,9 @@ public class Robot extends SampleRobot {
int imaqError;
//Constants
NIVision.Range TOTE_HUE_RANGE = new NIVision.Range(101, 64); //Default hue range for yellow tote
NIVision.Range TOTE_SAT_RANGE = new NIVision.Range(88, 255); //Default saturation range for yellow tote
NIVision.Range TOTE_VAL_RANGE = new NIVision.Range(134, 255); //Default value range for yellow tote
NIVision.Range TOTE_HUE_RANGE = new NIVision.Range(24, 49); //Default hue range for yellow tote
NIVision.Range TOTE_SAT_RANGE = new NIVision.Range(67, 255); //Default saturation range for yellow tote
NIVision.Range TOTE_VAL_RANGE = new NIVision.Range(49, 255); //Default value range for yellow tote
double AREA_MINIMUM = 0.5; //Default Area minimum for particle as a percentage of total image area
double LONG_RATIO = 2.22; //Tote long side = 26.9 / Tote height = 12.1 = 2.22
double SHORT_RATIO = 1.4; //Tote short side = 16.9 / Tote height = 12.1 = 1.4
@@ -85,7 +90,7 @@ public class Robot extends SampleRobot {
public void autonomous() {
while (isAutonomous() && isEnabled())
{
//read file in from disk. For this example to run you need to copy image20.jpg from the SampleImages folder in this project to the
//read file in from disk. For this example to run you need to copy image20.jpg from the SampleImages folder to the
//directory shown below using FTP or SFTP: http://wpilib.screenstepslive.com/s/4485/m/24166/l/282299-roborio-ftp
NIVision.imaqReadFile(frame, "/home/lvuser/SampleImages/image20.jpg");
@@ -125,6 +130,7 @@ public class Robot extends SampleRobot {
ParticleReport par = new ParticleReport();
par.PercentAreaToImageArea = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_AREA_BY_IMAGE_AREA);
par.Area = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_AREA);
par.ConvexHullArea = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_CONVEX_HULL_AREA);
par.BoundingRectTop = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_BOUNDING_RECT_TOP);
par.BoundingRectLeft = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_BOUNDING_RECT_LEFT);
par.BoundingRectBottom = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_BOUNDING_RECT_BOTTOM);
@@ -136,15 +142,20 @@ public class Robot extends SampleRobot {
//This example only scores the largest particle. Extending to score all particles and choosing the desired one is left as an exercise
//for the reader. Note that the long and short side scores expect a single tote and will not work for a stack of 2 or more totes.
//Modification of the code to accommodate 2 or more stacked totes is left as an exercise for the reader.
scores.Aspect = AspectScore(particles.elementAt(0));
SmartDashboard.putNumber("Aspect", scores.Aspect);
scores.Area = AreaScore(particles.elementAt(0));
SmartDashboard.putNumber("Area", scores.Area);
boolean isTote = scores.Aspect > SCORE_MIN && scores.Area > SCORE_MIN;
scores.Trapezoid = TrapezoidScore(particles.elementAt(0));
SmartDashboard.putNumber("Trapezoid", scores.Trapezoid);
scores.LongAspect = LongSideScore(particles.elementAt(0));
SmartDashboard.putNumber("Long Aspect", scores.LongAspect);
scores.ShortAspect = ShortSideScore(particles.elementAt(0));
SmartDashboard.putNumber("Short Aspect", scores.ShortAspect);
scores.AreaToConvexHullArea = ConvexHullAreaScore(particles.elementAt(0));
SmartDashboard.putNumber("Convex Hull Area", scores.AreaToConvexHullArea);
boolean isTote = scores.Trapezoid > SCORE_MIN && (scores.LongAspect > SCORE_MIN || scores.ShortAspect > SCORE_MIN) && scores.AreaToConvexHullArea > SCORE_MIN;
boolean isLong = scores.LongAspect > scores.ShortAspect;
//Send distance and tote status to dashboard. The bounding rect, particularly the horizontal center (left - right) may be useful for rotating/driving towards a tote
SmartDashboard.putBoolean("IsTote", isTote);
SmartDashboard.putNumber("Distance", computeDistance(binaryFrame, particles.elementAt(0)));
SmartDashboard.putNumber("Distance", computeDistance(binaryFrame, particles.elementAt(0), isLong));
} else {
SmartDashboard.putBoolean("IsTote", false);
}
@@ -175,19 +186,36 @@ public class Robot extends SampleRobot {
return (Math.max(0, Math.min(100*(1-Math.abs(1-ratio)), 100)));
}
double AreaScore(ParticleReport report)
/**
* Method to score convex hull area. This scores how "complete" the particle is. Particles with large holes will score worse than a filled in shape
*/
double ConvexHullAreaScore(ParticleReport report)
{
double boundingArea = (report.BoundingRectBottom - report.BoundingRectTop) * (report.BoundingRectRight - report.BoundingRectLeft);
//Tape is 7" edge so 49" bounding rect. With 2" wide tape it covers 24" of the rect.
return ratioToScore((49/24)*report.Area/boundingArea);
return ratioToScore((report.Area/report.ConvexHullArea)*1.18);
}
/**
* Method to score if the aspect ratio of the particle appears to match the retro-reflective target. Target is 7"x7" so aspect should be 1
* Method to score if the particle appears to be a trapezoid. Compares the convex hull (filled in) area to the area of the bounding box.
* The expectation is that the convex hull area is about 95.4% of the bounding box area for an ideal tote.
*/
double AspectScore(ParticleReport report)
double TrapezoidScore(ParticleReport report)
{
return ratioToScore(((report.BoundingRectRight-report.BoundingRectLeft)/(report.BoundingRectBottom-report.BoundingRectTop)));
return ratioToScore(report.ConvexHullArea/((report.BoundingRectRight-report.BoundingRectLeft)*(report.BoundingRectBottom-report.BoundingRectTop)*.954));
}
/**
* Method to score if the aspect ratio of the particle appears to match the long side of a tote.
*/
double LongSideScore(ParticleReport report)
{
return ratioToScore(((report.BoundingRectRight-report.BoundingRectLeft)/(report.BoundingRectBottom-report.BoundingRectTop))/LONG_RATIO);
}
/**
* Method to score if the aspect ratio of the particle appears to match the short side of a tote.
*/
double ShortSideScore(ParticleReport report){
return ratioToScore(((report.BoundingRectRight-report.BoundingRectLeft)/(report.BoundingRectBottom-report.BoundingRectTop))/SHORT_RATIO);
}
/**
@@ -199,13 +227,13 @@ public class Robot extends SampleRobot {
* @param isLong Boolean indicating if the target is believed to be the long side of a tote
* @return The estimated distance to the target in feet.
*/
double computeDistance (Image image, ParticleReport report) {
double computeDistance (Image image, ParticleReport report, boolean isLong) {
double normalizedWidth, targetWidth;
NIVision.GetImageSizeResult size;
size = NIVision.imaqGetImageSize(image);
normalizedWidth = 2*(report.BoundingRectRight - report.BoundingRectLeft)/size.width;
targetWidth = 7;
targetWidth = isLong ? 26.0 : 16.9;
return targetWidth/(normalizedWidth*12*Math.tan(VIEW_ANGLE*Math.PI/(180*2)));
}

View File

@@ -20,6 +20,8 @@ import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
* To use a USB camera instead, see the SimpelVision and AdvancedVision examples for details
* on using the USB camera. To use an Axis Camera, see the AxisCamera example for details on
* using an Axis Camera.
*
* Sample images can found here: http://wp.wpi.edu/wpilib/2015/01/16/sample-images-for-vision-projects/
*/
public class Robot extends SampleRobot {
//A structure to hold measurements of a particle
@@ -85,7 +87,7 @@ public class Robot extends SampleRobot {
public void autonomous() {
while (isAutonomous() && isEnabled())
{
//read file in from disk. For this example to run you need to copy image.jpg from the SampleImages folder in this project to the
//read file in from disk. For this example to run you need to copy image.jpg from the SampleImages folder to the
//directory shown below using FTP or SFTP: http://wpilib.screenstepslive.com/s/4485/m/24166/l/282299-roborio-ftp
NIVision.imaqReadFile(frame, "/home/lvuser/SampleImages/image.jpg");

View File

@@ -339,53 +339,10 @@
</tags>
<packages>
<package>src/$package-dir</package>
<package>SampleImages</package>
</packages>
<files>
<file source="examples/2015Vision/Color_src/Robot.java"
destination="src/$package-dir/Robot.java"></file>
<file source="examples/2015Vision/SampleImages/image.jpg"
destination="SampleImages/image.jpg"></file>
<file source="examples/2015Vision/SampleImages/image2.jpg"
destination="SampleImages/image2.jpg"></file>
<file source="examples/2015Vision/SampleImages/image3.jpg"
destination="SampleImages/image3.jpg"></file>
<file source="examples/2015Vision/SampleImages/image4.jpg"
destination="SampleImages/image4.jpg"></file>
<file source="examples/2015Vision/SampleImages/image5.jpg"
destination="SampleImages/image5.jpg"></file>
<file source="examples/2015Vision/SampleImages/image6.jpg"
destination="SampleImages/image6.jpg"></file>
<file source="examples/2015Vision/SampleImages/image7.jpg"
destination="SampleImages/image7.jpg"></file>
<file source="examples/2015Vision/SampleImages/image8.jpg"
destination="SampleImages/image8.jpg"></file>
<file source="examples/2015Vision/SampleImages/image9.jpg"
destination="SampleImages/image9.jpg"></file>
<file source="examples/2015Vision/SampleImages/image10.jpg"
destination="SampleImages/image10.jpg"></file>
<file source="examples/2015Vision/SampleImages/image11.jpg"
destination="SampleImages/image11.jpg"></file>
<file source="examples/2015Vision/SampleImages/image12.jpg"
destination="SampleImages/image12.jpg"></file>
<file source="examples/2015Vision/SampleImages/image13.jpg"
destination="SampleImages/image13.jpg"></file>
<file source="examples/2015Vision/SampleImages/image14.jpg"
destination="SampleImages/image14.jpg"></file>
<file source="examples/2015Vision/SampleImages/image15.jpg"
destination="SampleImages/image15.jpg"></file>
<file source="examples/2015Vision/SampleImages/image16.jpg"
destination="SampleImages/image16.jpg"></file>
<file source="examples/2015Vision/SampleImages/image17.jpg"
destination="SampleImages/image17.jpg"></file>
<file source="examples/2015Vision/SampleImages/image18.jpg"
destination="SampleImages/image18.jpg"></file>
<file source="examples/2015Vision/SampleImages/image19.jpg"
destination="SampleImages/image19.jpg"></file>
<file source="examples/2015Vision/SampleImages/image20.jpg"
destination="SampleImages/image20.jpg"></file>
<file source="examples/2015Vision/SampleImages/IMG_1800.png"
destination="SampleImages/IMG_1800.png"></file>
</files>
</example>
@@ -402,53 +359,10 @@
</tags>
<packages>
<package>src/$package-dir</package>
<package>SampleImages</package>
</packages>
<files>
<file source="examples/2015Vision/Retro_src/Robot.java"
destination="src/$package-dir/Robot.java"></file>
<file source="examples/2015Vision/SampleImages/image.jpg"
destination="SampleImages/image.jpg"></file>
<file source="examples/2015Vision/SampleImages/image2.jpg"
destination="SampleImages/image2.jpg"></file>
<file source="examples/2015Vision/SampleImages/image3.jpg"
destination="SampleImages/image3.jpg"></file>
<file source="examples/2015Vision/SampleImages/image4.jpg"
destination="SampleImages/image4.jpg"></file>
<file source="examples/2015Vision/SampleImages/image5.jpg"
destination="SampleImages/image5.jpg"></file>
<file source="examples/2015Vision/SampleImages/image6.jpg"
destination="SampleImages/image6.jpg"></file>
<file source="examples/2015Vision/SampleImages/image7.jpg"
destination="SampleImages/image7.jpg"></file>
<file source="examples/2015Vision/SampleImages/image8.jpg"
destination="SampleImages/image8.jpg"></file>
<file source="examples/2015Vision/SampleImages/image9.jpg"
destination="SampleImages/image9.jpg"></file>
<file source="examples/2015Vision/SampleImages/image10.jpg"
destination="SampleImages/image10.jpg"></file>
<file source="examples/2015Vision/SampleImages/image11.jpg"
destination="SampleImages/image11.jpg"></file>
<file source="examples/2015Vision/SampleImages/image12.jpg"
destination="SampleImages/image12.jpg"></file>
<file source="examples/2015Vision/SampleImages/image13.jpg"
destination="SampleImages/image13.jpg"></file>
<file source="examples/2015Vision/SampleImages/image14.jpg"
destination="SampleImages/image14.jpg"></file>
<file source="examples/2015Vision/SampleImages/image15.jpg"
destination="SampleImages/image15.jpg"></file>
<file source="examples/2015Vision/SampleImages/image16.jpg"
destination="SampleImages/image16.jpg"></file>
<file source="examples/2015Vision/SampleImages/image17.jpg"
destination="SampleImages/image17.jpg"></file>
<file source="examples/2015Vision/SampleImages/image18.jpg"
destination="SampleImages/image18.jpg"></file>
<file source="examples/2015Vision/SampleImages/image19.jpg"
destination="SampleImages/image19.jpg"></file>
<file source="examples/2015Vision/SampleImages/image20.jpg"
destination="SampleImages/image20.jpg"></file>
<file source="examples/2015Vision/SampleImages/IMG_1800.png"
destination="SampleImages/IMG_1800.png"></file>
</files>
</example>