jerrym | f157933 | 2013-02-07 01:56:28 +0000 | [diff] [blame] | 1 | /*----------------------------------------------------------------------------*/
|
| 2 | /* Copyright (c) FIRST 2008. All Rights Reserved. */
|
| 3 | /* Open Source Software - may be modified and shared by FRC teams. The code */
|
| 4 | /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
|
| 5 | /*----------------------------------------------------------------------------*/
|
| 6 |
|
| 7 | #include "BinaryImage.h"
|
| 8 | #include "WPIErrors.h"
|
| 9 |
|
| 10 | /** Private NI function needed to write to the VxWorks target */
|
| 11 | IMAQ_FUNC int Priv_SetWriteFileAllowed(UINT32 enable);
|
| 12 |
|
| 13 | BinaryImage::BinaryImage() : MonoImage()
|
| 14 | {
|
| 15 | }
|
| 16 |
|
| 17 | BinaryImage::~BinaryImage()
|
| 18 | {
|
| 19 | }
|
| 20 |
|
| 21 | /**
|
| 22 | * Get then number of particles for the image.
|
| 23 | * @returns the number of particles found for the image.
|
| 24 | */
|
| 25 | int BinaryImage::GetNumberParticles()
|
| 26 | {
|
| 27 | int numParticles = 0;
|
| 28 | int success = imaqCountParticles(m_imaqImage, 1, &numParticles);
|
| 29 | wpi_setImaqErrorWithContext(success, "Error counting particles");
|
| 30 | return numParticles;
|
| 31 | }
|
| 32 |
|
| 33 | /**
|
| 34 | * Get a single particle analysis report.
|
| 35 | * Get one (of possibly many) particle analysis reports for an image.
|
| 36 | * @param particleNumber Which particle analysis report to return.
|
| 37 | * @returns the selected particle analysis report
|
| 38 | */
|
| 39 | ParticleAnalysisReport BinaryImage::GetParticleAnalysisReport(int particleNumber)
|
| 40 | {
|
| 41 | ParticleAnalysisReport par;
|
| 42 | GetParticleAnalysisReport(particleNumber, &par);
|
| 43 | return par;
|
| 44 | }
|
| 45 |
|
| 46 | /**
|
| 47 | * Get a single particle analysis report.
|
| 48 | * Get one (of possibly many) particle analysis reports for an image.
|
| 49 | * This version could be more efficient when copying many reports.
|
| 50 | * @param particleNumber Which particle analysis report to return.
|
| 51 | * @param par the selected particle analysis report
|
| 52 | */
|
| 53 | void BinaryImage::GetParticleAnalysisReport(int particleNumber, ParticleAnalysisReport *par)
|
| 54 | {
|
| 55 | int success;
|
| 56 | int numParticles = 0;
|
| 57 |
|
| 58 | success = imaqGetImageSize(m_imaqImage, &par->imageWidth, &par->imageHeight);
|
| 59 | wpi_setImaqErrorWithContext(success, "Error getting image size");
|
| 60 | if (StatusIsFatal())
|
| 61 | return;
|
| 62 |
|
| 63 | success = imaqCountParticles(m_imaqImage, 1, &numParticles);
|
| 64 | wpi_setImaqErrorWithContext(success, "Error counting particles");
|
| 65 | if (StatusIsFatal())
|
| 66 | return;
|
| 67 |
|
| 68 | if (particleNumber >= numParticles)
|
| 69 | {
|
| 70 | wpi_setWPIErrorWithContext(ParameterOutOfRange, "particleNumber");
|
| 71 | return;
|
| 72 | }
|
| 73 |
|
| 74 | par->particleIndex = particleNumber;
|
| 75 | // Don't bother measuring the rest of the particle if one fails
|
| 76 | bool good = ParticleMeasurement(particleNumber, IMAQ_MT_CENTER_OF_MASS_X, &par->center_mass_x);
|
| 77 | good = good && ParticleMeasurement(particleNumber, IMAQ_MT_CENTER_OF_MASS_Y, &par->center_mass_y);
|
| 78 | good = good && ParticleMeasurement(particleNumber, IMAQ_MT_AREA, &par->particleArea);
|
| 79 | good = good && ParticleMeasurement(particleNumber, IMAQ_MT_BOUNDING_RECT_TOP, &par->boundingRect.top);
|
| 80 | good = good && ParticleMeasurement(particleNumber, IMAQ_MT_BOUNDING_RECT_LEFT, &par->boundingRect.left);
|
| 81 | good = good && ParticleMeasurement(particleNumber, IMAQ_MT_BOUNDING_RECT_HEIGHT, &par->boundingRect.height);
|
| 82 | good = good && ParticleMeasurement(particleNumber, IMAQ_MT_BOUNDING_RECT_WIDTH, &par->boundingRect.width);
|
| 83 | good = good && ParticleMeasurement(particleNumber, IMAQ_MT_AREA_BY_IMAGE_AREA, &par->particleToImagePercent);
|
| 84 | good = good && ParticleMeasurement(particleNumber, IMAQ_MT_AREA_BY_PARTICLE_AND_HOLES_AREA, &par->particleQuality);
|
| 85 |
|
| 86 | if (good)
|
| 87 | {
|
| 88 | /* normalized position (-1 to 1) */
|
| 89 | par->center_mass_x_normalized = NormalizeFromRange(par->center_mass_x, par->imageWidth);
|
| 90 | par->center_mass_y_normalized = NormalizeFromRange(par->center_mass_y, par->imageHeight);
|
| 91 | }
|
| 92 | }
|
| 93 |
|
| 94 |
|
| 95 | /**
|
| 96 | * Get an ordered vector of particles for the image.
|
| 97 | * Create a vector of particle analysis reports sorted by size for an image.
|
| 98 | * The vector contains the actual report structures.
|
| 99 | * @returns a pointer to the vector of particle analysis reports. The caller must delete the
|
| 100 | * vector when finished using it.
|
| 101 | */
|
| 102 | vector<ParticleAnalysisReport>* BinaryImage::GetOrderedParticleAnalysisReports()
|
| 103 | {
|
| 104 | vector<ParticleAnalysisReport>* particles = new vector<ParticleAnalysisReport>;
|
| 105 | int particleCount = GetNumberParticles();
|
| 106 | for(int particleIndex = 0; particleIndex < particleCount; particleIndex++)
|
| 107 | {
|
| 108 | particles->push_back(GetParticleAnalysisReport(particleIndex));
|
| 109 | }
|
| 110 | // TODO: This is pretty inefficient since each compare in the sort copies
|
| 111 | // both reports being compared... do it manually instead... while we're
|
| 112 | // at it, we should provide a version that allows a preallocated buffer of
|
| 113 | // ParticleAnalysisReport structures
|
| 114 | sort(particles->begin(), particles->end(), CompareParticleSizes);
|
| 115 | return particles;
|
| 116 | }
|
| 117 |
|
| 118 | /**
|
| 119 | * Write a binary image to flash.
|
| 120 | * Writes the binary image to flash on the cRIO for later inspection.
|
| 121 | * @param fileName the name of the image file written to the flash.
|
| 122 | */
|
| 123 | void BinaryImage::Write(const char *fileName)
|
| 124 | {
|
| 125 | RGBValue colorTable[256];
|
| 126 | Priv_SetWriteFileAllowed(1);
|
| 127 | memset(colorTable, 0, sizeof(colorTable));
|
| 128 | colorTable[0].R = 0;
|
| 129 | colorTable[1].R = 255;
|
| 130 | colorTable[0].G = colorTable[1].G = 0;
|
| 131 | colorTable[0].B = colorTable[1].B = 0;
|
| 132 | colorTable[0].alpha = colorTable[1].alpha = 0;
|
| 133 | imaqWriteFile(m_imaqImage, fileName, colorTable);
|
| 134 | }
|
| 135 |
|
| 136 | /**
|
| 137 | * Measure a single parameter for an image.
|
| 138 | * Get the measurement for a single parameter about an image by calling the imaqMeasureParticle
|
| 139 | * function for the selected parameter.
|
| 140 | * @param particleNumber which particle in the set of particles
|
| 141 | * @param whatToMeasure the imaq MeasurementType (what to measure)
|
| 142 | * @param result the value of the measurement
|
| 143 | * @returns false on failure, true on success
|
| 144 | */
|
| 145 | bool BinaryImage::ParticleMeasurement(int particleNumber, MeasurementType whatToMeasure, int *result)
|
| 146 | {
|
| 147 | double resultDouble;
|
| 148 | bool success = ParticleMeasurement(particleNumber, whatToMeasure, &resultDouble);
|
| 149 | *result = (int)resultDouble;
|
| 150 | return success;
|
| 151 | }
|
| 152 |
|
| 153 | /**
|
| 154 | * Measure a single parameter for an image.
|
| 155 | * Get the measurement for a single parameter about an image by calling the imaqMeasureParticle
|
| 156 | * function for the selected parameter.
|
| 157 | * @param particleNumber which particle in the set of particles
|
| 158 | * @param whatToMeasure the imaq MeasurementType (what to measure)
|
| 159 | * @param result the value of the measurement
|
| 160 | * @returns true on failure, false on success
|
| 161 | */
|
| 162 | bool BinaryImage::ParticleMeasurement(int particleNumber, MeasurementType whatToMeasure, double *result)
|
| 163 | {
|
| 164 | int success;
|
| 165 | success = imaqMeasureParticle(m_imaqImage, particleNumber, 0, whatToMeasure, result);
|
| 166 | wpi_setImaqErrorWithContext(success, "Error measuring particle");
|
| 167 | return !StatusIsFatal();
|
| 168 | }
|
| 169 |
|
| 170 | //Normalizes to [-1,1]
|
| 171 | double BinaryImage::NormalizeFromRange(double position, int range)
|
| 172 | {
|
| 173 | return (position * 2.0 / (double)range) - 1.0;
|
| 174 | }
|
| 175 |
|
| 176 | /**
|
| 177 | * The compare helper function for sort.
|
| 178 | * This function compares two particle analysis reports as a helper for the sort function.
|
| 179 | * @param particle1 The first particle to compare
|
| 180 | * @param particle2 the second particle to compare
|
| 181 | * @returns true if particle1 is greater than particle2
|
| 182 | */
|
| 183 | bool BinaryImage::CompareParticleSizes(ParticleAnalysisReport particle1, ParticleAnalysisReport particle2)
|
| 184 | {
|
| 185 | //we want descending sort order
|
| 186 | return particle1.particleToImagePercent > particle2.particleToImagePercent;
|
| 187 | }
|
| 188 |
|
| 189 | BinaryImage *BinaryImage::RemoveSmallObjects(bool connectivity8, int erosions)
|
| 190 | {
|
| 191 | BinaryImage *result = new BinaryImage();
|
| 192 | int success = imaqSizeFilter(result->GetImaqImage(), m_imaqImage, connectivity8, erosions, IMAQ_KEEP_LARGE, NULL);
|
| 193 | wpi_setImaqErrorWithContext(success, "Error in RemoveSmallObjects");
|
| 194 | return result;
|
| 195 | }
|
| 196 |
|
| 197 | BinaryImage *BinaryImage::RemoveLargeObjects(bool connectivity8, int erosions)
|
| 198 | {
|
| 199 | BinaryImage *result = new BinaryImage();
|
| 200 | int success = imaqSizeFilter(result->GetImaqImage(), m_imaqImage, connectivity8, erosions, IMAQ_KEEP_SMALL, NULL);
|
| 201 | wpi_setImaqErrorWithContext(success, "Error in RemoveLargeObjects");
|
| 202 | return result;
|
| 203 | }
|
| 204 |
|
| 205 | BinaryImage *BinaryImage::ConvexHull(bool connectivity8)
|
| 206 | {
|
| 207 | BinaryImage *result = new BinaryImage();
|
| 208 | int success = imaqConvexHull(result->GetImaqImage(), m_imaqImage, connectivity8);
|
| 209 | wpi_setImaqErrorWithContext(success, "Error in convex hull operation");
|
| 210 | return result;
|
| 211 | }
|
| 212 |
|
| 213 | BinaryImage *BinaryImage::ParticleFilter(ParticleFilterCriteria2 *criteria, int criteriaCount)
|
| 214 | {
|
| 215 | BinaryImage *result = new BinaryImage();
|
| 216 | int numParticles;
|
| 217 | ParticleFilterOptions2 filterOptions = {0, 0, 0, 1};
|
| 218 | int success = imaqParticleFilter4(result->GetImaqImage(), m_imaqImage, criteria, criteriaCount, &filterOptions, NULL, &numParticles);
|
| 219 | wpi_setImaqErrorWithContext(success, "Error in particle filter operation");
|
| 220 | return result;
|
| 221 | }
|
| 222 |
|