Commit cdb6b4fb4004e23c7e759d28efe1373576d4a180
Merge pull request #213 from biometrics/inline_pp5
Refactor PP5 comparison handling
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" | ... | ... |