Commit a438d3fa911fe599826f0bef120a3eefeb9112eb
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 :.
Showing
5 changed files
with
167 additions
and
77 deletions
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" | ... | ... |