Commit 61a43e72af505bb90e215f00a1a8fd2968ff95b9

Authored by Scott Klum
2 parents 624bd7de b5bfce26

Merge branch 'master' of https://github.com/biometrics/openbr

openbr/core/core.cpp
... ... @@ -29,6 +29,9 @@ struct AlgorithmCore
29 29 QSharedPointer<Transform> transform;
30 30 QSharedPointer<Distance> distance;
31 31  
  32 + QString transformString;
  33 + QString distanceString;
  34 +
32 35 AlgorithmCore(const QString &name)
33 36 {
34 37 this->name = name;
... ... @@ -134,6 +137,8 @@ struct AlgorithmCore
134 137 }
135 138 TemplateList data(TemplateList::fromGallery(input));
136 139  
  140 + bool multiProcess = Globals->file.getBool("multiProcess", false);
  141 +
137 142 if (gallery.contains("append"))
138 143 {
139 144 // Remove any templates which are already in the gallery
... ... @@ -155,20 +160,27 @@ struct AlgorithmCore
155 160 Globals->currentStep = 0;
156 161 Globals->totalSteps = data.length();
157 162  
158   - // Trust me, this makes complete sense.
159   - // We're just going to make a pipe with a placeholder first transform
160   - QString pipeDesc = "Identity+GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(data.length())+")+Discard";
161   - QScopedPointer<Transform> basePipe(Transform::make(pipeDesc,NULL));
  163 + QScopedPointer<Transform> basePipe;
162 164  
163   - CompositeTransform * downcast = dynamic_cast<CompositeTransform *>(basePipe.data());
164   - if (downcast == NULL)
165   - qFatal("downcast failed?");
  165 + if (!multiProcess)
  166 + {
  167 + QString pipeDesc = "Identity+GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(data.length())+")+Discard";
  168 + basePipe.reset(Transform::make(pipeDesc,NULL));
  169 + CompositeTransform * downcast = dynamic_cast<CompositeTransform *>(basePipe.data());
  170 + if (downcast == NULL)
  171 + qFatal("downcast failed?");
166 172  
167   - // replace that placeholder with the current algorithm
168   - downcast->transforms[0] = this->transform.data();
  173 + // replace that placeholder with the current algorithm
  174 + downcast->transforms[0] = this->transform.data();
169 175  
170   - // call init on the pipe to collapse the algorithm (if its top level is a pipe)
171   - downcast->init();
  176 + // call init on the pipe to collapse the algorithm (if its top level is a pipe)
  177 + downcast->init();
  178 + }
  179 + else
  180 + {
  181 + QString pipeDesc = "ProcessWrapper("+transformString+")"+"+GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(data.length())+")+Discard";
  182 + basePipe.reset(Transform::make(pipeDesc,NULL));
  183 + }
172 184  
173 185 // Next, we make a Stream (with placeholder transform)
174 186 QString streamDesc = "Stream(Identity, readMode=DistributeFrames)";
... ... @@ -176,7 +188,7 @@ struct AlgorithmCore
176 188 WrapperTransform * wrapper = dynamic_cast<WrapperTransform *> (baseStream.data());
177 189  
178 190 // replace that placeholder with the pipe we built
179   - wrapper->transform = downcast;
  191 + wrapper->transform = basePipe.data();
180 192  
181 193 // and get the final stream's stages by reinterpreting the pipe. Perfectly straightforward.
182 194 wrapper->init();
... ... @@ -196,6 +208,38 @@ struct AlgorithmCore
196 208 data >> *transform;
197 209 }
198 210  
  211 + // Read metadata for all templates stored in the specified gallery, return the read
  212 + // TeamplateList. If the gallery contains matrices, they are dropped.
  213 + void emptyRead(const File & file, TemplateList & templates)
  214 + {
  215 + // Is this a gallery type containing matrices?
  216 + if ((QStringList() << "gal" << "mem" << "template").contains(file.suffix())) {
  217 + // Retrieve it block by block, dropping matrices from read templates.
  218 + QScopedPointer<Gallery> gallery(Gallery::make(file));
  219 + gallery->set_readBlockSize(10);
  220 + bool done = false;
  221 + while (!done)
  222 + {
  223 + TemplateList tList = gallery->readBlock(&done);
  224 + for (int i=0; i < tList.size();i++)
  225 + {
  226 + tList[i].clear();
  227 + templates.append(tList[i]);
  228 + }
  229 + }
  230 + }
  231 + else {
  232 + // The file may have already been enrolled to a memory gallery
  233 + emptyRead(getMemoryGallery(file), templates);
  234 + if (!templates.empty())
  235 + return;
  236 +
  237 + // Nope, just retrieve the metadata
  238 + QScopedPointer<Gallery> gallery(Gallery::make(file));
  239 + templates = gallery->read();
  240 + }
  241 + }
  242 +
199 243 void retrieveOrEnroll(const File &file, QScopedPointer<Gallery> &gallery, FileList &galleryFiles)
200 244 {
201 245 if (!file.getBool("enroll") && (QStringList() << "gal" << "mem" << "template").contains(file.suffix())) {
... ... @@ -241,17 +285,14 @@ struct AlgorithmCore
241 285 dummyTarget.append(targets[0]);
242 286 QScopedPointer<Output> realOutput(Output::make(output, dummyTarget, queryFiles));
243 287  
244   - // Some outputs assume Globals->blockSize is a real thing, of course we have no interest in it.
245   - int old_block_size = Globals->blockSize;
246   - Globals->blockSize = INT_MAX;
  288 + realOutput->set_blockRows(INT_MAX);
  289 + realOutput->set_blockCols(INT_MAX);
247 290 realOutput->setBlock(0,0);
248 291 for (int i=0; i < queries.length(); i++)
249 292 {
250 293 float res = distance->compare(queries[i], targets[i]);
251 294 realOutput->setRelative(res, 0,i);
252 295 }
253   -
254   - Globals->blockSize = old_block_size;
255 296 }
256 297  
257 298 void deduplicate(const File &inputGallery, const File &outputGallery, const float threshold)
... ... @@ -310,71 +351,154 @@ struct AlgorithmCore
310 351 qPrintable(queryGallery.flat()),
311 352 output.isNull() ? "" : qPrintable(" to " + output.flat()));
312 353  
  354 + bool multiProcess = Globals->file.getBool("multiProcess", false);
  355 +
313 356 if (output.exists() && output.get<bool>("cache", false)) return;
314 357 if (queryGallery == ".") queryGallery = targetGallery;
315 358  
316   - QScopedPointer<Gallery> t, q;
317   - FileList targetFiles, queryFiles;
318   - retrieveOrEnroll(targetGallery, t, targetFiles);
319   - retrieveOrEnroll(queryGallery, q, queryFiles);
  359 + // Read metadata for the target and query sets, the resulting
  360 + // TemplateLists do not contain matrices
  361 + TemplateList targetMetadata;
  362 + TemplateList queryMetadata;
320 363  
321   - QList<int> partitionSizes;
322   - QList<File> outputFiles;
323   - if (output.contains("split")) {
324   - if (!output.fileName().contains("%1")) qFatal("Output file name missing split number place marker (%%1)");
325   - partitionSizes = output.getList<int>("split");
326   - for (int i=0; i<partitionSizes.size(); i++) {
327   - File splitOutputFile = output.name.arg(i);
328   - outputFiles.append(splitOutputFile);
329   - }
330   - }
331   - else outputFiles.append(output);
  364 + emptyRead(targetGallery, targetMetadata);
  365 + emptyRead(queryGallery, queryMetadata);
332 366  
333   - QList<Output*> outputs;
334   - foreach (const File &outputFile, outputFiles) outputs.append(Output::make(outputFile, targetFiles, queryFiles));
  367 + // Enroll the metadata we read to memory galleries
  368 + File targetMetaMem = targetGallery;
  369 + targetMetaMem.name = targetMetaMem.baseName() + "_meta.mem";
  370 + File queryMetaMem = queryGallery;
  371 + queryMetaMem.name = queryMetaMem.baseName() + "_meta.mem";
335 372  
336   - if (distance.isNull()) qFatal("Null distance.");
337   - Globals->currentStep = 0;
338   - Globals->totalSteps = double(targetFiles.size()) * double(queryFiles.size());
339   - Globals->startTime.start();
  373 + // Store the metadata in memory galleries.
  374 + QScopedPointer<Gallery> targetMeta(Gallery::make(targetMetaMem));
  375 + QScopedPointer<Gallery> queryMeta(Gallery::make(queryMetaMem));
340 376  
341   - int queryBlock = -1;
342   - bool queryDone = false;
343   - while (!queryDone) {
344   - queryBlock++;
345   - TemplateList queries = q->readBlock(&queryDone);
  377 + targetMeta->writeBlock(targetMetadata);
  378 + queryMeta->writeBlock(queryMetadata);
346 379  
347   - QList<TemplateList> queryPartitions;
348   - if (!partitionSizes.empty()) queryPartitions = queries.partition(partitionSizes);
349   - else queryPartitions.append(queries);
350 380  
351   - for (int i=0; i<queryPartitions.size(); i++) {
352   - int targetBlock = -1;
353   - bool targetDone = false;
354   - while (!targetDone) {
355   - targetBlock++;
  381 + // Is the target or query set larger? We will use the larger as the rows of our comparison matrix (and transpose the output if necessary)
  382 + bool transposeCompare = targetMetadata.size() > queryMetadata.size();
356 383  
357   - TemplateList targets = t->readBlock(&targetDone);
  384 + File rowGallery = queryGallery;
  385 + File colGallery = targetGallery;
  386 + int rowSize = queryMetadata.size();
358 387  
359   - QList<TemplateList> targetPartitions;
360   - if (!partitionSizes.empty()) targetPartitions = targets.partition(partitionSizes);
361   - else targetPartitions.append(targets);
  388 + if (transposeCompare)
  389 + {
  390 + rowGallery = targetGallery;
  391 + colGallery = queryGallery;
  392 + rowSize = targetMetadata.size();
  393 + }
362 394  
363   - outputs[i]->setBlock(queryBlock, targetBlock);
  395 + // Do we need to enroll the row set? If so we will do it inline with the comparisons
  396 + bool needEnrollRows = false;
  397 + if (!(QStringList() << "gal" << "mem" << "template").contains(rowGallery.suffix()))
  398 + {
  399 + needEnrollRows = true;
  400 + }
364 401  
365   - distance->compare(targetPartitions[i], queryPartitions[i], outputs[i]);
  402 + // Do we need to enroll the column set? We want it to be in a memory gallery, unless we
  403 + // are in multi-process mode
  404 + File colEnrolledGallery = colGallery;
  405 + QString targetExtension = multiProcess ? "gal" : "mem";
  406 + if (colGallery.suffix() != targetExtension)
  407 + {
  408 + if (multiProcess) {
  409 + colEnrolledGallery = colGallery.baseName() + colGallery.hash() + ".gal";
  410 + }
  411 + else {
  412 + colEnrolledGallery = colGallery.baseName() + colGallery.hash() + ".mem";
  413 + }
366 414  
367   - Globals->currentStep += double(targets.size()) * double(queries.size());
368   - Globals->printStatus();
369   - }
  415 + // We have to do actual enrollment if the gallery just specified metadata
  416 + if (!(QStringList() << "gal" << "template" << "mem").contains(colGallery.suffix()))
  417 + {
  418 + enroll(colGallery, colEnrolledGallery);
  419 + }
  420 + // If it did specify templates, but wasn't the write type, we still need to convert
  421 + // to the correct gallery type.
  422 + else
  423 + {
  424 + QScopedPointer<Gallery> readColGallery(Gallery::make(colGallery));
  425 + TemplateList templates = readColGallery->read();
  426 + QScopedPointer<Gallery> enrolledColOutput(Gallery::make(colEnrolledGallery));
  427 + enrolledColOutput->writeBlock(templates);
370 428 }
371 429 }
372 430  
373   - qDeleteAll(outputs);
  431 + // Describe a GalleryCompare transform, using the data we enrolled
  432 + QString compareRegionDesc = "GalleryCompare("+Globals->algorithm + "," + colEnrolledGallery.flat() + ")";
  433 +
  434 + QScopedPointer<Transform> compareRegion;
  435 +
  436 + // If we need to enroll th row set, add the current transform to the aglorithm
  437 + if (needEnrollRows)
  438 + {
  439 + if (!multiProcess)
  440 + {
  441 + compareRegionDesc = "Identity+" + compareRegionDesc;
  442 + compareRegion.reset(Transform::make(compareRegionDesc,NULL));
  443 + CompositeTransform * downcast = dynamic_cast<CompositeTransform *> (compareRegion.data());
  444 + if (downcast == NULL)
  445 + qFatal("Pipe downcast failed in compare");
  446 +
  447 + downcast->transforms[0] = this->transform.data();
  448 + downcast->init();
  449 + }
  450 + else
  451 + {
  452 + compareRegionDesc = "ProcessWrapper(" + this->transformString + "+" + compareRegionDesc + ")";
  453 + compareRegion.reset(Transform::make(compareRegionDesc, NULL));
  454 + }
  455 + }
  456 + else {
  457 + compareRegion.reset(Transform::make(compareRegionDesc,NULL));
  458 + }
374 459  
375   - const float speed = 1000 * Globals->totalSteps / Globals->startTime.elapsed() / std::max(1, abs(Globals->parallelism));
376   - if (!Globals->quiet && (Globals->totalSteps > 1)) fprintf(stderr, "\rSPEED=%.1e \n", speed);
377   - Globals->totalSteps = 0;
  460 + compareRegion->init();
  461 +
  462 + // We also need to add Output and progress counting to the algorithm we are building
  463 + QString joinDesc = "Identity+Identity";
  464 + QScopedPointer<Transform> join(Transform::make(joinDesc, NULL));
  465 +
  466 + // The output transform takes the metadata memGalleries we set up previously as input, along with the
  467 + // output specification we were passed
  468 + QString outputRegionDesc = "Output("+ output.flat() +"," + targetMetaMem.flat() +"," + queryMetaMem.flat() + ","+ QString::number(transposeCompare ? 1 : 0) + ")";
  469 + outputRegionDesc += "+ProgressCounter("+QString::number(rowSize)+")+Discard";
  470 + QScopedPointer<Transform> outputTform(Transform::make(outputRegionDesc, NULL));
  471 +
  472 + CompositeTransform * downcast = dynamic_cast<CompositeTransform *> (join.data());
  473 + downcast->transforms[0] = compareRegion.data();
  474 + downcast->transforms[1] = outputTform.data();
  475 +
  476 + // With this, we have set up a transform which (optionally) enrolls templates, compares them
  477 + // against a gallery, and outputs them.
  478 + join->init();
  479 +
  480 +
  481 + // Now, we will give that base algorithm to a stream, operating in StreamGallery mode
  482 + QString streamDesc = "Stream(Identity, readMode=StreamGallery)";
  483 + QScopedPointer<Transform> streamBase(Transform::make(streamDesc, NULL));
  484 + WrapperTransform * streamWrapper = dynamic_cast<WrapperTransform *> (streamBase.data());
  485 + streamWrapper->transform = join.data();
  486 +
  487 + streamWrapper->init();
  488 +
  489 + // We set up a template containing the file iwth the row gallery we
  490 + // want to compare
  491 + TemplateList rowGalleryTemplate;
  492 + rowGalleryTemplate.append(Template(rowGallery));
  493 + TemplateList outputGallery;
  494 +
  495 + // for prgress counting
  496 + Globals->currentStep = 0;
  497 + Globals->totalSteps = rowSize;
  498 + Globals->startTime.start();
  499 +
  500 + // Do the actual comparisons
  501 + streamWrapper->projectUpdate(rowGalleryTemplate, outputGallery);
378 502 }
379 503  
380 504 private:
... ... @@ -407,10 +531,15 @@ private:
407 531 if ((words.size() < 1) || (words.size() > 2)) qFatal("Invalid algorithm format.");
408 532 //! [Parsing the algorithm description]
409 533  
  534 + transformString = words[0];
  535 +
410 536  
411 537 //! [Creating the template generation and comparison methods]
412 538 transform = QSharedPointer<Transform>(Transform::make(words[0], NULL));
413   - if (words.size() > 1) distance = QSharedPointer<Distance>(Distance::make(words[1], NULL));
  539 + if (words.size() > 1) {
  540 + distance = QSharedPointer<Distance>(Distance::make(words[1], NULL));
  541 + distanceString = words[1];
  542 + }
414 543 //! [Creating the template generation and comparison methods]
415 544 }
416 545 };
... ...
openbr/openbr_plugin.cpp
... ... @@ -1101,13 +1101,19 @@ void Output::initialize(const FileList &amp;targetFiles, const FileList &amp;queryFiles)
1101 1101 {
1102 1102 this->targetFiles = targetFiles;
1103 1103 this->queryFiles = queryFiles;
  1104 + if (this->blockRows == -1)
  1105 + blockRows = Globals->blockSize;
  1106 +
  1107 + if (this->blockCols == -1)
  1108 + blockCols = Globals->blockSize;
  1109 +
1104 1110 selfSimilar = (queryFiles == targetFiles) && (targetFiles.size() > 1) && (queryFiles.size() > 1);
1105 1111 }
1106 1112  
1107 1113 void Output::setBlock(int rowBlock, int columnBlock)
1108 1114 {
1109   - offset = QPoint((columnBlock == -1) ? 0 : Globals->blockSize*columnBlock,
1110   - (rowBlock == -1) ? 0 : Globals->blockSize*rowBlock);
  1115 + offset = QPoint((columnBlock == -1) ? 0 : blockCols*columnBlock,
  1116 + (rowBlock == -1) ? 0 : blockRows*rowBlock);
1111 1117 if (!next.isNull()) next->setBlock(rowBlock, columnBlock);
1112 1118 }
1113 1119  
... ...
openbr/openbr_plugin.h
... ... @@ -996,6 +996,11 @@ class BR_EXPORT Output : public Object
996 996 Q_OBJECT
997 997  
998 998 public:
  999 + Q_PROPERTY(int blockRows READ get_blockRows WRITE set_blockRows RESET reset_blockRows STORED false)
  1000 + Q_PROPERTY(int blockCols READ get_blockCols WRITE set_blockCols RESET reset_blockCols STORED false)
  1001 + BR_PROPERTY(int, blockRows, -1)
  1002 + BR_PROPERTY(int, blockCols, -1)
  1003 +
999 1004 FileList targetFiles; /*!< \brief List of files representing the gallery templates. */
1000 1005 FileList queryFiles; /*!< \brief List of files representing the probe templates. */
1001 1006 bool selfSimilar; /*!< \brief \c true if the \em targetFiles == \em queryFiles, \c false otherwise. */
... ... @@ -1074,9 +1079,11 @@ public:
1074 1079 */
1075 1080 class BR_EXPORT Gallery : public Object
1076 1081 {
1077   - Q_OBJECT
1078   -
  1082 + Q_OBJECT
1079 1083 public:
  1084 + Q_PROPERTY(int readBlockSize READ get_readBlockSize WRITE set_readBlockSize RESET reset_readBlockSize STORED false)
  1085 + BR_PROPERTY(int, readBlockSize, Globals->blockSize)
  1086 +
1080 1087 virtual ~Gallery() {}
1081 1088 TemplateList read(); /*!< \brief Retrieve all the stored templates. */
1082 1089 FileList files(); /*!< \brief Retrieve all the stored template files. */
... ...
openbr/plugins/distance.cpp
... ... @@ -460,12 +460,13 @@ BR_REGISTER(Distance, SumDistance)
460 460 class GalleryCompareTransform : public Transform
461 461 {
462 462 Q_OBJECT
463   - Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance STORED false)
  463 + Q_PROPERTY(QString distanceAlgorithm READ get_distanceAlgorithm WRITE set_distanceAlgorithm RESET reset_distanceAlgorithm STORED false)
464 464 Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false)
465   - BR_PROPERTY(br::Distance*, distance, NULL)
  465 + BR_PROPERTY(QString, distanceAlgorithm, "")
466 466 BR_PROPERTY(QString, galleryName, "")
467 467  
468 468 TemplateList gallery;
  469 + QSharedPointer<Distance> distance;
469 470  
470 471 void project(const Template &src, Template &dst) const
471 472 {
... ... @@ -479,8 +480,13 @@ class GalleryCompareTransform : public Transform
479 480  
480 481 void init()
481 482 {
482   - if (!galleryName.isEmpty())
  483 + if (!galleryName.isEmpty()) {
483 484 gallery = TemplateList::fromGallery(galleryName);
  485 + }
  486 + if (!distanceAlgorithm.isEmpty())
  487 + {
  488 + distance = Distance::fromAlgorithm(distanceAlgorithm);
  489 + }
484 490 }
485 491 };
486 492  
... ...
openbr/plugins/gallery.cpp
... ... @@ -123,7 +123,7 @@ class galGallery : public Gallery
123 123 gallery.seek(0);
124 124  
125 125 TemplateList templates;
126   - while ((templates.size() < Globals->blockSize) && !stream.atEnd()) {
  126 + while ((templates.size() < readBlockSize) && !stream.atEnd()) {
127 127 Template m;
128 128 stream >> m;
129 129 templates.append(m);
... ... @@ -348,8 +348,8 @@ class memGallery : public Gallery
348 348 MemoryGalleries::aligned[file] = true;
349 349 }
350 350  
351   - TemplateList templates = MemoryGalleries::galleries[file].mid(block*Globals->blockSize, Globals->blockSize);
352   - *done = (templates.size() < Globals->blockSize);
  351 + TemplateList templates = MemoryGalleries::galleries[file].mid(block*readBlockSize, readBlockSize);
  352 + *done = (templates.size() < readBlockSize);
353 353 block = *done ? 0 : block+1;
354 354 return templates;
355 355 }
... ...
openbr/plugins/misc.cpp
... ... @@ -552,6 +552,146 @@ public:
552 552  
553 553 BR_REGISTER(Transform, ProgressCounterTransform)
554 554  
  555 +
  556 +class OutputTransform : public TimeVaryingTransform
  557 +{
  558 + Q_OBJECT
  559 +
  560 + Q_PROPERTY(QString outputString READ get_outputString WRITE set_outputString RESET reset_outputString STORED false)
  561 + // names of mem galleries containing filelists we need.
  562 + Q_PROPERTY(QString targetName READ get_targetName WRITE set_targetName RESET reset_targetName STORED false)
  563 + Q_PROPERTY(QString queryName READ get_queryName WRITE set_queryName RESET reset_queryName STORED false)
  564 + Q_PROPERTY(bool transposeMode READ get_transposeMode WRITE set_transposeMode RESET reset_transposeMode STORED false)
  565 +
  566 + BR_PROPERTY(QString, outputString, "")
  567 + BR_PROPERTY(QString, targetName, "")
  568 + BR_PROPERTY(QString, queryName, "")
  569 +
  570 + BR_PROPERTY(bool,transposeMode, false)
  571 + ;
  572 +
  573 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  574 + {
  575 + dst = src;
  576 +
  577 + if (src.empty())
  578 + return;
  579 +
  580 + // we received a template, which is the next row/column in order
  581 + foreach(const Template & t, dst) {
  582 + for (int i=0; i < t.m().cols; i++)
  583 + {
  584 + output->setRelative(t.m().at<float>(0, i), currentRow, currentCol);
  585 +
  586 + // row-major input
  587 + if (!transposeMode)
  588 + currentCol++;
  589 + // col-major input
  590 + else
  591 + currentRow++;
  592 + }
  593 + // filled in a row, advance to the next, reset column position
  594 + if (!transposeMode) {
  595 + currentRow++;
  596 + currentCol = 0;
  597 + }
  598 + // filled in a column, advance, reset row
  599 + else {
  600 + currentCol++;
  601 + currentRow = 0;
  602 + }
  603 + }
  604 +
  605 + bool blockDone = false;
  606 + // In direct mode, we don't buffer rows
  607 + if (!transposeMode)
  608 + {
  609 + currentBlockRow++;
  610 + blockDone = true;
  611 + }
  612 + // in transpose mode, we buffer 100 cols before writing the block
  613 + else if (currentCol == bufferedSize)
  614 + {
  615 + currentBlockCol++;
  616 + blockDone = true;
  617 + }
  618 + else return;
  619 +
  620 + if (blockDone)
  621 + {
  622 + // set the next block, only necessary if we haven't buffered the current item
  623 + output->setBlock(currentBlockRow, currentBlockCol);
  624 + currentRow = 0;
  625 + currentCol = 0;
  626 + }
  627 + }
  628 +
  629 + void train(const TemplateList& data)
  630 + {
  631 + (void) data;
  632 + }
  633 +
  634 + void init()
  635 + {
  636 + if (targetName.isEmpty() || queryName.isEmpty() || outputString.isEmpty())
  637 + return;
  638 +
  639 + QScopedPointer<Gallery> tGallery(Gallery::make(targetName));
  640 + QScopedPointer<Gallery> qGallery(Gallery::make(queryName));
  641 +
  642 + FileList targetFiles = tGallery->files();
  643 + FileList queryFiles = qGallery->files();
  644 +
  645 + currentBlockRow = 0;
  646 + currentBlockCol = 0;
  647 +
  648 + currentRow = 0;
  649 + currentCol = 0;
  650 +
  651 + bufferedSize = 100;
  652 +
  653 + if (transposeMode)
  654 + {
  655 + // buffer 100 cols at a time
  656 + fragmentsPerRow = bufferedSize;
  657 + // a single col contains comparisons to all query files
  658 + fragmentsPerCol = queryFiles.size();
  659 + }
  660 + else
  661 + {
  662 + // a single row contains comparisons to all target files
  663 + fragmentsPerRow = targetFiles.size();
  664 + // we output rows one at a time
  665 + fragmentsPerCol = 1;
  666 + }
  667 +
  668 + output = QSharedPointer<Output>(Output::make(outputString, targetFiles, queryFiles));
  669 + output->blockRows = fragmentsPerCol;
  670 + output->blockCols = fragmentsPerRow;
  671 + output->initialize(targetFiles, queryFiles);
  672 +
  673 + output->setBlock(currentBlockRow, currentBlockCol);
  674 + }
  675 +
  676 + QSharedPointer<Output> output;
  677 +
  678 + int bufferedSize;
  679 +
  680 + int currentRow;
  681 + int currentCol;
  682 +
  683 + int currentBlockRow;
  684 + int currentBlockCol;
  685 +
  686 + int fragmentsPerRow;
  687 + int fragmentsPerCol;
  688 +
  689 +public:
  690 + OutputTransform() : TimeVaryingTransform(false,false) {}
  691 +};
  692 +
  693 +BR_REGISTER(Transform, OutputTransform)
  694 +
555 695 }
556 696  
557 697 #include "misc.moc"
... ...
openbr/plugins/output.cpp
... ... @@ -215,9 +215,11 @@ class mtxOutput : public Output
215 215  
216 216 this->rowBlock = rowBlock;
217 217 this->columnBlock = columnBlock;
218   - blockScores = cv::Mat(std::min(queryFiles.size()-rowBlock*Globals->blockSize, Globals->blockSize),
219   - std::min(targetFiles.size()-columnBlock*Globals->blockSize, Globals->blockSize),
220   - CV_32FC1);
  218 +
  219 + int matrixRows = std::min(queryFiles.size()-rowBlock*this->blockRows, blockRows);
  220 + int matrixCols = std::min(targetFiles.size()-columnBlock*this->blockCols, blockCols);
  221 +
  222 + blockScores = cv::Mat(matrixRows, matrixCols, CV_32FC1);
221 223 }
222 224  
223 225 void setRelative(float value, int i, int j)
... ... @@ -237,7 +239,7 @@ class mtxOutput : public Output
237 239 if (!f.open(QFile::ReadWrite))
238 240 qFatal("Unable to open %s for modifying.", qPrintable(file));
239 241 for (int i=0; i<blockScores.rows; i++) {
240   - f.seek(headerSize + sizeof(float)*(quint64(rowBlock*Globals->blockSize+i)*targetFiles.size()+(columnBlock*Globals->blockSize)));
  242 + f.seek(headerSize + sizeof(float)*(quint64(rowBlock*this->blockRows+i)*targetFiles.size()+(columnBlock*this->blockCols)));
241 243 f.write((const char*)blockScores.row(i).data, sizeof(float)*blockScores.cols);
242 244 }
243 245 f.close();
... ...
openbr/plugins/stream.cpp
... ... @@ -25,6 +25,7 @@ class Idiocy : public QObject
25 25 public:
26 26 enum StreamModes { StreamVideo,
27 27 DistributeFrames,
  28 + StreamGallery,
28 29 Auto};
29 30  
30 31 Q_ENUMS(StreamModes)
... ... @@ -288,6 +289,75 @@ protected:
288 289 };
289 290  
290 291  
  292 +class StreamGallery : public TemplateProcessor
  293 +{
  294 +public:
  295 + StreamGallery()
  296 + {
  297 +
  298 + }
  299 +
  300 + bool open(Template &input)
  301 + {
  302 + // Create a gallery
  303 + gallery = QSharedPointer<Gallery>(Gallery::make(input.file));
  304 + // Failed ot open the gallery?
  305 + if (gallery.isNull()) {
  306 + qDebug()<<"Failed to create gallery!";
  307 + galleryOk = false;
  308 + return false;
  309 + }
  310 +
  311 + // Set up state variables for future reads
  312 + galleryOk = true;
  313 + gallery->set_readBlockSize(100);
  314 + nextIdx = 0;
  315 + lastBlock = false;
  316 + return galleryOk;
  317 + }
  318 +
  319 + bool isOpen() { return galleryOk; }
  320 +
  321 + void close()
  322 + {
  323 + galleryOk = false;
  324 + currentData.clear();
  325 + nextIdx = 0;
  326 + lastBlock = true;
  327 + }
  328 +
  329 + bool getNextTemplate(Template & output)
  330 + {
  331 + // If we still have data available, we return one of those
  332 + if (nextIdx >= currentData.size())
  333 + {
  334 + // Otherwise, read another block
  335 + if (!lastBlock) {
  336 + currentData = gallery->readBlock(&lastBlock);
  337 + nextIdx = 0;
  338 + }
  339 + else
  340 + {
  341 + galleryOk = false;
  342 + return false;
  343 + }
  344 + }
  345 + // Return the indicated template, and advance the index
  346 + output = currentData[nextIdx++];
  347 + return true;
  348 + }
  349 +
  350 +protected:
  351 +
  352 + QSharedPointer<Gallery> gallery;
  353 + bool galleryOk;
  354 + bool lastBlock;
  355 +
  356 + TemplateList currentData;
  357 + int nextIdx;
  358 +
  359 +};
  360 +
291 361 class DirectReturn : public TemplateProcessor
292 362 {
293 363 public:
... ... @@ -731,6 +801,11 @@ protected:
731 801 if (!frameSource)
732 802 frameSource = new DirectReturn();
733 803 }
  804 + else if (mode == br::Idiocy::StreamGallery)
  805 + {
  806 + if (!frameSource)
  807 + frameSource = new StreamGallery();
  808 + }
734 809 else if (mode == br::Idiocy::StreamVideo)
735 810 {
736 811 if (!frameSource) {
... ...