Commit ee6f9bbc83867fb79710659035f4bff6dadc2f10
1 parent
8a207670
Preliminary work on not loading complete galleries during enrollment
The basic idea is to read galleries incrementally, but there are some complications especially related to progress counting--if we don't read a gallery we don't know how many templates are stored in it since gallery formats aren't nice enough to provide headers with that information. One solution to the progress counting problem is to measure progress based on the position of a file pointer in the gallery file (i.e. measure the current position in the gallery file, divide by the total size of the gallery file). This is supported by expanding the Gallery API to include a totalSize method indicating the total size of the gallery file (or total number of templates if that is known), and then as templates are read, their position is stored in metadata (using the "p" key). Several galleries are updated to respect readBlockSize, and also to store position data in read templates. Support for filtering out already enrolled templates in read-mode was maintained by making the filtering an online process (part of the enrollment pipeline) rather than a batch process done before enrollment-proper starts.
Showing
7 changed files
with
291 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("p", 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("p", 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("p", 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("p", 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("p", 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("p", 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,17 @@ class ProgressCounterTransform : public TimeVaryingTransform | @@ -517,14 +517,17 @@ 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>("p",0); | ||
| 522 | + Globals->currentStep++; | ||
| 523 | + } | ||
| 524 | + | ||
| 520 | // updated every second | 525 | // updated every second |
| 521 | if (elapsed > 1000) { | 526 | if (elapsed > 1000) { |
| 522 | Globals->printStatus(); | 527 | Globals->printStatus(); |
| 523 | timer.start(); | 528 | timer.start(); |
| 524 | } | 529 | } |
| 525 | 530 | ||
| 526 | - Globals->currentStep++; | ||
| 527 | - | ||
| 528 | return; | 531 | return; |
| 529 | } | 532 | } |
| 530 | 533 | ||
| @@ -537,12 +540,13 @@ class ProgressCounterTransform : public TimeVaryingTransform | @@ -537,12 +540,13 @@ class ProgressCounterTransform : public TimeVaryingTransform | ||
| 537 | { | 540 | { |
| 538 | (void) data; | 541 | (void) data; |
| 539 | float p = br_progress(); | 542 | 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); | 543 | + 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 | } | 544 | } |
| 542 | 545 | ||
| 543 | void init() | 546 | void init() |
| 544 | { | 547 | { |
| 545 | timer.start(); | 548 | timer.start(); |
| 549 | + Globals->currentStep = 0; | ||
| 546 | } | 550 | } |
| 547 | 551 | ||
| 548 | public: | 552 | public: |
| @@ -689,6 +693,40 @@ public: | @@ -689,6 +693,40 @@ public: | ||
| 689 | 693 | ||
| 690 | BR_REGISTER(Transform, OutputTransform) | 694 | BR_REGISTER(Transform, OutputTransform) |
| 691 | 695 | ||
| 696 | +class FileExclusionTransform : public UntrainableMetaTransform | ||
| 697 | +{ | ||
| 698 | + Q_OBJECT | ||
| 699 | + | ||
| 700 | + Q_PROPERTY(QString exclusionGallery READ get_exclusionGallery WRITE set_exclusionGallery RESET reset_exclusionGallery STORED false) | ||
| 701 | + BR_PROPERTY(QString, exclusionGallery, "") | ||
| 702 | + | ||
| 703 | + QSet<QString> excluded; | ||
| 704 | + | ||
| 705 | + void project(const Template & src, Template & dst) const | ||
| 706 | + { | ||
| 707 | + qFatal("FileExclusion can't do anything here"); | ||
| 708 | + } | ||
| 709 | + | ||
| 710 | + void project(const TemplateList &src, TemplateList &dst) const | ||
| 711 | + { | ||
| 712 | + foreach(const Template & srcTemp, src) | ||
| 713 | + { | ||
| 714 | + if (!excluded.contains(srcTemp.file)) | ||
| 715 | + dst.append(srcTemp); | ||
| 716 | + } | ||
| 717 | + } | ||
| 718 | + | ||
| 719 | + void init() | ||
| 720 | + { | ||
| 721 | + if (exclusionGallery.isEmpty()) | ||
| 722 | + return; | ||
| 723 | + FileList temp = FileList::fromGallery(exclusionGallery); | ||
| 724 | + excluded = QSet<QString>::fromList(temp.names()); | ||
| 725 | + } | ||
| 726 | +}; | ||
| 727 | + | ||
| 728 | +BR_REGISTER(Transform, FileExclusionTransform) | ||
| 729 | + | ||
| 692 | } | 730 | } |
| 693 | 731 | ||
| 694 | #include "misc.moc" | 732 | #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 | { |