Commit a438d3fa911fe599826f0bef120a3eefeb9112eb

Authored by Charles Otto
1 parent 7c9ace46

Refactor PP5 comparison handling

Introduce PP5GalleryTransform, a transform that compares incoming templates
against a fixed gallery (thereby avoiding the cost of repeatedly setting up
pp5 galleries for the same templates).

Modify AlgorithmCore to support supplying Transforms to the right of the
algorithm string, in this case ! should be used instead of :.
openbr/core/core.cpp
... ... @@ -27,6 +27,7 @@ struct AlgorithmCore
27 27 {
28 28 QSharedPointer<Transform> transform;
29 29 QSharedPointer<Distance> distance;
  30 + QString galleryCompareString;
30 31  
31 32 QString transformString;
32 33 QString distanceString;
... ... @@ -147,9 +148,6 @@ struct AlgorithmCore
147 148 Gallery *temp = Gallery::make(input);
148 149 qint64 total = temp->totalSize();
149 150  
150   - Globals->currentStep = 0;
151   - Globals->totalSteps = total;
152   -
153 151 QScopedPointer<Transform> basePipe;
154 152  
155 153 QString pipeDesc = "GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(total)+")+Discard";
... ... @@ -189,6 +187,8 @@ struct AlgorithmCore
189 187 wrapper->init();
190 188  
191 189 Globals->startTime.start();
  190 + Globals->currentStep = 0;
  191 + Globals->totalSteps = total;
192 192  
193 193 TemplateList data, output;
194 194 data.append(input);
... ... @@ -335,7 +335,7 @@ struct AlgorithmCore
335 335 output.isNull() ? "" : qPrintable(" to " + output.flat()));
336 336  
337 337 // Escape hatch for distances that need to operate directly on the gallery files
338   - if (distance->compare(targetGallery, queryGallery, output))
  338 + if (distance && distance->compare(targetGallery, queryGallery, output))
339 339 return;
340 340  
341 341 // Are we comparing the same gallery against itself?
... ... @@ -442,8 +442,11 @@ struct AlgorithmCore
442 442 // The actual comparison step is done by a GalleryCompare transform, which has a Distance, and a gallery as data.
443 443 // Incoming templates are compared against the templates in the gallery, and the output is the resulting score
444 444 // vector.
445   - QString compareRegionDesc = "Pipe([GalleryCompare("+Globals->algorithm + "," + colEnrolledGallery.flat() + ")])";
446   -
  445 + QString compareRegionDesc;
  446 + if (this->galleryCompareString.isEmpty() )
  447 + compareRegionDesc = "Pipe([GalleryCompare("+Globals->algorithm + "," + colEnrolledGallery.flat() + ")])";
  448 + else
  449 + compareRegionDesc = "Pipe(["+this->galleryCompareString+"("+Globals->algorithm + "," + colEnrolledGallery.flat() + ")])";
447 450  
448 451 QScopedPointer<Transform> compareRegion;
449 452 // If we need to enroll the row set, we add the current algorithm's enrollment transform before the
... ... @@ -519,6 +522,7 @@ struct AlgorithmCore
519 522  
520 523 // Set up progress counting variables
521 524 Globals->currentStep = 0;
  525 + Globals->currentProgress = 0;
522 526 Globals->totalSteps = rowSize;
523 527 Globals->startTime.start();
524 528  
... ... @@ -553,19 +557,27 @@ private:
553 557 if (Globals->abbreviations.contains(description))
554 558 return init(Globals->abbreviations[description]);
555 559  
556   - //! [Parsing the algorithm description]
557   - QStringList words = QtUtils::parse(description, ':');
  560 + const bool compareTransform = description.contains('!');
  561 + QStringList words = QtUtils::parse(description, compareTransform ? '!' : ':');
  562 +
558 563 if ((words.size() < 1) || (words.size() > 2)) qFatal("Invalid algorithm format.");
559   - //! [Parsing the algorithm description]
560 564  
  565 + //! [Parsing the algorithm description]
561 566 transformString = words[0];
562 567  
563   -
564 568 //! [Creating the template generation and comparison methods]
565 569 transform = QSharedPointer<Transform>(Transform::make(words[0], NULL));
566 570 if (words.size() > 1) {
567   - distance = QSharedPointer<Distance>(Distance::make(words[1], NULL));
568   - distanceString = words[1];
  571 + if (!compareTransform) {
  572 + distance = QSharedPointer<Distance>(Distance::make(words[1], NULL));
  573 + distanceString = words[1];
  574 + galleryCompareString.clear();
  575 + }
  576 + else {
  577 + galleryCompareString = words[1];
  578 + distanceString.clear();
  579 + }
  580 +
569 581 }
570 582 //! [Creating the template generation and comparison methods]
571 583 }
... ...
openbr/openbr_plugin.cpp
... ... @@ -875,7 +875,7 @@ void br::Context::printStatus()
875 875 const float p = progress();
876 876 if (p < 1) {
877 877 int s = timeRemaining();
878   - fprintf(stderr,"%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g \r", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(s).toStdString().c_str(), Globals->currentStep);
  878 + fprintf(stderr,"\r%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(s).toStdString().c_str(), Globals->currentStep);
879 879 fflush(stderr);
880 880 }
881 881 }
... ...
openbr/plugins/gallery.cpp
... ... @@ -129,7 +129,7 @@ class BinaryGallery : public Gallery
129 129 if (t.isEmpty() && t.file.isNull())
130 130 continue;
131 131 templates.append(t);
132   - templates.last().file.set("progress", totalSize());
  132 + templates.last().file.set("progress", position());
133 133  
134 134 // Special case for pipes where we want to process data as soon as it is available
135 135 if (gallery.isSequential())
... ...
openbr/plugins/misc.cpp
... ... @@ -625,11 +625,18 @@ class ProgressCounterTransform : public TimeVaryingTransform
625 625 dst = src;
626 626  
627 627 qint64 elapsed = timer.elapsed();
628   -
  628 + int last_frame = -2;
629 629 if (!dst.empty()) {
630   - Globals->currentProgress = dst.last().file.get<qint64>("progress",0);
631   - dst.last().file.remove("progress");
632   - Globals->currentStep++;
  630 + for (int i=0;i < dst.size();i++) {
  631 + int frame = dst[i].file.get<int>("FrameNumber", -1);
  632 + if (frame == last_frame)
  633 + continue;
  634 +
  635 + Globals->currentProgress = dst[i].file.get<qint64>("progress",0);
  636 + dst[i].file.remove("progress");
  637 + Globals->currentStep++;
  638 + last_frame = frame;
  639 + }
633 640 }
634 641  
635 642 // updated every second
... ... @@ -650,13 +657,17 @@ class ProgressCounterTransform : public TimeVaryingTransform
650 657 {
651 658 (void) data;
652 659 float p = br_progress();
653   - qDebug("%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g \r", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), Globals->currentStep);
  660 + qDebug("\r%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), Globals->currentStep);
  661 + Globals->currentStep = 0;
  662 + Globals->currentProgress = 0;
  663 + Globals->totalSteps = 0;
654 664 }
655 665  
656 666 void init()
657 667 {
658 668 timer.start();
659 669 Globals->currentStep = 0;
  670 + Globals->currentProgress = 0;
660 671 }
661 672  
662 673 public:
... ... @@ -713,26 +724,26 @@ class OutputTransform : public TimeVaryingTransform
713 724 currentCol++;
714 725 currentRow = 0;
715 726 }
716   - }
717 727  
718   - bool blockDone = false;
719   - // In direct mode, we don't buffer rows
720   - if (!transposeMode) {
721   - currentBlockRow++;
722   - blockDone = true;
723   - }
724   - // in transpose mode, we buffer 100 cols before writing the block
725   - else if (currentCol == bufferedSize) {
726   - currentBlockCol++;
727   - blockDone = true;
728   - }
729   - else return;
  728 + bool blockDone = false;
  729 + // In direct mode, we don't buffer rows
  730 + if (!transposeMode) {
  731 + currentBlockRow++;
  732 + blockDone = true;
  733 + }
  734 + // in transpose mode, we buffer 100 cols before writing the block
  735 + else if (currentCol == bufferedSize) {
  736 + currentBlockCol++;
  737 + blockDone = true;
  738 + }
  739 + else return;
730 740  
731   - if (blockDone) {
732   - // set the next block, only necessary if we haven't buffered the current item
733   - output->setBlock(currentBlockRow, currentBlockCol);
734   - currentRow = 0;
735   - currentCol = 0;
  741 + if (blockDone) {
  742 + // set the next block, only necessary if we haven't buffered the current item
  743 + output->setBlock(currentBlockRow, currentBlockCol);
  744 + currentRow = 0;
  745 + currentCol = 0;
  746 + }
736 747 }
737 748 }
738 749  
... ...
openbr/plugins/pp5.cpp
... ... @@ -45,7 +45,7 @@ class PP5Initializer : public Initializer
45 45 void initialize() const
46 46 {
47 47 TRY(ppr_initialize_sdk(qPrintable(Globals->sdkPath + "/share/openbr/models/pp5/"), my_license_id, my_license_key))
48   - Globals->abbreviations.insert("PP5","Open+Expand+PP5Enroll:PP5Compare");
  48 + Globals->abbreviations.insert("PP5","Open+Expand+PP5Enroll!PP5Gallery");
49 49 Globals->abbreviations.insert("PP5Register", "Open+PP5Enroll(true)+RenameFirst([eyeL,PP5_Landmark0_Right_Eye],Affine_0)+RenameFirst([eyeR,PP5_Landmark1_Left_Eye],Affine_1)");
50 50 Globals->abbreviations.insert("PP5CropFace", "Open+PP5Enroll(true)+RenameFirst([eyeL,PP5_Landmark0_Right_Eye],Affine_0)+RenameFirst([eyeR,PP5_Landmark1_Left_Eye],Affine_1)+Affine(128,128,0.25,0.35)+Cvt(Gray)");
51 51 }
... ... @@ -85,7 +85,7 @@ struct PP5Context
85 85 default_settings.recognition.automatically_extract_templates = 1;
86 86 default_settings.recognition.enable_comparison = 1;
87 87 default_settings.recognition.enable_extraction = 1;
88   - default_settings.recognition.num_comparison_threads = QThreadPool::globalInstance()->maxThreadCount();
  88 + default_settings.recognition.num_comparison_threads = 1;
89 89 default_settings.recognition.recognizer = PPR_RECOGNIZER_MULTI_POSE;
90 90 TRY(ppr_initialize_context(default_settings, &context))
91 91 }
... ... @@ -205,6 +205,45 @@ struct PP5Context
205 205  
206 206 return metadata;
207 207 }
  208 +
  209 + void compareNative(ppr_gallery_type target, const QList<int> &targetIDs, ppr_gallery_type query, const QList<int> &queryIDs, Output *output) const
  210 + {
  211 + ppr_similarity_matrix_type simmat;
  212 + TRY(ppr_compare_galleries(context, query, target, &simmat))
  213 + for (int i=0; i<queryIDs.size(); i++) {
  214 + int query_subject_id = queryIDs[i];
  215 + for (int j=0; j<targetIDs.size(); j++) {
  216 + int target_subject_id = targetIDs[j];
  217 + float score = -std::numeric_limits<float>::max();
  218 + if ((query_subject_id != -1) && (target_subject_id != -1)) {
  219 + TRY(ppr_get_subject_similarity_score(context, simmat, query_subject_id, target_subject_id, &score))
  220 + }
  221 + output->setRelative(score, i, j);
  222 + }
  223 + }
  224 + ppr_free_similarity_matrix(simmat);
  225 + }
  226 +
  227 + void enroll(const TemplateList &templates, ppr_gallery_type *gallery, QList<int> &subject_ids) const
  228 + {
  229 + int subject_id = 0, face_id = 0;
  230 + foreach (const Template &src, templates) {
  231 + if (!src.empty() && src.m().data) {
  232 + foreach (const cv::Mat &m, src) {
  233 + ppr_face_type face;
  234 + createFace(m, &face);
  235 + TRY(ppr_add_face(context, gallery, face, subject_id, face_id))
  236 + face_id++;
  237 + ppr_free_face(face);
  238 + }
  239 + subject_ids.append(subject_id);
  240 + subject_id++;
  241 + } else {
  242 + subject_ids.append(-1);
  243 + }
  244 + }
  245 + }
  246 +
208 247 };
209 248  
210 249 /*!
... ... @@ -294,6 +333,7 @@ class PP5EnrollTransform : public UntrainableMetaTransform
294 333  
295 334 BR_REGISTER(Transform, PP5EnrollTransform)
296 335  
  336 +
297 337 /*!
298 338 * \ingroup distances
299 339 * \brief Compare templates with PP5
... ... @@ -351,44 +391,6 @@ class PP5CompareDistance : public Distance
351 391 ppr_free_gallery(query_gallery);
352 392 }
353 393  
354   - void compareNative(ppr_gallery_type target, const QList<int> &targetIDs, ppr_gallery_type query, const QList<int> &queryIDs, Output *output) const
355   - {
356   - ppr_similarity_matrix_type simmat;
357   - TRY(ppr_compare_galleries(context, query, target, &simmat))
358   - for (int i=0; i<queryIDs.size(); i++) {
359   - int query_subject_id = queryIDs[i];
360   - for (int j=0; j<targetIDs.size(); j++) {
361   - int target_subject_id = targetIDs[j];
362   - float score = -std::numeric_limits<float>::max();
363   - if ((query_subject_id != -1) && (target_subject_id != -1)) {
364   - TRY(ppr_get_subject_similarity_score(context, simmat, query_subject_id, target_subject_id, &score))
365   - }
366   - output->setRelative(score, i, j);
367   - }
368   - }
369   - ppr_free_similarity_matrix(simmat);
370   - }
371   -
372   - void enroll(const TemplateList &templates, ppr_gallery_type *gallery, QList<int> &subject_ids) const
373   - {
374   - int subject_id = 0, face_id = 0;
375   - foreach (const Template &src, templates) {
376   - if (!src.empty() && src.m().data) {
377   - foreach (const cv::Mat &m, src) {
378   - ppr_face_type face;
379   - createFace(m, &face);
380   - TRY(ppr_add_face(context, gallery, face, subject_id, face_id))
381   - face_id++;
382   - ppr_free_face(face);
383   - }
384   - subject_ids.append(subject_id);
385   - subject_id++;
386   - } else {
387   - subject_ids.append(-1);
388   - }
389   - }
390   - }
391   -
392 394 NativeGallery cacheRetain(const File &gallery) const
393 395 {
394 396 QMutexLocker locker(&cacheLock);
... ... @@ -439,4 +441,69 @@ class PP5CompareDistance : public Distance
439 441  
440 442 BR_REGISTER(Distance, PP5CompareDistance)
441 443  
  444 +class PP5GalleryTransform: public UntrainableMetaTransform
  445 + , public PP5Context
  446 +{
  447 + Q_OBJECT
  448 + Q_PROPERTY(QString junk READ get_junk WRITE set_junk RESET reset_junk STORED false)
  449 + Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false)
  450 + BR_PROPERTY(QString, junk, "")
  451 + BR_PROPERTY(QString, galleryName, "")
  452 +
  453 + ppr_gallery_type target;
  454 + QList<int> targetIDs;
  455 +
  456 + void project(const Template & src, Template & dst) const
  457 + {
  458 + TemplateList temp, output;
  459 + temp.append(src);
  460 + project(temp, output);
  461 + if (!output.empty())
  462 + dst = output[0];
  463 + }
  464 +
  465 + void project(const TemplateList & src, TemplateList & dst) const
  466 + {
  467 + dst.clear();
  468 + QList<int> queryIDs;
  469 +
  470 + ppr_gallery_type query;
  471 + ppr_create_gallery(context, &query);
  472 + enroll(src,&query, queryIDs);
  473 +
  474 + ppr_similarity_matrix_type simmat;
  475 +
  476 + TRY(ppr_compare_galleries(context, query, target, &simmat))
  477 +
  478 + for (int i=0; i<queryIDs.size(); i++) {
  479 + dst.append(Template());
  480 + dst[i].file = src[i].file;
  481 + dst[i].m() = cv::Mat(1,targetIDs.size(), CV_32FC1);
  482 +
  483 + int query_subject_id = queryIDs[i];
  484 + for (int j=0; j<targetIDs.size(); j++) {
  485 + int target_subject_id = targetIDs[j];
  486 + float score = -std::numeric_limits<float>::max();
  487 + if ((query_subject_id != -1) && (target_subject_id != -1)) {
  488 + TRY(ppr_get_subject_similarity_score(context, simmat, query_subject_id, target_subject_id, &score))
  489 + }
  490 + dst[i].m().at<float>(0,j) = score;
  491 + }
  492 + }
  493 +
  494 + ppr_free_similarity_matrix(simmat);
  495 + ppr_free_gallery(query);
  496 + }
  497 +
  498 + void init()
  499 + {
  500 + // set up the gallery
  501 + ppr_create_gallery(context, &target);
  502 + TemplateList templates = TemplateList::fromGallery(galleryName);
  503 + enroll(templates,&target, targetIDs);
  504 + }
  505 +};
  506 +
  507 +BR_REGISTER(Transform, PP5GalleryTransform)
  508 +
442 509 #include "plugins/pp5.moc"
... ...