blob: 83d37c6e4cb8da2eed3fba5a2f8cb11ebfbbe8fd [file] [log] [blame]
jerrymf1579332013-02-07 01:56:28 +00001/*----------------------------------------------------------------------------*/
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 */
11IMAQ_FUNC int Priv_SetWriteFileAllowed(UINT32 enable);
12
13BinaryImage::BinaryImage() : MonoImage()
14{
15}
16
17BinaryImage::~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 */
25int 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 */
39ParticleAnalysisReport 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 */
53void 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 */
102vector<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 */
123void 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 */
145bool 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 */
162bool 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]
171double 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 */
183bool BinaryImage::CompareParticleSizes(ParticleAnalysisReport particle1, ParticleAnalysisReport particle2)
184{
185 //we want descending sort order
186 return particle1.particleToImagePercent > particle2.particleToImagePercent;
187}
188
189BinaryImage *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
197BinaryImage *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
205BinaryImage *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
213BinaryImage *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