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,6 +27,7 @@ struct AlgorithmCore
27 { 27 {
28 QSharedPointer<Transform> transform; 28 QSharedPointer<Transform> transform;
29 QSharedPointer<Distance> distance; 29 QSharedPointer<Distance> distance;
  30 + QString galleryCompareString;
30 31
31 QString transformString; 32 QString transformString;
32 QString distanceString; 33 QString distanceString;
@@ -147,9 +148,6 @@ struct AlgorithmCore @@ -147,9 +148,6 @@ struct AlgorithmCore
147 Gallery *temp = Gallery::make(input); 148 Gallery *temp = Gallery::make(input);
148 qint64 total = temp->totalSize(); 149 qint64 total = temp->totalSize();
149 150
150 - Globals->currentStep = 0;  
151 - Globals->totalSteps = total;  
152 -  
153 QScopedPointer<Transform> basePipe; 151 QScopedPointer<Transform> basePipe;
154 152
155 QString pipeDesc = "GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(total)+")+Discard"; 153 QString pipeDesc = "GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(total)+")+Discard";
@@ -189,6 +187,8 @@ struct AlgorithmCore @@ -189,6 +187,8 @@ struct AlgorithmCore
189 wrapper->init(); 187 wrapper->init();
190 188
191 Globals->startTime.start(); 189 Globals->startTime.start();
  190 + Globals->currentStep = 0;
  191 + Globals->totalSteps = total;
192 192
193 TemplateList data, output; 193 TemplateList data, output;
194 data.append(input); 194 data.append(input);
@@ -335,7 +335,7 @@ struct AlgorithmCore @@ -335,7 +335,7 @@ struct AlgorithmCore
335 output.isNull() ? "" : qPrintable(" to " + output.flat())); 335 output.isNull() ? "" : qPrintable(" to " + output.flat()));
336 336
337 // Escape hatch for distances that need to operate directly on the gallery files 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 return; 339 return;
340 340
341 // Are we comparing the same gallery against itself? 341 // Are we comparing the same gallery against itself?
@@ -442,8 +442,11 @@ struct AlgorithmCore @@ -442,8 +442,11 @@ struct AlgorithmCore
442 // The actual comparison step is done by a GalleryCompare transform, which has a Distance, and a gallery as data. 442 // The actual comparison step is done by a GalleryCompare transform, which has a Distance, and a gallery as data.
443 // Incoming templates are compared against the templates in the gallery, and the output is the resulting score 443 // Incoming templates are compared against the templates in the gallery, and the output is the resulting score
444 // vector. 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 QScopedPointer<Transform> compareRegion; 451 QScopedPointer<Transform> compareRegion;
449 // If we need to enroll the row set, we add the current algorithm's enrollment transform before the 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,6 +522,7 @@ struct AlgorithmCore
519 522
520 // Set up progress counting variables 523 // Set up progress counting variables
521 Globals->currentStep = 0; 524 Globals->currentStep = 0;
  525 + Globals->currentProgress = 0;
522 Globals->totalSteps = rowSize; 526 Globals->totalSteps = rowSize;
523 Globals->startTime.start(); 527 Globals->startTime.start();
524 528
@@ -553,19 +557,27 @@ private: @@ -553,19 +557,27 @@ private:
553 if (Globals->abbreviations.contains(description)) 557 if (Globals->abbreviations.contains(description))
554 return init(Globals->abbreviations[description]); 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 if ((words.size() < 1) || (words.size() > 2)) qFatal("Invalid algorithm format."); 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 transformString = words[0]; 566 transformString = words[0];
562 567
563 -  
564 //! [Creating the template generation and comparison methods] 568 //! [Creating the template generation and comparison methods]
565 transform = QSharedPointer<Transform>(Transform::make(words[0], NULL)); 569 transform = QSharedPointer<Transform>(Transform::make(words[0], NULL));
566 if (words.size() > 1) { 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 //! [Creating the template generation and comparison methods] 582 //! [Creating the template generation and comparison methods]
571 } 583 }
openbr/openbr_plugin.cpp
@@ -875,7 +875,7 @@ void br::Context::printStatus() @@ -875,7 +875,7 @@ void br::Context::printStatus()
875 const float p = progress(); 875 const float p = progress();
876 if (p < 1) { 876 if (p < 1) {
877 int s = timeRemaining(); 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 fflush(stderr); 879 fflush(stderr);
880 } 880 }
881 } 881 }
openbr/plugins/gallery.cpp
@@ -129,7 +129,7 @@ class BinaryGallery : public Gallery @@ -129,7 +129,7 @@ class BinaryGallery : public Gallery
129 if (t.isEmpty() && t.file.isNull()) 129 if (t.isEmpty() && t.file.isNull())
130 continue; 130 continue;
131 templates.append(t); 131 templates.append(t);
132 - templates.last().file.set("progress", totalSize()); 132 + templates.last().file.set("progress", position());
133 133
134 // Special case for pipes where we want to process data as soon as it is available 134 // Special case for pipes where we want to process data as soon as it is available
135 if (gallery.isSequential()) 135 if (gallery.isSequential())
openbr/plugins/misc.cpp
@@ -625,11 +625,18 @@ class ProgressCounterTransform : public TimeVaryingTransform @@ -625,11 +625,18 @@ class ProgressCounterTransform : public TimeVaryingTransform
625 dst = src; 625 dst = src;
626 626
627 qint64 elapsed = timer.elapsed(); 627 qint64 elapsed = timer.elapsed();
628 - 628 + int last_frame = -2;
629 if (!dst.empty()) { 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 // updated every second 642 // updated every second
@@ -650,13 +657,17 @@ class ProgressCounterTransform : public TimeVaryingTransform @@ -650,13 +657,17 @@ class ProgressCounterTransform : public TimeVaryingTransform
650 { 657 {
651 (void) data; 658 (void) data;
652 float p = br_progress(); 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 void init() 666 void init()
657 { 667 {
658 timer.start(); 668 timer.start();
659 Globals->currentStep = 0; 669 Globals->currentStep = 0;
  670 + Globals->currentProgress = 0;
660 } 671 }
661 672
662 public: 673 public:
@@ -713,26 +724,26 @@ class OutputTransform : public TimeVaryingTransform @@ -713,26 +724,26 @@ class OutputTransform : public TimeVaryingTransform
713 currentCol++; 724 currentCol++;
714 currentRow = 0; 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,7 +45,7 @@ class PP5Initializer : public Initializer
45 void initialize() const 45 void initialize() const
46 { 46 {
47 TRY(ppr_initialize_sdk(qPrintable(Globals->sdkPath + "/share/openbr/models/pp5/"), my_license_id, my_license_key)) 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 Globals->abbreviations.insert("PP5Register", "Open+PP5Enroll(true)+RenameFirst([eyeL,PP5_Landmark0_Right_Eye],Affine_0)+RenameFirst([eyeR,PP5_Landmark1_Left_Eye],Affine_1)"); 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 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)"); 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,7 +85,7 @@ struct PP5Context
85 default_settings.recognition.automatically_extract_templates = 1; 85 default_settings.recognition.automatically_extract_templates = 1;
86 default_settings.recognition.enable_comparison = 1; 86 default_settings.recognition.enable_comparison = 1;
87 default_settings.recognition.enable_extraction = 1; 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 default_settings.recognition.recognizer = PPR_RECOGNIZER_MULTI_POSE; 89 default_settings.recognition.recognizer = PPR_RECOGNIZER_MULTI_POSE;
90 TRY(ppr_initialize_context(default_settings, &context)) 90 TRY(ppr_initialize_context(default_settings, &context))
91 } 91 }
@@ -205,6 +205,45 @@ struct PP5Context @@ -205,6 +205,45 @@ struct PP5Context
205 205
206 return metadata; 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,6 +333,7 @@ class PP5EnrollTransform : public UntrainableMetaTransform
294 333
295 BR_REGISTER(Transform, PP5EnrollTransform) 334 BR_REGISTER(Transform, PP5EnrollTransform)
296 335
  336 +
297 /*! 337 /*!
298 * \ingroup distances 338 * \ingroup distances
299 * \brief Compare templates with PP5 339 * \brief Compare templates with PP5
@@ -351,44 +391,6 @@ class PP5CompareDistance : public Distance @@ -351,44 +391,6 @@ class PP5CompareDistance : public Distance
351 ppr_free_gallery(query_gallery); 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 NativeGallery cacheRetain(const File &gallery) const 394 NativeGallery cacheRetain(const File &gallery) const
393 { 395 {
394 QMutexLocker locker(&cacheLock); 396 QMutexLocker locker(&cacheLock);
@@ -439,4 +441,69 @@ class PP5CompareDistance : public Distance @@ -439,4 +441,69 @@ class PP5CompareDistance : public Distance
439 441
440 BR_REGISTER(Distance, PP5CompareDistance) 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 #include "plugins/pp5.moc" 509 #include "plugins/pp5.moc"