-
Notifications
You must be signed in to change notification settings - Fork 0
/
objectsrecogfilter.cpp
287 lines (235 loc) · 8.11 KB
/
objectsrecogfilter.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
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
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
#include "objectsrecogfilter.h"
#include <QDir>
#include <QDebug>
#include "private/qvideoframe_p.h"
#include "auxutils.h"
ObjectsRecogFilter::ObjectsRecogFilter()
{
connect(this, SIGNAL(runTensorFlow(QImage)), this, SLOT(TensorFlowExecution(QImage)));
connect(&tft,SIGNAL(results(int, QStringList, QList<double>, QList<QRectF>, double)),this,SLOT(processResults(int, QStringList, QList<double>, QList<QRectF>, double)));
releaseRunning();
initialized = false;
emit initializedChanged(initialized);
}
void ObjectsRecogFilter::setCameraOrientation(double o)
{
camOrientation = o;
}
void ObjectsRecogFilter::setVideoOrientation(double o)
{
vidOrientation = o;
}
double ObjectsRecogFilter::getCameraOrientation()
{
return camOrientation;
}
double ObjectsRecogFilter::getVideoOrientation()
{
return vidOrientation;
}
bool ObjectsRecogFilter::getRunning()
{
QMutexLocker locker(&mutex);
bool val = running;
if (!val) setRunning(true);
return !val;
}
void ObjectsRecogFilter::setRunning(bool val)
{
running = val;
}
double ObjectsRecogFilter::getMinConfidence() const
{
return minConf;
}
void ObjectsRecogFilter::setMinConfidence(double value)
{
minConf = value;
tf.setThreshold(minConf);
}
void ObjectsRecogFilter::releaseRunning()
{
QMutexLocker locker(&mutex);
setRunning(false);
}
QSize ObjectsRecogFilter::getContentSize() const
{
return videoSize;
}
void ObjectsRecogFilter::setContentSize(const QSize &value)
{
videoSize = value;
}
QVideoFilterRunnable *ObjectsRecogFilter::createFilterRunnable()
{
rfr = new ObjectsRecogFilterRunable(this,tf.getResults());
return rfr;
}
ObjectsRecogFilterRunable::ObjectsRecogFilterRunable(ObjectsRecogFilter *filter, QStringList res)
{
m_filter = filter;
results = res;
}
void ObjectsRecogFilterRunable::setResults(int net, QStringList res, QList<double> conf, QList<QRectF> box, double time)
{
network = net;
results = res;
confidence = conf;
boxes = box;
infTime = time;
}
QVideoFrame ObjectsRecogFilterRunable::run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, RunFlags flags)
{
Q_UNUSED(surfaceFormat);
Q_UNUSED(flags);
QImage img;
bool mirrorHorizontal;
bool mirrorVertical = false;
if(input->isValid())
{
// Get image from video frame, we need to convert it
// for unsupported QImage formats, i.e Format_YUV420P
//
// When input has an unsupported format the QImage
// default format is ARGB32
//
// NOTE: BGR images are not properly managed by qt_imageFromVideoFrame
//
bool BGRVideoFrame = AuxUtils::isBGRvideoFrame(*input);
if (BGRVideoFrame)
{
input->map(QAbstractVideoBuffer::ReadOnly);
img = QImage(input->bits(),input->width(),input->height(),QImage::Format_ARGB32).copy();
input->unmap();
// WARNING: Mirror only for Android? How to check if this has to be done?
// surfaceFormat.isMirrored() == false for Android
mirrorVertical = true;
}
else img = qt_imageFromVideoFrame(*input);
// Check if mirroring is needed
if (!mirrorVertical) mirrorVertical = surfaceFormat.isMirrored();
mirrorHorizontal = surfaceFormat.scanLineDirection() == QVideoSurfaceFormat::BottomToTop;
img = img.mirrored(mirrorHorizontal,mirrorVertical);
// Check img is valid
if (img.format() != QImage::Format_Invalid)
{
// Take into account the rotation
img = AuxUtils::rotateImage(img,-m_filter->getVideoOrientation());
// Content size
QRectF srcRect = AuxUtils::frameMatchImg(img,m_filter->getContentSize());
QString text = "";
// If not initialized, intialize with image size
if (!m_filter->getInitialized())
{
m_filter->init(img.height(),img.width());
results.clear();
confidence.clear();
boxes.clear();
infTime = -1;
}
else if (m_filter->getImgHeight() != img.height() ||
m_filter->getImgWidth() != img.width())
// If image size changed, initialize input tensor
m_filter->initInput(img.height(),img.width());
// Get a mutex for creating a thread to execute TensorFlow
if (m_filter->getRunning())
emit m_filter->runTensorFlow(img);
// Image classification network
if (network == Tensorflow::knIMAGE_CLASSIFIER)
{
// Get current TensorFlow outputs
QString objStr = results.count()>0 ? results.first() : "";
double objCon = confidence.count()>0 ? confidence.first() : -1;
// Check if there are results & the minimum confidence level is reached
if (objStr.length()>0 && objCon >= m_filter->getMinConfidence())
{
// Formatting of confidence value
QString confVal = QString::number(objCon * 100, 'f', 2) + " %";
// Text
text = objStr + '\n' + confVal + '\n';
}
}
// Object detection network
else if (network == Tensorflow::knOBJECT_DETECTION)
{
// Draw boxes on image
img = AuxUtils::drawBoxes(img,img.rect(),results,confidence,boxes,m_filter->getMinConfidence(),!BGRVideoFrame);
}
// Show inference time
if (m_filter->getShowTime() && infTime>0)
text = text + QString::number(infTime) + " ms";
if (!text.isEmpty())
img = AuxUtils::drawText(img,srcRect,text);
// Restore rotation
img = AuxUtils::rotateImage(img,m_filter->getVideoOrientation());
}
// NOTE: for BGR images loaded as RGB
if (BGRVideoFrame) img = img.rgbSwapped();
// Return video frame from img
return QVideoFrame(img);
}
return *input;
}
double ObjectsRecogFilter::getImgHeight() const
{
return tf.getImgHeight();
}
double ObjectsRecogFilter::getImgWidth() const
{
return tf.getImgWidth();
}
bool ObjectsRecogFilter::getInitialized() const
{
return initialized;
}
QString ObjectsRecogFilter::getModel() const
{
return kindNetwork;
}
// TODO: set modelType literals as constant values,
// they are defined in AppSettingsPage.qml
void ObjectsRecogFilter::setModel(const QString &value)
{
const QString MODEL_FILE_IMG_CLA = "imageClassification.pb";
const QString MODEL_FILE_OBJ_DET = "object_detection.pb";
const QString LABELS_FILE_IMG_CLA = "imageClassificationLabels.txt";
const QString LABELS_FILE_OBJ_DET = "object_detection_labels.txt";
QString assetsPath = AuxUtils::getAssetsPath();
QString modelFilename;
QString labelsFilename;
kindNetwork = value;
modelFilename = kindNetwork == "ImageClassification" ? MODEL_FILE_IMG_CLA : MODEL_FILE_OBJ_DET;
labelsFilename = assetsPath + QDir::separator() + (kindNetwork == "ImageClassification" ? LABELS_FILE_IMG_CLA : LABELS_FILE_OBJ_DET);
tf.setModelFilename(AuxUtils::resolveModelFilePath(modelFilename));
tf.setLabelsFilename(labelsFilename);
initialized = false;
emit initializedChanged(initialized);
tft.setTf(&tf);
}
bool ObjectsRecogFilter::getShowTime() const
{
return showInfTime;
}
void ObjectsRecogFilter::setShowTime(bool value)
{
showInfTime = value;
}
void ObjectsRecogFilter::init(int imgHeight, int imgWidth)
{
initialized = tf.init(imgHeight,imgWidth);
emit initializedChanged(initialized);
tft.setTf(&tf);
}
void ObjectsRecogFilter::initInput(int imgHeight, int imgWidth)
{
tf.initInput(imgHeight,imgWidth);
}
void ObjectsRecogFilter::TensorFlowExecution(QImage imgTF)
{
tft.run(imgTF);
}
void ObjectsRecogFilter::processResults(int network, QStringList res, QList<double> conf, QList<QRectF> boxes, double time)
{
rfr->setResults(network,res,conf,boxes,time);
releaseRunning();
}