Commit 7685e92fa6b8a203861b22aa90362d47c7553805
Merge pull request #191 from biometrics/streaming_gallery
Preliminary work on not loading complete galleries during enrollment
Showing
7 changed files
with
292 additions
and
90 deletions
openbr/core/core.cpp
| @@ -134,55 +134,51 @@ struct AlgorithmCore | @@ -134,55 +134,51 @@ struct AlgorithmCore | ||
| 134 | if (input.name.isEmpty()) return FileList(); | 134 | if (input.name.isEmpty()) return FileList(); |
| 135 | else gallery = getMemoryGallery(input); | 135 | else gallery = getMemoryGallery(input); |
| 136 | } | 136 | } |
| 137 | - TemplateList data(TemplateList::fromGallery(input)); | ||
| 138 | 137 | ||
| 139 | bool multiProcess = Globals->file.getBool("multiProcess", false); | 138 | bool multiProcess = Globals->file.getBool("multiProcess", false); |
| 139 | + bool fileExclusion = false; | ||
| 140 | 140 | ||
| 141 | - if (gallery.contains("append")) | ||
| 142 | - { | ||
| 143 | - // Remove any templates which are already in the gallery | ||
| 144 | - QScopedPointer<Gallery> g(Gallery::make(gallery)); | ||
| 145 | - files = g->files(); | ||
| 146 | - QSet<QString> nameSet = QSet<QString>::fromList(files.names()); | ||
| 147 | - for (int i = data.size() - 1; i>=0; i--) { | ||
| 148 | - if (nameSet.contains(data[i].file.name)) | ||
| 149 | - { | ||
| 150 | - data.removeAt(i); | ||
| 151 | - } | ||
| 152 | - } | 141 | + // In append mode, we will exclude any templates with filenames already present in the output gallery |
| 142 | + if (gallery.contains("append") && gallery.exists() ) { | ||
| 143 | + FileList::fromGallery(gallery,true); | ||
| 144 | + fileExclusion = true; | ||
| 153 | } | 145 | } |
| 154 | 146 | ||
| 155 | - if (data.empty()) | ||
| 156 | - return files; | 147 | + Gallery * temp = Gallery::make(input); |
| 148 | + qint64 total = temp->totalSize(); | ||
| 157 | 149 | ||
| 158 | - // Store steps for ProgressCounter | ||
| 159 | Globals->currentStep = 0; | 150 | Globals->currentStep = 0; |
| 160 | - Globals->totalSteps = data.length(); | 151 | + Globals->totalSteps = total; |
| 161 | 152 | ||
| 162 | QScopedPointer<Transform> basePipe; | 153 | QScopedPointer<Transform> basePipe; |
| 163 | 154 | ||
| 164 | - if (!multiProcess) | ||
| 165 | - { | ||
| 166 | - QString pipeDesc = "GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(data.length())+")+Discard"; | 155 | + QString pipeDesc = "GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(total)+")+Discard"; |
| 156 | + | ||
| 157 | + if (!multiProcess) { | ||
| 167 | basePipe.reset(Transform::make(pipeDesc,NULL)); | 158 | basePipe.reset(Transform::make(pipeDesc,NULL)); |
| 168 | CompositeTransform * downcast = dynamic_cast<CompositeTransform *>(basePipe.data()); | 159 | CompositeTransform * downcast = dynamic_cast<CompositeTransform *>(basePipe.data()); |
| 169 | - if (downcast == NULL) | ||
| 170 | - qFatal("downcast failed?"); | ||
| 171 | 160 | ||
| 172 | - // replace that placeholder with the current algorithm | 161 | + if (downcast == NULL) qFatal("downcast failed?"); |
| 162 | + | ||
| 173 | downcast->transforms.prepend(this->transform.data()); | 163 | downcast->transforms.prepend(this->transform.data()); |
| 164 | + if (fileExclusion) { | ||
| 165 | + Transform * temp = Transform::make("FileExclusion(" + gallery.flat() + ")", downcast); | ||
| 166 | + downcast->transforms.prepend(temp); | ||
| 167 | + } | ||
| 174 | 168 | ||
| 175 | // call init on the pipe to collapse the algorithm (if its top level is a pipe) | 169 | // call init on the pipe to collapse the algorithm (if its top level is a pipe) |
| 176 | downcast->init(); | 170 | downcast->init(); |
| 177 | } | 171 | } |
| 178 | - else | ||
| 179 | - { | ||
| 180 | - QString pipeDesc = "ProcessWrapper("+transformString+")"+"+GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(data.length())+")+Discard"; | 172 | + else { |
| 173 | + pipeDesc = "ProcessWrapper("+transformString+")"+pipeDesc; | ||
| 174 | + if (fileExclusion) | ||
| 175 | + pipeDesc = "FileExclusion(" + gallery.flat() +")" + pipeDesc; | ||
| 176 | + | ||
| 181 | basePipe.reset(Transform::make(pipeDesc,NULL)); | 177 | basePipe.reset(Transform::make(pipeDesc,NULL)); |
| 182 | } | 178 | } |
| 183 | 179 | ||
| 184 | // Next, we make a Stream (with placeholder transform) | 180 | // Next, we make a Stream (with placeholder transform) |
| 185 | - QString streamDesc = "Stream(readMode=DistributeFrames)"; | 181 | + QString streamDesc = "Stream(readMode=StreamGallery)"; |
| 186 | QScopedPointer<Transform> baseStream(Transform::make(streamDesc, NULL)); | 182 | QScopedPointer<Transform> baseStream(Transform::make(streamDesc, NULL)); |
| 187 | WrapperTransform * wrapper = dynamic_cast<WrapperTransform *> (baseStream.data()); | 183 | WrapperTransform * wrapper = dynamic_cast<WrapperTransform *> (baseStream.data()); |
| 188 | 184 | ||
| @@ -194,9 +190,11 @@ struct AlgorithmCore | @@ -194,9 +190,11 @@ struct AlgorithmCore | ||
| 194 | 190 | ||
| 195 | Globals->startTime.start(); | 191 | Globals->startTime.start(); |
| 196 | 192 | ||
| 197 | - wrapper->projectUpdate(data,data); | 193 | + TemplateList data, output; |
| 194 | + data.append(input); | ||
| 195 | + wrapper->projectUpdate(data, output); | ||
| 198 | 196 | ||
| 199 | - files.append(data.files()); | 197 | + files.append(output.files()); |
| 200 | 198 | ||
| 201 | return files; | 199 | return files; |
| 202 | } | 200 | } |
| @@ -337,13 +335,9 @@ struct AlgorithmCore | @@ -337,13 +335,9 @@ struct AlgorithmCore | ||
| 337 | // comparison against the smaller gallery (which will be enrolled, and stored in memory). | 335 | // comparison against the smaller gallery (which will be enrolled, and stored in memory). |
| 338 | bool needEnrollRows = false; | 336 | bool needEnrollRows = false; |
| 339 | 337 | ||
| 340 | - | ||
| 341 | - | ||
| 342 | - | ||
| 343 | if (output.exists() && output.get<bool>("cache", false)) return; | 338 | if (output.exists() && output.get<bool>("cache", false)) return; |
| 344 | if (queryGallery == ".") queryGallery = targetGallery; | 339 | if (queryGallery == ".") queryGallery = targetGallery; |
| 345 | 340 | ||
| 346 | - | ||
| 347 | // To decide which gallery is larger, we need to read both, but at this point we just want the | 341 | // To decide which gallery is larger, we need to read both, but at this point we just want the |
| 348 | // metadata, and don't need the enrolled matrices. | 342 | // metadata, and don't need the enrolled matrices. |
| 349 | FileList targetMetadata; | 343 | FileList targetMetadata; |
| @@ -359,15 +353,21 @@ struct AlgorithmCore | @@ -359,15 +353,21 @@ struct AlgorithmCore | ||
| 359 | 353 | ||
| 360 | File rowGallery = queryGallery; | 354 | File rowGallery = queryGallery; |
| 361 | File colGallery = targetGallery; | 355 | File colGallery = targetGallery; |
| 362 | - int rowSize = queryMetadata.size(); | 356 | + qint64 rowSize; |
| 363 | 357 | ||
| 358 | + Gallery * temp; | ||
| 364 | if (transposeMode) | 359 | if (transposeMode) |
| 365 | { | 360 | { |
| 366 | rowGallery = targetGallery; | 361 | rowGallery = targetGallery; |
| 367 | colGallery = queryGallery; | 362 | colGallery = queryGallery; |
| 368 | - rowSize = targetMetadata.size(); | 363 | + temp = Gallery::make(targetGallery); |
| 369 | } | 364 | } |
| 370 | - | 365 | + else |
| 366 | + { | ||
| 367 | + temp = Gallery::make(queryGallery); | ||
| 368 | + } | ||
| 369 | + rowSize = temp->totalSize(); | ||
| 370 | + delete temp; | ||
| 371 | 371 | ||
| 372 | // Is the column gallery already enrolled? We keep the enrolled column gallery in memory, and in multi-process | 372 | // Is the column gallery already enrolled? We keep the enrolled column gallery in memory, and in multi-process |
| 373 | // mode, every worker process retains a copy of this gallery in memory. When not in multi-process mode, we can | 373 | // mode, every worker process retains a copy of this gallery in memory. When not in multi-process mode, we can |
| @@ -423,8 +423,6 @@ struct AlgorithmCore | @@ -423,8 +423,6 @@ struct AlgorithmCore | ||
| 423 | // progress counting step. | 423 | // progress counting step. |
| 424 | // After the base algorithm is built, the whole thing will be run in a stream, so that I/O can be handled sequentially. | 424 | // After the base algorithm is built, the whole thing will be run in a stream, so that I/O can be handled sequentially. |
| 425 | 425 | ||
| 426 | - | ||
| 427 | - | ||
| 428 | // The actual comparison step is done by a GalleryCompare transform, which has a Distance, and a gallery as data. | 426 | // The actual comparison step is done by a GalleryCompare transform, which has a Distance, and a gallery as data. |
| 429 | // Incoming templates are compared against the templates in the gallery, and the output is the resulting score | 427 | // Incoming templates are compared against the templates in the gallery, and the output is the resulting score |
| 430 | // vector. | 428 | // vector. |
openbr/openbr_plugin.cpp
| @@ -865,14 +865,14 @@ void br::Context::printStatus() | @@ -865,14 +865,14 @@ void br::Context::printStatus() | ||
| 865 | const float p = progress(); | 865 | const float p = progress(); |
| 866 | if (p < 1) { | 866 | if (p < 1) { |
| 867 | int s = timeRemaining(); | 867 | int s = timeRemaining(); |
| 868 | - fprintf(stderr, "%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g/%g \r", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(s).toStdString().c_str(), Globals->currentStep, Globals->totalSteps); | 868 | + 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); |
| 869 | } | 869 | } |
| 870 | } | 870 | } |
| 871 | 871 | ||
| 872 | float br::Context::progress() const | 872 | float br::Context::progress() const |
| 873 | { | 873 | { |
| 874 | if (totalSteps == 0) return -1; | 874 | if (totalSteps == 0) return -1; |
| 875 | - return currentStep / totalSteps; | 875 | + return currentProgress / totalSteps; |
| 876 | } | 876 | } |
| 877 | 877 | ||
| 878 | void br::Context::setProperty(const QString &key, const QString &value) | 878 | void br::Context::setProperty(const QString &key, const QString &value) |
openbr/openbr_plugin.h
| @@ -687,6 +687,10 @@ public: | @@ -687,6 +687,10 @@ public: | ||
| 687 | Q_PROPERTY(double currentStep READ get_currentStep WRITE set_currentStep RESET reset_currentStep) | 687 | Q_PROPERTY(double currentStep READ get_currentStep WRITE set_currentStep RESET reset_currentStep) |
| 688 | BR_PROPERTY(double, currentStep, 0) | 688 | BR_PROPERTY(double, currentStep, 0) |
| 689 | 689 | ||
| 690 | + Q_PROPERTY(double currentProgress READ get_currentProgress WRITE set_currentProgress RESET reset_currentProgress) | ||
| 691 | + BR_PROPERTY(double, currentProgress, 0) | ||
| 692 | + | ||
| 693 | + | ||
| 690 | /*! | 694 | /*! |
| 691 | * \brief Used internally to compute progress() and timeRemaining(). | 695 | * \brief Used internally to compute progress() and timeRemaining(). |
| 692 | */ | 696 | */ |
| @@ -1095,6 +1099,9 @@ public: | @@ -1095,6 +1099,9 @@ public: | ||
| 1095 | static Gallery *make(const File &file); /*!< \brief Make a gallery to/from a file on disk. */ | 1099 | static Gallery *make(const File &file); /*!< \brief Make a gallery to/from a file on disk. */ |
| 1096 | void init(); | 1100 | void init(); |
| 1097 | 1101 | ||
| 1102 | + virtual qint64 totalSize() { return std::numeric_limits<qint64>::max(); } | ||
| 1103 | + virtual qint64 position() { return 0; } | ||
| 1104 | + | ||
| 1098 | private: | 1105 | private: |
| 1099 | QSharedPointer<Gallery> next; | 1106 | QSharedPointer<Gallery> next; |
| 1100 | }; | 1107 | }; |
openbr/plugins/gallery.cpp
| @@ -23,6 +23,7 @@ | @@ -23,6 +23,7 @@ | ||
| 23 | #include <QSqlError> | 23 | #include <QSqlError> |
| 24 | #include <QSqlQuery> | 24 | #include <QSqlQuery> |
| 25 | #include <QSqlRecord> | 25 | #include <QSqlRecord> |
| 26 | +#include <QXmlStreamReader> | ||
| 26 | #endif // BR_EMBEDDED | 27 | #endif // BR_EMBEDDED |
| 27 | #include <opencv2/highgui/highgui.hpp> | 28 | #include <opencv2/highgui/highgui.hpp> |
| 28 | #include "openbr_internal.h" | 29 | #include "openbr_internal.h" |
| @@ -127,6 +128,7 @@ class galGallery : public Gallery | @@ -127,6 +128,7 @@ class galGallery : public Gallery | ||
| 127 | Template m; | 128 | Template m; |
| 128 | stream >> m; | 129 | stream >> m; |
| 129 | templates.append(m); | 130 | templates.append(m); |
| 131 | + templates.last().file.set("progress", totalSize()); | ||
| 130 | } | 132 | } |
| 131 | 133 | ||
| 132 | *done = stream.atEnd(); | 134 | *done = stream.atEnd(); |
| @@ -140,6 +142,17 @@ class galGallery : public Gallery | @@ -140,6 +142,17 @@ class galGallery : public Gallery | ||
| 140 | 142 | ||
| 141 | stream << t; | 143 | stream << t; |
| 142 | } | 144 | } |
| 145 | + | ||
| 146 | + qint64 totalSize() | ||
| 147 | + { | ||
| 148 | + return gallery.size(); | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + qint64 position() | ||
| 152 | + { | ||
| 153 | + return gallery.pos(); | ||
| 154 | + } | ||
| 155 | + | ||
| 143 | }; | 156 | }; |
| 144 | 157 | ||
| 145 | BR_REGISTER(Gallery, galGallery) | 158 | BR_REGISTER(Gallery, galGallery) |
| @@ -328,6 +341,7 @@ class memGallery : public Gallery | @@ -328,6 +341,7 @@ class memGallery : public Gallery | ||
| 328 | { | 341 | { |
| 329 | Q_OBJECT | 342 | Q_OBJECT |
| 330 | int block; | 343 | int block; |
| 344 | + qint64 gallerySize; | ||
| 331 | 345 | ||
| 332 | void init() | 346 | void init() |
| 333 | { | 347 | { |
| @@ -338,6 +352,7 @@ class memGallery : public Gallery | @@ -338,6 +352,7 @@ class memGallery : public Gallery | ||
| 338 | MemoryGalleries::galleries[file] = gallery->read(); | 352 | MemoryGalleries::galleries[file] = gallery->read(); |
| 339 | align(MemoryGalleries::galleries[file]); | 353 | align(MemoryGalleries::galleries[file]); |
| 340 | MemoryGalleries::aligned[file] = true; | 354 | MemoryGalleries::aligned[file] = true; |
| 355 | + gallerySize = MemoryGalleries::galleries[file].size(); | ||
| 341 | } | 356 | } |
| 342 | } | 357 | } |
| 343 | 358 | ||
| @@ -349,6 +364,10 @@ class memGallery : public Gallery | @@ -349,6 +364,10 @@ class memGallery : public Gallery | ||
| 349 | } | 364 | } |
| 350 | 365 | ||
| 351 | TemplateList templates = MemoryGalleries::galleries[file].mid(block*readBlockSize, readBlockSize); | 366 | TemplateList templates = MemoryGalleries::galleries[file].mid(block*readBlockSize, readBlockSize); |
| 367 | + for (qint64 i = 0; i < templates.size();i++) { | ||
| 368 | + templates[i].file.set("progress", i + block * readBlockSize); | ||
| 369 | + } | ||
| 370 | + | ||
| 352 | *done = (templates.size() < readBlockSize); | 371 | *done = (templates.size() < readBlockSize); |
| 353 | block = *done ? 0 : block+1; | 372 | block = *done ? 0 : block+1; |
| 354 | return templates; | 373 | return templates; |
| @@ -389,6 +408,16 @@ class memGallery : public Gallery | @@ -389,6 +408,16 @@ class memGallery : public Gallery | ||
| 389 | templates.alignedData = alignedData; | 408 | templates.alignedData = alignedData; |
| 390 | } | 409 | } |
| 391 | 410 | ||
| 411 | + qint64 totalSize() | ||
| 412 | + { | ||
| 413 | + return gallerySize; | ||
| 414 | + } | ||
| 415 | + | ||
| 416 | + qint64 position() | ||
| 417 | + { | ||
| 418 | + return block * readBlockSize; | ||
| 419 | + } | ||
| 420 | + | ||
| 392 | }; | 421 | }; |
| 393 | 422 | ||
| 394 | BR_REGISTER(Gallery, memGallery) | 423 | BR_REGISTER(Gallery, memGallery) |
| @@ -449,16 +478,19 @@ FileList FileList::fromGallery(const File & file, bool cache) | @@ -449,16 +478,19 @@ FileList FileList::fromGallery(const File & file, bool cache) | ||
| 449 | * | 478 | * |
| 450 | * \see txtGallery | 479 | * \see txtGallery |
| 451 | */ | 480 | */ |
| 452 | -class csvGallery : public Gallery | 481 | +class csvGallery : public FileGallery |
| 453 | { | 482 | { |
| 454 | Q_OBJECT | 483 | Q_OBJECT |
| 455 | Q_PROPERTY(int fileIndex READ get_fileIndex WRITE set_fileIndex RESET reset_fileIndex) | 484 | Q_PROPERTY(int fileIndex READ get_fileIndex WRITE set_fileIndex RESET reset_fileIndex) |
| 456 | BR_PROPERTY(int, fileIndex, 0) | 485 | BR_PROPERTY(int, fileIndex, 0) |
| 457 | 486 | ||
| 458 | FileList files; | 487 | FileList files; |
| 488 | + QStringList headers; | ||
| 459 | 489 | ||
| 460 | ~csvGallery() | 490 | ~csvGallery() |
| 461 | { | 491 | { |
| 492 | + f.close(); | ||
| 493 | + | ||
| 462 | if (files.isEmpty()) return; | 494 | if (files.isEmpty()) return; |
| 463 | 495 | ||
| 464 | QMap<QString,QVariant> samples; | 496 | QMap<QString,QVariant> samples; |
| @@ -496,25 +528,37 @@ class csvGallery : public Gallery | @@ -496,25 +528,37 @@ class csvGallery : public Gallery | ||
| 496 | 528 | ||
| 497 | TemplateList readBlock(bool *done) | 529 | TemplateList readBlock(bool *done) |
| 498 | { | 530 | { |
| 499 | - *done = true; | 531 | + *done = false; |
| 500 | TemplateList templates; | 532 | TemplateList templates; |
| 501 | - if (!file.exists()) return templates; | ||
| 502 | - | ||
| 503 | - QStringList lines = QtUtils::readLines(file); | 533 | + if (!file.exists()) { |
| 534 | + *done = true; | ||
| 535 | + return templates; | ||
| 536 | + } | ||
| 504 | QRegExp regexp("\\s*,\\s*"); | 537 | QRegExp regexp("\\s*,\\s*"); |
| 505 | - QStringList headers; | ||
| 506 | - if (!lines.isEmpty()) headers = lines.takeFirst().split(regexp); | ||
| 507 | 538 | ||
| 508 | - foreach (const QString &line, lines) { | 539 | + if (f.pos() == 0) |
| 540 | + { | ||
| 541 | + // read a line | ||
| 542 | + QByteArray lineBytes = f.readLine(); | ||
| 543 | + QString line = QString::fromLocal8Bit(lineBytes).trimmed(); | ||
| 544 | + headers = line.split(regexp); | ||
| 545 | + } | ||
| 546 | + | ||
| 547 | + for (qint64 i = 0; i < this->readBlockSize && !f.atEnd(); i++){ | ||
| 548 | + QByteArray lineBytes = f.readLine(); | ||
| 549 | + QString line = QString::fromLocal8Bit(lineBytes).trimmed(); | ||
| 550 | + | ||
| 509 | QStringList words = line.split(regexp); | 551 | QStringList words = line.split(regexp); |
| 510 | if (words.size() != headers.size()) continue; | 552 | if (words.size() != headers.size()) continue; |
| 511 | - File f; | ||
| 512 | - for (int i=0; i<words.size(); i++) { | ||
| 513 | - if (i == 0) f.name = words[i]; | ||
| 514 | - else f.set(headers[i], words[i]); | 553 | + File fi; |
| 554 | + for (int j=0; j<words.size(); j++) { | ||
| 555 | + if (j == 0) fi.name = words[j]; | ||
| 556 | + else fi.set(headers[j], words[j]); | ||
| 515 | } | 557 | } |
| 516 | - templates.append(f); | 558 | + templates.append(fi); |
| 559 | + templates.last().file.set("progress", f.pos()); | ||
| 517 | } | 560 | } |
| 561 | + *done = f.atEnd(); | ||
| 518 | 562 | ||
| 519 | return templates; | 563 | return templates; |
| 520 | } | 564 | } |
| @@ -568,18 +612,12 @@ BR_REGISTER(Gallery, csvGallery) | @@ -568,18 +612,12 @@ BR_REGISTER(Gallery, csvGallery) | ||
| 568 | \endverbatim | 612 | \endverbatim |
| 569 | * \see csvGallery | 613 | * \see csvGallery |
| 570 | */ | 614 | */ |
| 571 | -class txtGallery : public Gallery | 615 | +class txtGallery : public FileGallery |
| 572 | { | 616 | { |
| 573 | Q_OBJECT | 617 | Q_OBJECT |
| 574 | Q_PROPERTY(QString label READ get_label WRITE set_label RESET reset_label STORED false) | 618 | Q_PROPERTY(QString label READ get_label WRITE set_label RESET reset_label STORED false) |
| 575 | BR_PROPERTY(QString, label, "") | 619 | BR_PROPERTY(QString, label, "") |
| 576 | 620 | ||
| 577 | - QFile f; | ||
| 578 | - ~txtGallery() | ||
| 579 | - { | ||
| 580 | - f.close(); | ||
| 581 | - } | ||
| 582 | - | ||
| 583 | TemplateList readBlock(bool *done) | 621 | TemplateList readBlock(bool *done) |
| 584 | { | 622 | { |
| 585 | *done = false; | 623 | *done = false; |
| @@ -597,6 +635,7 @@ class txtGallery : public Gallery | @@ -597,6 +635,7 @@ class txtGallery : public Gallery | ||
| 597 | int splitIndex = line.lastIndexOf(' '); | 635 | int splitIndex = line.lastIndexOf(' '); |
| 598 | if (splitIndex == -1) templates.append(File(line)); | 636 | if (splitIndex == -1) templates.append(File(line)); |
| 599 | else templates.append(File(line.mid(0, splitIndex), line.mid(splitIndex+1))); | 637 | else templates.append(File(line.mid(0, splitIndex), line.mid(splitIndex+1))); |
| 638 | + templates.last().file.set("progress", this->position()); | ||
| 600 | } | 639 | } |
| 601 | 640 | ||
| 602 | if (f.atEnd()) { | 641 | if (f.atEnd()) { |
| @@ -608,14 +647,6 @@ class txtGallery : public Gallery | @@ -608,14 +647,6 @@ class txtGallery : public Gallery | ||
| 608 | return templates; | 647 | return templates; |
| 609 | } | 648 | } |
| 610 | 649 | ||
| 611 | - void init() | ||
| 612 | - { | ||
| 613 | - f.setFileName(file); | ||
| 614 | - QtUtils::touchDir(f); | ||
| 615 | - if (!f.open(QFile::ReadWrite)) | ||
| 616 | - qFatal("Failed to open %s for read/write.", qPrintable(file)); | ||
| 617 | - } | ||
| 618 | - | ||
| 619 | void write(const Template &t) | 650 | void write(const Template &t) |
| 620 | { | 651 | { |
| 621 | QString line = t.file.name; | 652 | QString line = t.file.name; |
| @@ -627,21 +658,16 @@ class txtGallery : public Gallery | @@ -627,21 +658,16 @@ class txtGallery : public Gallery | ||
| 627 | }; | 658 | }; |
| 628 | 659 | ||
| 629 | BR_REGISTER(Gallery, txtGallery) | 660 | BR_REGISTER(Gallery, txtGallery) |
| 661 | + | ||
| 630 | /*! | 662 | /*! |
| 631 | * \ingroup galleries | 663 | * \ingroup galleries |
| 632 | * \brief Treats each line as a call to File::flat() | 664 | * \brief Treats each line as a call to File::flat() |
| 633 | * \author Josh Klontz \cite jklontz | 665 | * \author Josh Klontz \cite jklontz |
| 634 | */ | 666 | */ |
| 635 | -class flatGallery : public Gallery | 667 | +class flatGallery : public FileGallery |
| 636 | { | 668 | { |
| 637 | Q_OBJECT | 669 | Q_OBJECT |
| 638 | 670 | ||
| 639 | - QFile f; | ||
| 640 | - ~flatGallery() | ||
| 641 | - { | ||
| 642 | - f.close(); | ||
| 643 | - } | ||
| 644 | - | ||
| 645 | TemplateList readBlock(bool *done) | 671 | TemplateList readBlock(bool *done) |
| 646 | { | 672 | { |
| 647 | *done = false; | 673 | *done = false; |
| @@ -654,8 +680,10 @@ class flatGallery : public Gallery | @@ -654,8 +680,10 @@ class flatGallery : public Gallery | ||
| 654 | { | 680 | { |
| 655 | QByteArray line = f.readLine(); | 681 | QByteArray line = f.readLine(); |
| 656 | 682 | ||
| 657 | - if (!line.isEmpty()) | 683 | + if (!line.isEmpty()) { |
| 658 | templates.append(File(QString::fromLocal8Bit(line).trimmed())); | 684 | templates.append(File(QString::fromLocal8Bit(line).trimmed())); |
| 685 | + templates.last().file.set("progress", this->position()); | ||
| 686 | + } | ||
| 659 | 687 | ||
| 660 | if (f.atEnd()) { | 688 | if (f.atEnd()) { |
| 661 | *done=true; | 689 | *done=true; |
| @@ -666,15 +694,6 @@ class flatGallery : public Gallery | @@ -666,15 +694,6 @@ class flatGallery : public Gallery | ||
| 666 | return templates; | 694 | return templates; |
| 667 | } | 695 | } |
| 668 | 696 | ||
| 669 | - void init() | ||
| 670 | - { | ||
| 671 | - f.setFileName(file); | ||
| 672 | - QtUtils::touchDir(f); | ||
| 673 | - if (!f.open(QFile::ReadWrite)) | ||
| 674 | - qFatal("Failed to open %s for read/write.", qPrintable(file)); | ||
| 675 | - | ||
| 676 | - } | ||
| 677 | - | ||
| 678 | void write(const Template &t) | 697 | void write(const Template &t) |
| 679 | { | 698 | { |
| 680 | f.write((t.file.flat()+"\n").toLocal8Bit() ); | 699 | f.write((t.file.flat()+"\n").toLocal8Bit() ); |
| @@ -688,29 +707,140 @@ BR_REGISTER(Gallery, flatGallery) | @@ -688,29 +707,140 @@ BR_REGISTER(Gallery, flatGallery) | ||
| 688 | * \brief A \ref sigset input. | 707 | * \brief A \ref sigset input. |
| 689 | * \author Josh Klontz \cite jklontz | 708 | * \author Josh Klontz \cite jklontz |
| 690 | */ | 709 | */ |
| 691 | -class xmlGallery : public Gallery | 710 | +class xmlGallery : public FileGallery |
| 692 | { | 711 | { |
| 693 | Q_OBJECT | 712 | Q_OBJECT |
| 694 | Q_PROPERTY(bool ignoreMetadata READ get_ignoreMetadata WRITE set_ignoreMetadata RESET reset_ignoreMetadata STORED false) | 713 | Q_PROPERTY(bool ignoreMetadata READ get_ignoreMetadata WRITE set_ignoreMetadata RESET reset_ignoreMetadata STORED false) |
| 695 | BR_PROPERTY(bool, ignoreMetadata, false) | 714 | BR_PROPERTY(bool, ignoreMetadata, false) |
| 696 | FileList files; | 715 | FileList files; |
| 697 | 716 | ||
| 717 | + QXmlStreamReader reader; | ||
| 718 | + | ||
| 719 | + QString currentSignatureName; | ||
| 720 | + bool signatureActive; | ||
| 721 | + | ||
| 698 | ~xmlGallery() | 722 | ~xmlGallery() |
| 699 | { | 723 | { |
| 724 | + f.close(); | ||
| 700 | if (!files.isEmpty()) | 725 | if (!files.isEmpty()) |
| 701 | BEE::writeSigset(file, files, ignoreMetadata); | 726 | BEE::writeSigset(file, files, ignoreMetadata); |
| 702 | } | 727 | } |
| 703 | 728 | ||
| 704 | TemplateList readBlock(bool *done) | 729 | TemplateList readBlock(bool *done) |
| 705 | { | 730 | { |
| 731 | + if (reader.atEnd()) | ||
| 732 | + f.seek(0); | ||
| 733 | + | ||
| 734 | + TemplateList templates; | ||
| 735 | + qint64 count = 0; | ||
| 736 | + while (!reader.atEnd()) | ||
| 737 | + { | ||
| 738 | + // if an identity is active we try to read presentations | ||
| 739 | + if (signatureActive) | ||
| 740 | + { | ||
| 741 | + while (signatureActive) | ||
| 742 | + { | ||
| 743 | + QXmlStreamReader::TokenType signatureToken = reader.readNext(); | ||
| 744 | + | ||
| 745 | + // did the signature end? | ||
| 746 | + if (signatureToken == QXmlStreamReader::EndElement && reader.name() == "biometric-signature") { | ||
| 747 | + signatureActive = false; | ||
| 748 | + break; | ||
| 749 | + } | ||
| 750 | + // did we reach the end of the document? Theoretically this shoudln't happen without reaching the end of | ||
| 751 | + if (signatureToken == QXmlStreamReader::EndDocument) | ||
| 752 | + break; | ||
| 753 | + | ||
| 754 | + // a presentation! | ||
| 755 | + if (signatureToken == QXmlStreamReader::StartElement && reader.name() == "presentation") { | ||
| 756 | + templates.append(Template(File("",currentSignatureName))); | ||
| 757 | + foreach (const QXmlStreamAttribute & attribute, reader.attributes()) { | ||
| 758 | + // file-name is stored directly on file, not as a key/value pair | ||
| 759 | + if (attribute.name() == "file-name") | ||
| 760 | + templates.last().file.name = attribute.value().toString(); | ||
| 761 | + // other values are directly set as metadata | ||
| 762 | + else if (!ignoreMetadata) templates.last().file.set(attribute.name().toString(), attribute.value().toString()); | ||
| 763 | + } | ||
| 764 | + | ||
| 765 | + // a presentation can have bounding boxes as child elements | ||
| 766 | + bool signatureActive = true; | ||
| 767 | + QList<QRectF> rects = templates.last().file.rects(); | ||
| 768 | + while (signatureActive) | ||
| 769 | + { | ||
| 770 | + QXmlStreamReader::TokenType pToken = reader.readNext(); | ||
| 771 | + if (pToken == QXmlStreamReader::EndElement && reader.name() == "presentation") | ||
| 772 | + break; | ||
| 773 | + | ||
| 774 | + if (pToken == QXmlStreamReader::StartElement) | ||
| 775 | + { | ||
| 776 | + // get boudning box properties as attributes, just going to assume this all works | ||
| 777 | + qreal x = reader.attributes().value("x").toDouble(); | ||
| 778 | + qreal y = reader.attributes().value("y").toDouble(); | ||
| 779 | + qreal width = reader.attributes().value("width").toDouble(); | ||
| 780 | + qreal height = reader.attributes().value("height").toDouble(); | ||
| 781 | + rects += QRectF(x, y, width, height); | ||
| 782 | + } | ||
| 783 | + } | ||
| 784 | + templates.last().file.setRects(rects); | ||
| 785 | + templates.last().file.set("progress", f.pos()); | ||
| 786 | + | ||
| 787 | + count++; | ||
| 788 | + if (count >= this->readBlockSize) { | ||
| 789 | + *done = false; | ||
| 790 | + return templates; | ||
| 791 | + } | ||
| 792 | + } | ||
| 793 | + } | ||
| 794 | + } | ||
| 795 | + // otherwise, keep reading elements until the next identity is reacehed | ||
| 796 | + else | ||
| 797 | + { | ||
| 798 | + QXmlStreamReader::TokenType token = reader.readNext(); | ||
| 799 | + | ||
| 800 | + // end of file? | ||
| 801 | + if (token == QXmlStreamReader::EndDocument) | ||
| 802 | + break; | ||
| 803 | + | ||
| 804 | + // we are only interested in new elements | ||
| 805 | + if (token != QXmlStreamReader::StartElement) | ||
| 806 | + continue; | ||
| 807 | + | ||
| 808 | + QStringRef elName = reader.name(); | ||
| 809 | + | ||
| 810 | + // biometric-signature-set is the root element | ||
| 811 | + if (elName == "biometric-signature-set") | ||
| 812 | + continue; | ||
| 813 | + | ||
| 814 | + // biometric-signature -- an identity | ||
| 815 | + if (elName == "biometric-signature") | ||
| 816 | + { | ||
| 817 | + // read the name associated with the current signature | ||
| 818 | + if (!reader.attributes().hasAttribute("name")) | ||
| 819 | + { | ||
| 820 | + qDebug() << "Biometric signature missing name"; | ||
| 821 | + continue; | ||
| 822 | + } | ||
| 823 | + currentSignatureName = reader.attributes().value("name").toString(); | ||
| 824 | + signatureActive = true; | ||
| 825 | + } | ||
| 826 | + } | ||
| 827 | + | ||
| 828 | + } | ||
| 706 | *done = true; | 829 | *done = true; |
| 707 | - return TemplateList(BEE::readSigset(file, ignoreMetadata)); | 830 | + |
| 831 | + return templates; | ||
| 708 | } | 832 | } |
| 709 | 833 | ||
| 710 | void write(const Template &t) | 834 | void write(const Template &t) |
| 711 | { | 835 | { |
| 712 | files.append(t.file); | 836 | files.append(t.file); |
| 713 | } | 837 | } |
| 838 | + | ||
| 839 | + void init() | ||
| 840 | + { | ||
| 841 | + FileGallery::init(); | ||
| 842 | + reader.setDevice(&f); | ||
| 843 | + } | ||
| 714 | }; | 844 | }; |
| 715 | 845 | ||
| 716 | BR_REGISTER(Gallery, xmlGallery) | 846 | BR_REGISTER(Gallery, xmlGallery) |
| @@ -1178,6 +1308,17 @@ BR_REGISTER(Gallery, vbbGallery) | @@ -1178,6 +1308,17 @@ BR_REGISTER(Gallery, vbbGallery) | ||
| 1178 | 1308 | ||
| 1179 | #endif | 1309 | #endif |
| 1180 | 1310 | ||
| 1311 | +void FileGallery::init() | ||
| 1312 | +{ | ||
| 1313 | + f.setFileName(file); | ||
| 1314 | + QtUtils::touchDir(f); | ||
| 1315 | + if (!f.open(QFile::ReadWrite)) | ||
| 1316 | + qFatal("Failed to open %s for read/write.", qPrintable(file)); | ||
| 1317 | + fileSize = f.size(); | ||
| 1318 | + | ||
| 1319 | + Gallery::init(); | ||
| 1320 | +} | ||
| 1321 | + | ||
| 1181 | } // namespace br | 1322 | } // namespace br |
| 1182 | 1323 | ||
| 1183 | #include "gallery.moc" | 1324 | #include "gallery.moc" |
openbr/plugins/misc.cpp
| @@ -517,14 +517,18 @@ class ProgressCounterTransform : public TimeVaryingTransform | @@ -517,14 +517,18 @@ class ProgressCounterTransform : public TimeVaryingTransform | ||
| 517 | 517 | ||
| 518 | qint64 elapsed = timer.elapsed(); | 518 | qint64 elapsed = timer.elapsed(); |
| 519 | 519 | ||
| 520 | + if (!dst.empty()) { | ||
| 521 | + Globals->currentProgress = dst.last().file.get<qint64>("progress",0); | ||
| 522 | + dst.last().file.remove("progress"); | ||
| 523 | + Globals->currentStep++; | ||
| 524 | + } | ||
| 525 | + | ||
| 520 | // updated every second | 526 | // updated every second |
| 521 | if (elapsed > 1000) { | 527 | if (elapsed > 1000) { |
| 522 | Globals->printStatus(); | 528 | Globals->printStatus(); |
| 523 | timer.start(); | 529 | timer.start(); |
| 524 | } | 530 | } |
| 525 | 531 | ||
| 526 | - Globals->currentStep++; | ||
| 527 | - | ||
| 528 | return; | 532 | return; |
| 529 | } | 533 | } |
| 530 | 534 | ||
| @@ -537,12 +541,13 @@ class ProgressCounterTransform : public TimeVaryingTransform | @@ -537,12 +541,13 @@ class ProgressCounterTransform : public TimeVaryingTransform | ||
| 537 | { | 541 | { |
| 538 | (void) data; | 542 | (void) data; |
| 539 | float p = br_progress(); | 543 | float p = br_progress(); |
| 540 | - qDebug("%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g/%g \r", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), Globals->currentStep, Globals->totalSteps); | 544 | + 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); |
| 541 | } | 545 | } |
| 542 | 546 | ||
| 543 | void init() | 547 | void init() |
| 544 | { | 548 | { |
| 545 | timer.start(); | 549 | timer.start(); |
| 550 | + Globals->currentStep = 0; | ||
| 546 | } | 551 | } |
| 547 | 552 | ||
| 548 | public: | 553 | public: |
| @@ -689,6 +694,40 @@ public: | @@ -689,6 +694,40 @@ public: | ||
| 689 | 694 | ||
| 690 | BR_REGISTER(Transform, OutputTransform) | 695 | BR_REGISTER(Transform, OutputTransform) |
| 691 | 696 | ||
| 697 | +class FileExclusionTransform : public UntrainableMetaTransform | ||
| 698 | +{ | ||
| 699 | + Q_OBJECT | ||
| 700 | + | ||
| 701 | + Q_PROPERTY(QString exclusionGallery READ get_exclusionGallery WRITE set_exclusionGallery RESET reset_exclusionGallery STORED false) | ||
| 702 | + BR_PROPERTY(QString, exclusionGallery, "") | ||
| 703 | + | ||
| 704 | + QSet<QString> excluded; | ||
| 705 | + | ||
| 706 | + void project(const Template & src, Template & dst) const | ||
| 707 | + { | ||
| 708 | + qFatal("FileExclusion can't do anything here"); | ||
| 709 | + } | ||
| 710 | + | ||
| 711 | + void project(const TemplateList &src, TemplateList &dst) const | ||
| 712 | + { | ||
| 713 | + foreach(const Template & srcTemp, src) | ||
| 714 | + { | ||
| 715 | + if (!excluded.contains(srcTemp.file)) | ||
| 716 | + dst.append(srcTemp); | ||
| 717 | + } | ||
| 718 | + } | ||
| 719 | + | ||
| 720 | + void init() | ||
| 721 | + { | ||
| 722 | + if (exclusionGallery.isEmpty()) | ||
| 723 | + return; | ||
| 724 | + FileList temp = FileList::fromGallery(exclusionGallery); | ||
| 725 | + excluded = QSet<QString>::fromList(temp.names()); | ||
| 726 | + } | ||
| 727 | +}; | ||
| 728 | + | ||
| 729 | +BR_REGISTER(Transform, FileExclusionTransform) | ||
| 730 | + | ||
| 692 | } | 731 | } |
| 693 | 732 | ||
| 694 | #include "misc.moc" | 733 | #include "misc.moc" |
openbr/plugins/openbr_internal.h
| @@ -345,6 +345,21 @@ protected: | @@ -345,6 +345,21 @@ protected: | ||
| 345 | UntrainableMetadataTransform() : MetadataTransform(false) {} | 345 | UntrainableMetadataTransform() : MetadataTransform(false) {} |
| 346 | }; | 346 | }; |
| 347 | 347 | ||
| 348 | +class FileGallery : public Gallery | ||
| 349 | +{ | ||
| 350 | + Q_OBJECT | ||
| 351 | +public: | ||
| 352 | + QFile f; | ||
| 353 | + qint64 fileSize; | ||
| 354 | + | ||
| 355 | + virtual ~FileGallery() { f.close(); } | ||
| 356 | + | ||
| 357 | + void init(); | ||
| 358 | + | ||
| 359 | + qint64 totalSize() { return fileSize; } | ||
| 360 | + qint64 position() { return f.pos(); } | ||
| 361 | +}; | ||
| 362 | + | ||
| 348 | } | 363 | } |
| 349 | 364 | ||
| 350 | #endif // OPENBR_INTERNAL_H | 365 | #endif // OPENBR_INTERNAL_H |
openbr/plugins/process.cpp
| @@ -497,6 +497,8 @@ class ProcessWrapperTransform : public TimeVaryingTransform | @@ -497,6 +497,8 @@ class ProcessWrapperTransform : public TimeVaryingTransform | ||
| 497 | 497 | ||
| 498 | void projectUpdate(const TemplateList &src, TemplateList &dst) | 498 | void projectUpdate(const TemplateList &src, TemplateList &dst) |
| 499 | { | 499 | { |
| 500 | + if (src.empty()) | ||
| 501 | + return; | ||
| 500 | 502 | ||
| 501 | if (!processActive) | 503 | if (!processActive) |
| 502 | { | 504 | { |