Commit 6e844a9c9f2d0cb2b73ca1a184d0099eb01791c0

Authored by Charles Otto
1 parent fbd840a0

Update handling of FTE

If a transform sets FTE on a template, don't pass that on to subsequent
transforms. This is done by placing checks after every project call by stream
and pipe. Switch the FTE marker from metadata to a member variable of template.
openbr/core/core.cpp
... ... @@ -195,13 +195,11 @@ struct AlgorithmCore
195 195 if (fileExclusion)
196 196 outputDesc = "FileExclusion(" + gallery.flat() + ")+";
197 197 outputDesc.append("GalleryOutput("+gallery.flat()+")");
198   - QScopedPointer<Transform> outputTform(Transform::make(outputDesc, NULL));
199   - stages.append(outputTform.data());
200 198 stages.append(progressCounter.data());
201 199  
202 200 QScopedPointer<Transform> pipeline(br::pipeTransforms(stages));
203 201  
204   - QScopedPointer<Transform> stream(br::wrapTransform(pipeline.data(), "Stream(readMode=StreamGallery, endPoint=DiscardTemplates)"));
  202 + QScopedPointer<Transform> stream(br::wrapTransform(pipeline.data(), "Stream(readMode=StreamGallery, endPoint="+outputDesc+"+DiscardTemplates)"));
205 203  
206 204 TemplateList data, output;
207 205 data.append(input);
... ... @@ -479,8 +477,6 @@ struct AlgorithmCore
479 477 // output specification we were passed. Gallery metadata is necessary for some Outputs to function correctly.
480 478 QString outputString = output.flat().isEmpty() ? "Empty" : output.flat();
481 479 QString outputRegionDesc = "Output("+ outputString +"," + targetGallery.flat() +"," + queryGallery.flat() + ","+ QString::number(transposeMode ? 1 : 0) + ")";
482   - QScopedPointer<Transform> outputTForm(Transform::make(outputRegionDesc,NULL));
483   - compareOutput.append(outputTForm.data());
484 480  
485 481 // The ProgressCounter transform will simply provide a display about the number of rows completed.
486 482 compareOutput.append(progressCounter.data());
... ... @@ -491,7 +487,7 @@ struct AlgorithmCore
491 487  
492 488 // Now, we will give that base transform to a stream, which will incrementally read the row gallery
493 489 // and pass the transforms it reads through the base algorithm.
494   - QScopedPointer<Transform> streamWrapper(br::wrapTransform(pipeline, "Stream(readMode=StreamGallery, endPoint=DiscardTemplates)"));
  490 + QScopedPointer<Transform> streamWrapper(br::wrapTransform(pipeline, "Stream(readMode=StreamGallery, endPoint="+outputRegionDesc+"+DiscardTemplates)"));
495 491  
496 492 // We set up a template containing the rowGallery we want to compare.
497 493 TemplateList rowGalleryTemplate;
... ...
openbr/openbr_plugin.cpp
... ... @@ -261,6 +261,7 @@ void File::appendRects(const QList&lt;cv::Rect&gt; &amp;rects)
261 261 /* File - private methods */
262 262 void File::init(const QString &file)
263 263 {
  264 + fte = false;
264 265 name = file;
265 266  
266 267 while (name.endsWith(']') || name.endsWith(')')) {
... ... @@ -287,6 +288,11 @@ void File::init(const QString &amp;file)
287 288 }
288 289 name = name.left(index);
289 290 }
  291 +
  292 + if (contains("FTE")) {
  293 + fte = getBool("FTE");
  294 + remove("FTE");
  295 + }
290 296 }
291 297  
292 298 /* File - global methods */
... ... @@ -367,7 +373,7 @@ int FileList::failures() const
367 373 {
368 374 int failures = 0;
369 375 foreach (const File &file, *this)
370   - if (file.get<bool>("FTO", false) || file.get<bool>("FTE", false))
  376 + if (file.fte)
371 377 failures++;
372 378 return failures;
373 379 }
... ... @@ -1344,7 +1350,7 @@ static void _project(const Transform *transform, const Template *src, Template *
1344 1350 } catch (...) {
1345 1351 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src->file.flat()), qPrintable(transform->objectName()));
1346 1352 *dst = Template(src->file);
1347   - dst->file.set("FTE", true);
  1353 + dst->file.fte = true;
1348 1354 }
1349 1355 }
1350 1356  
... ... @@ -1474,6 +1480,9 @@ float Distance::compare(const Template &amp;a, const Template &amp;b) const
1474 1480  
1475 1481 float Distance::compare(const cv::Mat &a, const cv::Mat &b) const
1476 1482 {
  1483 + if (a.empty() || b.empty() || a.rows != b.rows || a.cols != b.cols || a.elemSize() != b.elemSize())
  1484 + return -std::numeric_limits<float>::max();
  1485 +
1477 1486 return compare(a.data, b.data, a.rows * a.cols * a.elemSize());
1478 1487 }
1479 1488  
... ...
openbr/openbr_plugin.h
... ... @@ -170,7 +170,7 @@ struct BR_EXPORT File
170 170 {
171 171 QString name; /*!< \brief Path to a file on disk. */
172 172  
173   - File() {}
  173 + File() { fte = false; }
174 174 File(const QString &file) { init(file); } /*!< \brief Construct a file from a string. */
175 175 File(const QString &file, const QVariant &label) { init(file); set("Label", label); } /*!< \brief Construct a file from a string and assign a label. */
176 176 File(const char *file) { init(file); } /*!< \brief Construct a file from a c-style string. */
... ... @@ -308,7 +308,7 @@ struct BR_EXPORT File
308 308 return result;
309 309 }
310 310  
311   - inline bool failed() const { return getBool("FTE") || getBool("FTO"); } /*!< \brief Returns \c true if the file failed to open or enroll, \c false otherwise. */
  311 + inline bool failed() const { return fte; } /*!< \brief Returns \c true if the file failed to open or enroll, \c false otherwise. */
312 312  
313 313 QList<QPointF> namedPoints() const; /*!< \brief Returns points convertible from metadata keys. */
314 314 QList<QPointF> points() const; /*!< \brief Returns the file's points list. */
... ... @@ -327,6 +327,7 @@ struct BR_EXPORT File
327 327 inline void setRects(const QList<QRectF> &rects) { clearRects(); appendRects(rects); } /*!< \brief Overwrites the file's rect list. */
328 328 inline void setRects(const QList<cv::Rect> &rects) { clearRects(); appendRects(rects); } /*!< \brief Overwrites the file's rect list. */
329 329  
  330 + bool fte;
330 331 private:
331 332 QVariantMap m_metadata;
332 333 BR_EXPORT friend QDataStream &operator<<(QDataStream &stream, const File &file);
... ... @@ -1295,7 +1296,7 @@ public:
1295 1296 * \brief Return a pointer to a simplified version of this transform (if possible). Transforms which are only active during training should remove
1296 1297 * themselves by either returning their child transforms (where relevant) or returning NULL. Set newTransform to true if the transform returned is newly allocated.
1297 1298 */
1298   - virtual Transform * simplify(bool & newTransform) { newTransform = false; return this; }
  1299 + virtual Transform * simplify(bool &newTransform) { newTransform = false; return this; }
1299 1300  
1300 1301 protected:
1301 1302 Transform(bool independent = true, bool trainable = true); /*!< \brief Construct a transform. */
... ...
openbr/plugins/draw.cpp
... ... @@ -607,7 +607,7 @@ class MeanImageTransform : public TimeVaryingTransform
607 607 cnt++;
608 608 }
609 609  
610   - virtual void finalize(TemplateList & output)
  610 + virtual void finalize(TemplateList &output)
611 611 {
612 612 average /= float(cnt);
613 613 imwrite(QString("%1.%2").arg(imgname).arg(ext).toStdString(), average);
... ...
openbr/plugins/keypoint.cpp
... ... @@ -54,7 +54,7 @@ class KeyPointDetectorTransform : public UntrainableTransform
54 54 featureDetector->detect(src, keyPoints);
55 55 } catch (...) {
56 56 qWarning("Key point detection failed for file %s", qPrintable(src.file.name));
57   - dst.file.set("FTE", true);
  57 + dst.file.fte = true;
58 58 }
59 59  
60 60 QList<Rect> rects;
... ...
openbr/plugins/meta.cpp
... ... @@ -76,8 +76,21 @@ class PipeTransform : public CompositeTransform
76 76  
77 77 void _projectPartial(TemplateList *srcdst, int startIndex, int stopIndex)
78 78 {
79   - for (int i=startIndex; i<stopIndex; i++)
80   - *srcdst >> *transforms[i];
  79 + TemplateList dst = *srcdst;
  80 + TemplateList temp;
  81 + for (int i=startIndex; i<stopIndex; i++) {
  82 + TemplateList temp;
  83 + transforms[i]->project(dst, temp);
  84 +
  85 + dst.clear();
  86 + foreach (const Template &t, *srcdst) {
  87 + if (!t.file.fte)
  88 + dst.append(t);
  89 + else
  90 + srcdst->append(t);
  91 + }
  92 + }
  93 + srcdst->append(dst);
81 94 }
82 95  
83 96 void train(const QList<TemplateList> &data)
... ... @@ -136,10 +149,13 @@ class PipeTransform : public CompositeTransform
136 149 foreach (Transform *f, transforms) {
137 150 try {
138 151 f->projectUpdate(dst);
  152 + if (dst.file.fte)
  153 + break;
139 154 } catch (...) {
140 155 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
141 156 dst = Template(src.file);
142   - dst.file.set("FTE", true);
  157 + dst.file.fte = true;
  158 + break;
143 159 }
144 160 }
145 161 }
... ... @@ -149,8 +165,7 @@ class PipeTransform : public CompositeTransform
149 165 void projectUpdate(const TemplateList &src, TemplateList &dst)
150 166 {
151 167 dst = src;
152   - foreach (Transform *f, transforms)
153   - {
  168 + foreach (Transform *f, transforms) {
154 169 f->projectUpdate(dst);
155 170 }
156 171 }
... ... @@ -188,9 +203,7 @@ class PipeTransform : public CompositeTransform
188 203 continue;
189 204 }
190 205 for (int j=0; j < probe->transforms.size(); j++)
191   - {
192 206 flattened.append(probe->transforms[j]);
193   - }
194 207 }
195 208 transforms = flattened;
196 209  
... ... @@ -202,10 +215,20 @@ protected:
202 215 // or if parallelism is disabled, handle them sequentially
203 216 void _project(const TemplateList &src, TemplateList &dst) const
204 217 {
205   - dst = src;
  218 + TemplateList temp, output;
  219 + temp = src;
206 220 foreach (const Transform *f, transforms) {
207   - dst >> *f;
  221 + dst.clear();
  222 + f->project(temp, dst);
  223 + temp.clear();
  224 + foreach(const Template &t, dst) {
  225 + if (!t.file.fte)
  226 + temp.append(t);
  227 + else output.append(t);
  228 + }
208 229 }
  230 + output.append(temp);
  231 + dst = output;
209 232 }
210 233  
211 234 // Single template const project, pass the template through each sub-transform, one after the other
... ... @@ -215,10 +238,12 @@ protected:
215 238 foreach (const Transform *f, transforms) {
216 239 try {
217 240 dst >> *f;
  241 + if (dst.file.fte)
  242 + break;
218 243 } catch (...) {
219 244 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
220 245 dst = Template(src.file);
221   - dst.file.set("FTE", true);
  246 + dst.file.fte = true;
222 247 }
223 248 }
224 249 }
... ... @@ -323,7 +348,8 @@ class ForkTransform : public CompositeTransform
323 348 } catch (...) {
324 349 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
325 350 dst = Template(src.file);
326   - dst.file.set("FTE", true);
  351 + dst.file.fte = true;
  352 + break;
327 353 }
328 354 }
329 355 }
... ... @@ -379,7 +405,8 @@ protected:
379 405 } catch (...) {
380 406 qWarning("Exception triggered when processing %s with transform %s", qPrintable(src.file.flat()), qPrintable(f->objectName()));
381 407 dst = Template(src.file);
382   - dst.file.set("FTE", true);
  408 + dst.file.fte = true;
  409 + break;
383 410 }
384 411 }
385 412 }
... ...
openbr/plugins/misc.cpp
... ... @@ -52,7 +52,8 @@ class OpenTransform : public UntrainableMetaTransform
52 52 dst.append(t);
53 53 dst.file.append(t.file.localMetadata());
54 54 }
55   - dst.file.set("FTO", dst.isEmpty());
  55 + if (dst.isEmpty())
  56 + dst.file.fte = true;
56 57 } else {
57 58 // Propogate or decode existing matricies
58 59 foreach (const Mat &m, src) {
... ... @@ -610,6 +611,10 @@ class GalleryOutputTransform : public TimeVaryingTransform
610 611 if (src.empty())
611 612 return;
612 613 dst = src;
  614 + for (int i=0; i < dst.size();i++) {
  615 + if (dst[i].file.getBool("FTE"))
  616 + dst[i].file.fte = true;
  617 + }
613 618 writer->writeBlock(dst);
614 619 }
615 620  
... ... @@ -725,8 +730,10 @@ class OutputTransform : public TimeVaryingTransform
725 730  
726 731 // we received a template, which is the next row/column in order
727 732 foreach (const Template &t, dst) {
728   - for (int i=0; i < t.m().cols; i++) {
729   - output->setRelative(t.m().at<float>(0, i), currentRow, currentCol);
  733 + bool fte = t.file.getBool("FTE") || t.file.fte;
  734 +
  735 + for (int i=0; i < scoresPerMat; i++) {
  736 + output->setRelative(fte ? -std::numeric_limits<float>::max() : t.m().at<float>(0, i), currentRow, currentCol);
730 737  
731 738 // row-major input
732 739 if (!transposeMode)
... ... @@ -794,10 +801,12 @@ class OutputTransform : public TimeVaryingTransform
794 801 fragmentsPerRow = bufferedSize;
795 802 // a single col contains comparisons to all query files
796 803 fragmentsPerCol = queryFiles.size();
  804 + scoresPerMat = fragmentsPerCol;
797 805 }
798 806 else {
799 807 // a single row contains comparisons to all target files
800 808 fragmentsPerRow = targetFiles.size();
  809 + scoresPerMat = fragmentsPerRow;
801 810 // we output rows one at a time
802 811 fragmentsPerCol = 1;
803 812 }
... ... @@ -823,6 +832,8 @@ class OutputTransform : public TimeVaryingTransform
823 832 int fragmentsPerRow;
824 833 int fragmentsPerCol;
825 834  
  835 + int scoresPerMat;
  836 +
826 837 public:
827 838 OutputTransform() : TimeVaryingTransform(false,false) {}
828 839 };
... ...
openbr/plugins/pp5.cpp
... ... @@ -323,7 +323,7 @@ class PP5EnrollTransform : public UntrainableMetaTransform
323 323 // No faces were detected when we were expecting one, output something with FTE set.
324 324 if (!foundFace && !Globals->enrollAll) {
325 325 dstList.append(Template(src.file, detectOnly ? src.m() : cv::Mat()));
326   - dstList.last().file.set("FTE", true);
  326 + dstList.last().file.fte = true;
327 327 }
328 328 }
329 329  
... ...
openbr/plugins/stasm4.cpp
... ... @@ -144,7 +144,7 @@ class StasmTransform : public UntrainableTransform
144 144  
145 145 if (!foundFace) {
146 146 if (Globals->verbose) qWarning("No face found in %s.", qPrintable(src.file.fileName()));
147   - dst.file.set("FTE",true);
  147 + dst.file.fte = true;
148 148 } else {
149 149 QList<QPointF> points;
150 150 for (int i = 0; i < nLandmarks; i++) {
... ...
openbr/plugins/stream.cpp
... ... @@ -907,7 +907,17 @@ public:
907 907 qFatal("null input to multi-thread stage");
908 908 }
909 909  
910   - input->data >> *transform;
  910 + TemplateList project;
  911 + TemplateList completed;
  912 + for (int i=0; i < input->data.size(); i++) {
  913 + if (input->data[i].file.fte)
  914 + completed.append(input->data[i]);
  915 + else
  916 + project.append(input->data[i]);
  917 + }
  918 + input->data.clear();
  919 + transform->project(project, input->data);
  920 + input->data.append(completed);
911 921  
912 922 should_continue = nextStage->tryAcquireNextStage(input, final);
913 923  
... ... @@ -927,7 +937,7 @@ public:
927 937 {
928 938 // nothing to do.
929 939 }
930   - void status(){
  940 + void status() {
931 941 qDebug("multi thread stage %d, nothing to worry about", this->stage_id);
932 942 }
933 943 };
... ... @@ -980,13 +990,22 @@ public:
980 990 qFatal("NULL input to stage %d", this->stage_id);
981 991  
982 992 if (input->sequenceNumber != next_target)
983   - {
984 993 qFatal("out of order frames for stage %d, got %d expected %d", this->stage_id, input->sequenceNumber, this->next_target);
985   - }
  994 +
986 995 next_target = input->sequenceNumber + 1;
987 996  
  997 + TemplateList project;
  998 + TemplateList completed;
  999 + foreach (const Template &t, input->data) {
  1000 + if (t.file.fte)
  1001 + completed.append(t);
  1002 + else
  1003 + project.append(t);
  1004 + }
  1005 + input->data.clear();
988 1006 // Project the input we got
989   - transform->projectUpdate(input->data);
  1007 + transform->projectUpdate(project, input->data);
  1008 + input->data.append(completed);
990 1009  
991 1010 should_continue = nextStage->tryAcquireNextStage(input,final);
992 1011  
... ... @@ -1057,12 +1076,40 @@ public:
1057 1076 return true;
1058 1077 }
1059 1078  
1060   - void status(){
  1079 + void status() {
1061 1080 qDebug("single thread stage %d, status starting? %d, next %d buffer size %d", this->stage_id, this->currentStatus == SingleThreadStage::STARTING, this->next_target, this->inputBuffer->size());
1062 1081 }
1063 1082  
1064 1083 };
1065 1084  
  1085 +class EndStage : public SingleThreadStage
  1086 +{
  1087 +public:
  1088 + EndStage(bool input_variance) : SingleThreadStage(input_variance) {}
  1089 +
  1090 + ~EndStage() {}
  1091 +
  1092 + // Calledfrom a different thread than run.
  1093 + bool tryAcquireNextStage(FrameData *& input, bool &final)
  1094 + {
  1095 + for (int i=0; i < input->data.size(); i++) {
  1096 + if (input->data[i].file.fte) {
  1097 + input->data[i].file.fte = false;
  1098 + input->data[i].file.set("FTE",QVariant::fromValue(true));
  1099 + }
  1100 + else
  1101 + input->data[i].file.set("FTE",QVariant::fromValue(false));
  1102 + }
  1103 +
  1104 + return SingleThreadStage::tryAcquireNextStage(input, final);
  1105 + }
  1106 +
  1107 + void status() {
  1108 + qDebug("end stage %d, status starting? %d, next %d buffer size %d", this->stage_id, this->currentStatus == SingleThreadStage::STARTING, this->next_target, this->inputBuffer->size());
  1109 + }
  1110 +
  1111 +};
  1112 +
1066 1113 // Semi-functional, doesn't do anything productive outside of stream::train
1067 1114 class CollectSets : public TimeVaryingTransform
1068 1115 {
... ... @@ -1099,7 +1146,7 @@ public:
1099 1146 data.append(src);
1100 1147 }
1101 1148  
1102   - void finalize(TemplateList & output)
  1149 + void finalize(TemplateList &output)
1103 1150 {
1104 1151 output = data;
1105 1152 data.clear();
... ... @@ -1198,7 +1245,7 @@ public:
1198 1245 return true;
1199 1246 }
1200 1247  
1201   - void status(){
  1248 + void status() {
1202 1249 qDebug("Read stage %d, status starting? %d, next frame %d buffer size %d", this->stage_id, this->currentStatus == SingleThreadStage::STARTING, this->next_target, this->dataSource.size());
1203 1250 }
1204 1251 };
... ... @@ -1463,7 +1510,7 @@ public:
1463 1510  
1464 1511 // We also have the last stage, which just puts the output of the
1465 1512 // previous stages on a template list.
1466   - collectionStage = new SingleThreadStage(prev_stage_variance);
  1513 + collectionStage = new EndStage(prev_stage_variance);
1467 1514 collectionStage->transform = this->endPoint;
1468 1515  
1469 1516  
... ...