2015 Color and Retroreflective vision samples for C++ and Java
Change-Id: Id95925ced100b25d591c40995bb016780737312d
@@ -0,0 +1,212 @@
|
||||
package $package;
|
||||
|
||||
import java.lang.Math;
|
||||
import java.util.Comparator;
|
||||
import java.util.Vector;
|
||||
|
||||
import com.ni.vision.NIVision;
|
||||
import com.ni.vision.NIVision.Image;
|
||||
import com.ni.vision.NIVision.ImageType;
|
||||
|
||||
import edu.wpi.first.wpilibj.CameraServer;
|
||||
import edu.wpi.first.wpilibj.SampleRobot;
|
||||
import edu.wpi.first.wpilibj.Timer;
|
||||
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
||||
|
||||
/**
|
||||
* Example of finding yellow totes based on color.
|
||||
* This example utilizes an image file, which you need to copy to the roboRIO
|
||||
* To use a camera you will have to integrate the appropriate camera details with this example.
|
||||
* 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.
|
||||
*/
|
||||
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 BoundingRectLeft;
|
||||
double BoundingRectTop;
|
||||
double BoundingRectRight;
|
||||
double BoundingRectBottom;
|
||||
|
||||
public int compareTo(ParticleReport r)
|
||||
{
|
||||
return (int)(r.Area - this.Area);
|
||||
}
|
||||
|
||||
public int compare(ParticleReport r1, ParticleReport r2)
|
||||
{
|
||||
return (int)(r1.Area - r2.Area);
|
||||
}
|
||||
};
|
||||
|
||||
//Structure to represent the scores for the various tests used for target identification
|
||||
public class Scores {
|
||||
double Area;
|
||||
double Aspect;
|
||||
};
|
||||
|
||||
//Images
|
||||
Image frame;
|
||||
Image binaryFrame;
|
||||
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
|
||||
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
|
||||
double SCORE_MIN = 75.0; //Minimum score to be considered a tote
|
||||
double VIEW_ANGLE = 49.4; //View angle fo camera, set to Axis m1011 by default, 64 for m1013, 51.7 for 206, 52 for HD3000 square, 60 for HD3000 640x480
|
||||
NIVision.ParticleFilterCriteria2 criteria[] = new NIVision.ParticleFilterCriteria2[1];
|
||||
NIVision.ParticleFilterOptions2 filterOptions = new NIVision.ParticleFilterOptions2(0,0,1,1);
|
||||
Scores scores = new Scores();
|
||||
|
||||
public void robotInit() {
|
||||
// create images
|
||||
frame = NIVision.imaqCreateImage(ImageType.IMAGE_RGB, 0);
|
||||
binaryFrame = NIVision.imaqCreateImage(ImageType.IMAGE_U8, 0);
|
||||
criteria[0] = new NIVision.ParticleFilterCriteria2(NIVision.MeasurementType.MT_AREA_BY_IMAGE_AREA, AREA_MINIMUM, 100.0, 0, 0);
|
||||
|
||||
//Put default values to SmartDashboard so fields will appear
|
||||
SmartDashboard.putNumber("Tote hue min", TOTE_HUE_RANGE.minValue);
|
||||
SmartDashboard.putNumber("Tote hue max", TOTE_HUE_RANGE.maxValue);
|
||||
SmartDashboard.putNumber("Tote sat min", TOTE_SAT_RANGE.minValue);
|
||||
SmartDashboard.putNumber("Tote sat max", TOTE_SAT_RANGE.maxValue);
|
||||
SmartDashboard.putNumber("Tote val min", TOTE_VAL_RANGE.minValue);
|
||||
SmartDashboard.putNumber("Tote val max", TOTE_VAL_RANGE.maxValue);
|
||||
SmartDashboard.putNumber("Area min %", AREA_MINIMUM);
|
||||
}
|
||||
|
||||
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
|
||||
//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");
|
||||
|
||||
//Update threshold values from SmartDashboard. For performance reasons it is recommended to remove this after calibration is finished.
|
||||
TOTE_HUE_RANGE.minValue = (int)SmartDashboard.getNumber("Tote hue min", TOTE_HUE_RANGE.minValue);
|
||||
TOTE_HUE_RANGE.maxValue = (int)SmartDashboard.getNumber("Tote hue max", TOTE_HUE_RANGE.maxValue);
|
||||
TOTE_SAT_RANGE.minValue = (int)SmartDashboard.getNumber("Tote sat min", TOTE_SAT_RANGE.minValue);
|
||||
TOTE_SAT_RANGE.maxValue = (int)SmartDashboard.getNumber("Tote sat max", TOTE_SAT_RANGE.maxValue);
|
||||
TOTE_VAL_RANGE.minValue = (int)SmartDashboard.getNumber("Tote val min", TOTE_VAL_RANGE.minValue);
|
||||
TOTE_VAL_RANGE.maxValue = (int)SmartDashboard.getNumber("Tote val max", TOTE_VAL_RANGE.maxValue);
|
||||
|
||||
//Threshold the image looking for yellow (tote color)
|
||||
NIVision.imaqColorThreshold(binaryFrame, frame, 255, NIVision.ColorMode.HSV, TOTE_HUE_RANGE, TOTE_SAT_RANGE, TOTE_VAL_RANGE);
|
||||
|
||||
//Send particle count to dashboard
|
||||
int numParticles = NIVision.imaqCountParticles(binaryFrame, 1);
|
||||
SmartDashboard.putNumber("Masked particles", numParticles);
|
||||
|
||||
//Send masked image to dashboard to assist in tweaking mask.
|
||||
CameraServer.getInstance().setImage(binaryFrame);
|
||||
|
||||
//filter out small particles
|
||||
float areaMin = (float)SmartDashboard.getNumber("Area min %", AREA_MINIMUM);
|
||||
criteria[0].lower = areaMin;
|
||||
imaqError = NIVision.imaqParticleFilter4(binaryFrame, binaryFrame, criteria, filterOptions, null);
|
||||
|
||||
//Send particle count after filtering to dashboard
|
||||
numParticles = NIVision.imaqCountParticles(binaryFrame, 1);
|
||||
SmartDashboard.putNumber("Filtered particles", numParticles);
|
||||
|
||||
if(numParticles > 0)
|
||||
{
|
||||
//Measure particles and sort by particle size
|
||||
Vector<ParticleReport> particles = new Vector<ParticleReport>();
|
||||
for(int particleIndex = 0; particleIndex < numParticles; particleIndex++)
|
||||
{
|
||||
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.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);
|
||||
par.BoundingRectRight = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_BOUNDING_RECT_RIGHT);
|
||||
particles.add(par);
|
||||
}
|
||||
particles.sort(null);
|
||||
|
||||
//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;
|
||||
|
||||
//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)));
|
||||
} else {
|
||||
SmartDashboard.putBoolean("IsTote", false);
|
||||
}
|
||||
|
||||
Timer.delay(0.005); // wait for a motor update time
|
||||
}
|
||||
}
|
||||
|
||||
public void operatorControl() {
|
||||
while(isOperatorControl() && isEnabled()) {
|
||||
Timer.delay(0.005); // wait for a motor update time
|
||||
}
|
||||
}
|
||||
|
||||
//Comparator function for sorting particles. Returns true if particle 1 is larger
|
||||
static boolean CompareParticleSizes(ParticleReport particle1, ParticleReport particle2)
|
||||
{
|
||||
//we want descending sort order
|
||||
return particle1.PercentAreaToImageArea > particle2.PercentAreaToImageArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a ratio with ideal value of 1 to a score. The resulting function is piecewise
|
||||
* linear going from (0,0) to (1,100) to (2,0) and is 0 for all inputs outside the range 0-2
|
||||
*/
|
||||
double ratioToScore(double ratio)
|
||||
{
|
||||
return (Math.max(0, Math.min(100*(1-Math.abs(1-ratio)), 100)));
|
||||
}
|
||||
|
||||
double AreaScore(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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
double AspectScore(ParticleReport report)
|
||||
{
|
||||
return ratioToScore(((report.BoundingRectRight-report.BoundingRectLeft)/(report.BoundingRectBottom-report.BoundingRectTop)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the estimated distance to a target using the width of the particle in the image. For more information and graphics
|
||||
* showing the math behind this approach see the Vision Processing section of the ScreenStepsLive documentation.
|
||||
*
|
||||
* @param image The image to use for measuring the particle estimated rectangle
|
||||
* @param report The Particle Analysis Report for the particle
|
||||
* @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 normalizedWidth, targetWidth;
|
||||
NIVision.GetImageSizeResult size;
|
||||
|
||||
size = NIVision.imaqGetImageSize(image);
|
||||
normalizedWidth = 2*(report.BoundingRectRight - report.BoundingRectLeft)/size.width;
|
||||
targetWidth = 7;
|
||||
|
||||
return targetWidth/(normalizedWidth*12*Math.tan(VIEW_ANGLE*Math.PI/(180*2)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
package $package;
|
||||
|
||||
import java.lang.Math;
|
||||
import java.util.Comparator;
|
||||
import java.util.Vector;
|
||||
|
||||
import com.ni.vision.NIVision;
|
||||
import com.ni.vision.NIVision.Image;
|
||||
import com.ni.vision.NIVision.ImageType;
|
||||
|
||||
import edu.wpi.first.wpilibj.CameraServer;
|
||||
import edu.wpi.first.wpilibj.SampleRobot;
|
||||
import edu.wpi.first.wpilibj.Timer;
|
||||
import edu.wpi.first.wpilibj.smartdashboard.SmartDashboard;
|
||||
|
||||
/**
|
||||
* Example of finding yellow totes based on retroreflective target.
|
||||
* This example utilizes an image file, which you need to copy to the roboRIO
|
||||
* To use a camera you will have to integrate the appropriate camera details with this example.
|
||||
* 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.
|
||||
*/
|
||||
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 BoundingRectLeft;
|
||||
double BoundingRectTop;
|
||||
double BoundingRectRight;
|
||||
double BoundingRectBottom;
|
||||
|
||||
public int compareTo(ParticleReport r)
|
||||
{
|
||||
return (int)(r.Area - this.Area);
|
||||
}
|
||||
|
||||
public int compare(ParticleReport r1, ParticleReport r2)
|
||||
{
|
||||
return (int)(r1.Area - r2.Area);
|
||||
}
|
||||
};
|
||||
|
||||
//Structure to represent the scores for the various tests used for target identification
|
||||
public class Scores {
|
||||
double Area;
|
||||
double Aspect;
|
||||
};
|
||||
|
||||
//Images
|
||||
Image frame;
|
||||
Image binaryFrame;
|
||||
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
|
||||
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
|
||||
double SCORE_MIN = 75.0; //Minimum score to be considered a tote
|
||||
double VIEW_ANGLE = 49.4; //View angle fo camera, set to Axis m1011 by default, 64 for m1013, 51.7 for 206, 52 for HD3000 square, 60 for HD3000 640x480
|
||||
NIVision.ParticleFilterCriteria2 criteria[] = new NIVision.ParticleFilterCriteria2[1];
|
||||
NIVision.ParticleFilterOptions2 filterOptions = new NIVision.ParticleFilterOptions2(0,0,1,1);
|
||||
Scores scores = new Scores();
|
||||
|
||||
public void robotInit() {
|
||||
// create images
|
||||
frame = NIVision.imaqCreateImage(ImageType.IMAGE_RGB, 0);
|
||||
binaryFrame = NIVision.imaqCreateImage(ImageType.IMAGE_U8, 0);
|
||||
criteria[0] = new NIVision.ParticleFilterCriteria2(NIVision.MeasurementType.MT_AREA_BY_IMAGE_AREA, AREA_MINIMUM, 100.0, 0, 0);
|
||||
|
||||
//Put default values to SmartDashboard so fields will appear
|
||||
SmartDashboard.putNumber("Tote hue min", TOTE_HUE_RANGE.minValue);
|
||||
SmartDashboard.putNumber("Tote hue max", TOTE_HUE_RANGE.maxValue);
|
||||
SmartDashboard.putNumber("Tote sat min", TOTE_SAT_RANGE.minValue);
|
||||
SmartDashboard.putNumber("Tote sat max", TOTE_SAT_RANGE.maxValue);
|
||||
SmartDashboard.putNumber("Tote val min", TOTE_VAL_RANGE.minValue);
|
||||
SmartDashboard.putNumber("Tote val max", TOTE_VAL_RANGE.maxValue);
|
||||
SmartDashboard.putNumber("Area min %", AREA_MINIMUM);
|
||||
}
|
||||
|
||||
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
|
||||
//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");
|
||||
|
||||
//Update threshold values from SmartDashboard. For performance reasons it is recommended to remove this after calibration is finished.
|
||||
TOTE_HUE_RANGE.minValue = (int)SmartDashboard.getNumber("Tote hue min", TOTE_HUE_RANGE.minValue);
|
||||
TOTE_HUE_RANGE.maxValue = (int)SmartDashboard.getNumber("Tote hue max", TOTE_HUE_RANGE.maxValue);
|
||||
TOTE_SAT_RANGE.minValue = (int)SmartDashboard.getNumber("Tote sat min", TOTE_SAT_RANGE.minValue);
|
||||
TOTE_SAT_RANGE.maxValue = (int)SmartDashboard.getNumber("Tote sat max", TOTE_SAT_RANGE.maxValue);
|
||||
TOTE_VAL_RANGE.minValue = (int)SmartDashboard.getNumber("Tote val min", TOTE_VAL_RANGE.minValue);
|
||||
TOTE_VAL_RANGE.maxValue = (int)SmartDashboard.getNumber("Tote val max", TOTE_VAL_RANGE.maxValue);
|
||||
|
||||
//Threshold the image looking for yellow (tote color)
|
||||
NIVision.imaqColorThreshold(binaryFrame, frame, 255, NIVision.ColorMode.HSV, TOTE_HUE_RANGE, TOTE_SAT_RANGE, TOTE_VAL_RANGE);
|
||||
|
||||
//Send particle count to dashboard
|
||||
int numParticles = NIVision.imaqCountParticles(binaryFrame, 1);
|
||||
SmartDashboard.putNumber("Masked particles", numParticles);
|
||||
|
||||
//Send masked image to dashboard to assist in tweaking mask.
|
||||
CameraServer.getInstance().setImage(binaryFrame);
|
||||
|
||||
//filter out small particles
|
||||
float areaMin = (float)SmartDashboard.getNumber("Area min %", AREA_MINIMUM);
|
||||
criteria[0].lower = areaMin;
|
||||
imaqError = NIVision.imaqParticleFilter4(binaryFrame, binaryFrame, criteria, filterOptions, null);
|
||||
|
||||
//Send particle count after filtering to dashboard
|
||||
numParticles = NIVision.imaqCountParticles(binaryFrame, 1);
|
||||
SmartDashboard.putNumber("Filtered particles", numParticles);
|
||||
|
||||
if(numParticles > 0)
|
||||
{
|
||||
//Measure particles and sort by particle size
|
||||
Vector<ParticleReport> particles = new Vector<ParticleReport>();
|
||||
for(int particleIndex = 0; particleIndex < numParticles; particleIndex++)
|
||||
{
|
||||
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.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);
|
||||
par.BoundingRectRight = NIVision.imaqMeasureParticle(binaryFrame, particleIndex, 0, NIVision.MeasurementType.MT_BOUNDING_RECT_RIGHT);
|
||||
particles.add(par);
|
||||
}
|
||||
particles.sort(null);
|
||||
|
||||
//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 this scores and reports information about a single particle (single L shaped target). To get accurate information
|
||||
//about the location of the tote (not just the distance) you will need to correlate two adjacent targets in order to find the true center of the tote.
|
||||
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;
|
||||
|
||||
//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)));
|
||||
} else {
|
||||
SmartDashboard.putBoolean("IsTote", false);
|
||||
}
|
||||
|
||||
Timer.delay(0.005); // wait for a motor update time
|
||||
}
|
||||
}
|
||||
|
||||
public void operatorControl() {
|
||||
while(isOperatorControl() && isEnabled()) {
|
||||
Timer.delay(0.005); // wait for a motor update time
|
||||
}
|
||||
}
|
||||
|
||||
//Comparator function for sorting particles. Returns true if particle 1 is larger
|
||||
static boolean CompareParticleSizes(ParticleReport particle1, ParticleReport particle2)
|
||||
{
|
||||
//we want descending sort order
|
||||
return particle1.PercentAreaToImageArea > particle2.PercentAreaToImageArea;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a ratio with ideal value of 1 to a score. The resulting function is piecewise
|
||||
* linear going from (0,0) to (1,100) to (2,0) and is 0 for all inputs outside the range 0-2
|
||||
*/
|
||||
double ratioToScore(double ratio)
|
||||
{
|
||||
return (Math.max(0, Math.min(100*(1-Math.abs(1-ratio)), 100)));
|
||||
}
|
||||
|
||||
double AreaScore(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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
double AspectScore(ParticleReport report)
|
||||
{
|
||||
return ratioToScore(((report.BoundingRectRight-report.BoundingRectLeft)/(report.BoundingRectBottom-report.BoundingRectTop)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the estimated distance to a target using the width of the particle in the image. For more information and graphics
|
||||
* showing the math behind this approach see the Vision Processing section of the ScreenStepsLive documentation.
|
||||
*
|
||||
* @param image The image to use for measuring the particle estimated rectangle
|
||||
* @param report The Particle Analysis Report for the particle
|
||||
* @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 normalizedWidth, targetWidth;
|
||||
NIVision.GetImageSizeResult size;
|
||||
|
||||
size = NIVision.imaqGetImageSize(image);
|
||||
normalizedWidth = 2*(report.BoundingRectRight - report.BoundingRectLeft)/size.width;
|
||||
targetWidth = 7;
|
||||
|
||||
return targetWidth/(normalizedWidth*12*Math.tan(VIEW_ANGLE*Math.PI/(180*2)));
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 364 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 11 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 16 KiB |
@@ -325,6 +325,132 @@
|
||||
destination="src/$package-dir/Robot.java"></file>
|
||||
</files>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<name>2015 Vision Color Sample</name>
|
||||
<description>An example program that demonstrates image processing to locate Yellow totes by color.
|
||||
This example uses a file which must be copied over to the roboRIO via FTP to demonstrate processing.
|
||||
To use this code with a camera, you must integrate the code for image acquisition from the appropriate
|
||||
camera example;
|
||||
</description>
|
||||
<tags>
|
||||
<tag>Vision</tag>
|
||||
<tag>Complete List</tag>
|
||||
</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>
|
||||
|
||||
<example>
|
||||
<name>2015 Vision Retro Sample</name>
|
||||
<description>An example program that demonstrates image processing to locate Yellow totes by the retroreflective target.
|
||||
This example uses a file which must be copied over to the roboRIO via FTP to demonstrate processing.
|
||||
To use this code with a camera, you must integrate the code for image acquisition from the appropriate
|
||||
camera example;
|
||||
</description>
|
||||
<tags>
|
||||
<tag>Vision</tag>
|
||||
<tag>Complete List</tag>
|
||||
</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>
|
||||
|
||||
<example>
|
||||
<name>Axis Camera Sample</name>
|
||||
|
||||