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