-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathImageProcessor.cpp
More file actions
254 lines (198 loc) · 6.71 KB
/
Copy pathImageProcessor.cpp
File metadata and controls
254 lines (198 loc) · 6.71 KB
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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/**------------------------------------------------------------------------
* All Rights Reserved
* Author: Diego Macrini
*-----------------------------------------------------------------------*/
#include <RootHeader.h>
#include "ImageProcessor.h"
#include "VSCGraph.h"
#include <Tools/UserArguments.h>
#include <Tools/UserEvents.h>
#include <Tools/CvMatView.h>
#include <VideoParserGUI/DrawingUtils.h>
using namespace vpl;
extern UserArguments g_userArgs;
void ImageProcessor::ReadParamsFromUserArguments()
{
VisSysComponent::ReadParamsFromUserArguments();
g_userArgs.ReadArg(Name(), "bufferSize", "Number of "
"previous frames stored. Set >= 1 for motion detection",
8u, &m_params.maxBufferSize);
g_userArgs.ReadArg(Name(), "darkPixelValue",
"Pixel value that is considered the begining of darkness",
50.0f, &m_params.darkPixelValue);
g_userArgs.ReadArg(Name(), "darknessThreshold",
"Level of darkness (1 == complete black) at which tracking is suspended",
0.7, &m_params.darknessThreshold);
g_userArgs.ReadArg(Name(), "pixelDiffThreshold",
"Minimum intensity difference to consider that a pixel is noisy "
"(for anti-noise mode only)", 20.0, &m_params.pixelDiffThreshold);
g_userArgs.ReadArg(Name(), "maxTolerableNoiseLevel",
"Maximum image noise level [0,1] that does not activate noise mode "
"(for anti-noise mode only)", 0.01, &m_params.maxTolerableNoiseLevel);
}
void ImageProcessor::Initialize(graph::node v)
{
VisSysComponent::Initialize(v);
m_stats.Clear();
// Make sure that this component runs in all modes
//SetRunningMode(ALL_RUNNING_MODES);
}
//!
double ImageProcessor::ComputeDarknessLevel(FloatImg img) const
{
unsigned level = 0;
for (auto it = img.begin(); it != img.end(); ++it)
{
if (*it <= m_params.darkPixelValue)
level++;
}
return double(level) / img.size();
}
//!
double ImageProcessor::ComputeNoiseLevel(FloatImg img, FloatImg meanImg) const
{
unsigned similarPixelCount = 0;
// Compare the mean image with the true current image
for (auto it0 = meanImg.begin(), it1 = img.begin();
it0 != meanImg.end(); ++it0, ++it1)
{
if (fabs(*it0 - *it1) <= m_params.pixelDiffThreshold)
similarPixelCount++;
}
return 1 - double(similarPixelCount) / meanImg.size();
}
void ImageProcessor::Run()
{
// Delete elements from the end if list is too long
if (m_imgBuffer.size() > m_params.maxBufferSize)
m_imgBuffer.pop_back();
// Get the current images from the container graph
const VSCGraph* pG = static_cast<const VSCGraph*>(ContainerGraph());
const InputImageInfo& iii = pG->GetInputImageInfo();
std::cout << "Frame number: " << iii.frameNumber << std::endl;
m_imgBuffer.push_front(iii);
// See if the current frame is too dark or not
m_stats.darknessLevel = ComputeDarknessLevel(iii.greyFrame);
// When is offtime the image might be noisy when is not too dark. So,
// remove noise and enhance the info by averaging the last frames.
if (!IsTooDark() && IsOfftime() && m_imgBuffer.size() >= 2)
SetAntiNoiseMode(true);
// Note: the anti-noise mode is set above but also can be set by other components
// in previous passes, because it's a shared variable of the vision system.
if (AntiNoiseMode())
{
// Create a new "mean" image and keep the original current one,
// so that both can be compared.
FloatImg meanImg(iii.greyFrame.ni(), iii.greyFrame.nj());
meanImg.fill(0);
for (auto it = m_imgBuffer.begin(); it != m_imgBuffer.end(); ++it)
{
auto srcIt = it->greyFrame.begin();
auto tgtIt = meanImg.begin();
for (; tgtIt != meanImg.end(); ++tgtIt, ++srcIt)
*tgtIt += *srcIt;
}
for (auto it = meanImg.begin(); it != meanImg.end(); ++it)
*it /= m_imgBuffer.size();
// Compute the noise level based on the mean image
m_stats.noiseLevel = ComputeNoiseLevel(iii.greyFrame, meanImg);
if (IsNoisy())
{
// Recompute the darkness level
m_stats.darknessLevel = ComputeDarknessLevel(meanImg);
m_imgBuffer.front().greyFrame = meanImg;
}
else
{
SetAntiNoiseMode(false);
}
}
else
{
// By default, the noise level is zero
m_stats.noiseLevel = 0;
}
}
/*!
This function is called when the left mouse botton and
the mouse pointer was on the component's view.
@return zero if the even was not dealt with and 1 otherwise.
*/
bool ImageProcessor::OnGUIEvent(const UserEventInfo& uei)
{
unsigned x = (unsigned)uei.coord.x;
unsigned y = (unsigned)uei.coord.y;
if (x >= GetRGBImage().ni())
x = (GetRGBImage().ni() > 0) ? GetRGBImage().ni() - 1 : 0;
if (y >= GetRGBImage().nj())
y = (GetRGBImage().nj() > 0) ? GetRGBImage().nj() - 1 : 0;
if (uei.id == EVENT_MOUSE_PUSH)
{
UIBoundingBox bbox(x, x, y, y, false); // coords are not regularized
GetROISequence().push_back(bbox);
}
else if (uei.id == EVENT_MOUSE_DRAG)
{
GetROISequence().back().xmax = x;
GetROISequence().back().ymax = y;
}
return true;
}
void ImageProcessor::GetDisplayInfo(const DisplayInfoIn& dii, DisplayInfoOut& dio) const
{
if (m_imgBuffer.empty())
return;
std::ostringstream oss;
if (dii.outputIdx == 0)
{
dio.imageType = RGB_IMAGE;
dio.imagePtr = ConvertToBaseImgPtr(m_imgBuffer.front().rgbFrame);
if (IsTooDark())
oss << "The image is too dark.";
}
else if (dii.outputIdx == 1)
{
dio.imageType = FLOAT_IMAGE;
dio.imagePtr = ConvertToBaseImgPtr(m_imgBuffer.front().greyFrame);
oss << "Image noise level: " << m_stats.noiseLevel << "\n";
oss << "Darkness level: " << m_stats.darknessLevel;
}
else if (dii.outputIdx == 2 && !GetROISequence().empty())
{
unsigned roiIdx = (unsigned)dii.params[0];
RGBImg img = m_imgBuffer.front().rgbFrame;
ByteImg mask(img.ni(), img.nj());
mask.fill(0);
GetROISequence().FillMask(roiIdx, mask);
dio.imageType = BYTE_IMAGE;
dio.imagePtr = ConvertToBaseImgPtr(mask);
}
if (!GetROISequence().empty())
{
auto ra = GetROISequence();
for (auto it = ra.begin(); it != ra.end(); ++it)
oss << Tuple<unsigned, 4>(it->xmin, it->xmax, it->ymin, it->ymax) << ' ';
}
// Set the draggable property to fase so that the FL_DRAG event is sent to the component
dio.specs.draggableContent = false;
// Images should not be zoomed
dio.specs.zoomableContent = false;
dio.message = oss.str();
}
/*!
Draws the output of the component. This function is called from
a "drawing" thread, which is different from the "processing" thread
that calls Run(). In order to protect the shared resources between the
threads, a mutex is used.
*/
void ImageProcessor::Draw(const DisplayInfoIn& dii) const
{
// Don't draw ROI when when showing masks
if (dii.outputIdx == 2 || m_imgBuffer.empty())
return;
const ROISequence& roiSequence = m_imgBuffer.front().roiSequence;
for (auto it = roiSequence.begin(); it != roiSequence.end(); ++it)
{
DrawSelection(Point(it->xmin, it->ymin), Point(it->xmax, it->ymax));
}
}