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,6 +29,9 @@ struct AlgorithmCore
29 QSharedPointer<Transform> transform; 29 QSharedPointer<Transform> transform;
30 QSharedPointer<Distance> distance; 30 QSharedPointer<Distance> distance;
31 31
  32 + QString transformString;
  33 + QString distanceString;
  34 +
32 AlgorithmCore(const QString &name) 35 AlgorithmCore(const QString &name)
33 { 36 {
34 this->name = name; 37 this->name = name;
@@ -134,6 +137,8 @@ struct AlgorithmCore @@ -134,6 +137,8 @@ struct AlgorithmCore
134 } 137 }
135 TemplateList data(TemplateList::fromGallery(input)); 138 TemplateList data(TemplateList::fromGallery(input));
136 139
  140 + bool multiProcess = Globals->file.getBool("multiProcess", false);
  141 +
137 if (gallery.contains("append")) 142 if (gallery.contains("append"))
138 { 143 {
139 // Remove any templates which are already in the gallery 144 // Remove any templates which are already in the gallery
@@ -155,20 +160,27 @@ struct AlgorithmCore @@ -155,20 +160,27 @@ struct AlgorithmCore
155 Globals->currentStep = 0; 160 Globals->currentStep = 0;
156 Globals->totalSteps = data.length(); 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 // Next, we make a Stream (with placeholder transform) 185 // Next, we make a Stream (with placeholder transform)
174 QString streamDesc = "Stream(Identity, readMode=DistributeFrames)"; 186 QString streamDesc = "Stream(Identity, readMode=DistributeFrames)";
@@ -176,7 +188,7 @@ struct AlgorithmCore @@ -176,7 +188,7 @@ struct AlgorithmCore
176 WrapperTransform * wrapper = dynamic_cast<WrapperTransform *> (baseStream.data()); 188 WrapperTransform * wrapper = dynamic_cast<WrapperTransform *> (baseStream.data());
177 189
178 // replace that placeholder with the pipe we built 190 // replace that placeholder with the pipe we built
179 - wrapper->transform = downcast; 191 + wrapper->transform = basePipe.data();
180 192
181 // and get the final stream's stages by reinterpreting the pipe. Perfectly straightforward. 193 // and get the final stream's stages by reinterpreting the pipe. Perfectly straightforward.
182 wrapper->init(); 194 wrapper->init();
@@ -196,6 +208,38 @@ struct AlgorithmCore @@ -196,6 +208,38 @@ struct AlgorithmCore
196 data >> *transform; 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 void retrieveOrEnroll(const File &file, QScopedPointer<Gallery> &gallery, FileList &galleryFiles) 243 void retrieveOrEnroll(const File &file, QScopedPointer<Gallery> &gallery, FileList &galleryFiles)
200 { 244 {
201 if (!file.getBool("enroll") && (QStringList() << "gal" << "mem" << "template").contains(file.suffix())) { 245 if (!file.getBool("enroll") && (QStringList() << "gal" << "mem" << "template").contains(file.suffix())) {
@@ -241,17 +285,14 @@ struct AlgorithmCore @@ -241,17 +285,14 @@ struct AlgorithmCore
241 dummyTarget.append(targets[0]); 285 dummyTarget.append(targets[0]);
242 QScopedPointer<Output> realOutput(Output::make(output, dummyTarget, queryFiles)); 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 realOutput->setBlock(0,0); 290 realOutput->setBlock(0,0);
248 for (int i=0; i < queries.length(); i++) 291 for (int i=0; i < queries.length(); i++)
249 { 292 {
250 float res = distance->compare(queries[i], targets[i]); 293 float res = distance->compare(queries[i], targets[i]);
251 realOutput->setRelative(res, 0,i); 294 realOutput->setRelative(res, 0,i);
252 } 295 }
253 -  
254 - Globals->blockSize = old_block_size;  
255 } 296 }
256 297
257 void deduplicate(const File &inputGallery, const File &outputGallery, const float threshold) 298 void deduplicate(const File &inputGallery, const File &outputGallery, const float threshold)
@@ -310,71 +351,154 @@ struct AlgorithmCore @@ -310,71 +351,154 @@ struct AlgorithmCore
310 qPrintable(queryGallery.flat()), 351 qPrintable(queryGallery.flat()),
311 output.isNull() ? "" : qPrintable(" to " + output.flat())); 352 output.isNull() ? "" : qPrintable(" to " + output.flat()));
312 353
  354 + bool multiProcess = Globals->file.getBool("multiProcess", false);
  355 +
313 if (output.exists() && output.get<bool>("cache", false)) return; 356 if (output.exists() && output.get<bool>("cache", false)) return;
314 if (queryGallery == ".") queryGallery = targetGallery; 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 private: 504 private:
@@ -407,10 +531,15 @@ private: @@ -407,10 +531,15 @@ private:
407 if ((words.size() < 1) || (words.size() > 2)) qFatal("Invalid algorithm format."); 531 if ((words.size() < 1) || (words.size() > 2)) qFatal("Invalid algorithm format.");
408 //! [Parsing the algorithm description] 532 //! [Parsing the algorithm description]
409 533
  534 + transformString = words[0];
  535 +
410 536
411 //! [Creating the template generation and comparison methods] 537 //! [Creating the template generation and comparison methods]
412 transform = QSharedPointer<Transform>(Transform::make(words[0], NULL)); 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 //! [Creating the template generation and comparison methods] 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,13 +1101,19 @@ void Output::initialize(const FileList &amp;targetFiles, const FileList &amp;queryFiles)
1101 { 1101 {
1102 this->targetFiles = targetFiles; 1102 this->targetFiles = targetFiles;
1103 this->queryFiles = queryFiles; 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 selfSimilar = (queryFiles == targetFiles) && (targetFiles.size() > 1) && (queryFiles.size() > 1); 1110 selfSimilar = (queryFiles == targetFiles) && (targetFiles.size() > 1) && (queryFiles.size() > 1);
1105 } 1111 }
1106 1112
1107 void Output::setBlock(int rowBlock, int columnBlock) 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 if (!next.isNull()) next->setBlock(rowBlock, columnBlock); 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,6 +996,11 @@ class BR_EXPORT Output : public Object
996 Q_OBJECT 996 Q_OBJECT
997 997
998 public: 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 FileList targetFiles; /*!< \brief List of files representing the gallery templates. */ 1004 FileList targetFiles; /*!< \brief List of files representing the gallery templates. */
1000 FileList queryFiles; /*!< \brief List of files representing the probe templates. */ 1005 FileList queryFiles; /*!< \brief List of files representing the probe templates. */
1001 bool selfSimilar; /*!< \brief \c true if the \em targetFiles == \em queryFiles, \c false otherwise. */ 1006 bool selfSimilar; /*!< \brief \c true if the \em targetFiles == \em queryFiles, \c false otherwise. */
@@ -1074,9 +1079,11 @@ public: @@ -1074,9 +1079,11 @@ public:
1074 */ 1079 */
1075 class BR_EXPORT Gallery : public Object 1080 class BR_EXPORT Gallery : public Object
1076 { 1081 {
1077 - Q_OBJECT  
1078 - 1082 + Q_OBJECT
1079 public: 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 virtual ~Gallery() {} 1087 virtual ~Gallery() {}
1081 TemplateList read(); /*!< \brief Retrieve all the stored templates. */ 1088 TemplateList read(); /*!< \brief Retrieve all the stored templates. */
1082 FileList files(); /*!< \brief Retrieve all the stored template files. */ 1089 FileList files(); /*!< \brief Retrieve all the stored template files. */
openbr/plugins/distance.cpp
@@ -460,12 +460,13 @@ BR_REGISTER(Distance, SumDistance) @@ -460,12 +460,13 @@ BR_REGISTER(Distance, SumDistance)
460 class GalleryCompareTransform : public Transform 460 class GalleryCompareTransform : public Transform
461 { 461 {
462 Q_OBJECT 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 Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false) 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 BR_PROPERTY(QString, galleryName, "") 466 BR_PROPERTY(QString, galleryName, "")
467 467
468 TemplateList gallery; 468 TemplateList gallery;
  469 + QSharedPointer<Distance> distance;
469 470
470 void project(const Template &src, Template &dst) const 471 void project(const Template &src, Template &dst) const
471 { 472 {
@@ -479,8 +480,13 @@ class GalleryCompareTransform : public Transform @@ -479,8 +480,13 @@ class GalleryCompareTransform : public Transform
479 480
480 void init() 481 void init()
481 { 482 {
482 - if (!galleryName.isEmpty()) 483 + if (!galleryName.isEmpty()) {
483 gallery = TemplateList::fromGallery(galleryName); 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,7 +123,7 @@ class galGallery : public Gallery
123 gallery.seek(0); 123 gallery.seek(0);
124 124
125 TemplateList templates; 125 TemplateList templates;
126 - while ((templates.size() < Globals->blockSize) && !stream.atEnd()) { 126 + while ((templates.size() < readBlockSize) && !stream.atEnd()) {
127 Template m; 127 Template m;
128 stream >> m; 128 stream >> m;
129 templates.append(m); 129 templates.append(m);
@@ -348,8 +348,8 @@ class memGallery : public Gallery @@ -348,8 +348,8 @@ class memGallery : public Gallery
348 MemoryGalleries::aligned[file] = true; 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 block = *done ? 0 : block+1; 353 block = *done ? 0 : block+1;
354 return templates; 354 return templates;
355 } 355 }
openbr/plugins/misc.cpp
@@ -552,6 +552,146 @@ public: @@ -552,6 +552,146 @@ public:
552 552
553 BR_REGISTER(Transform, ProgressCounterTransform) 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 #include "misc.moc" 697 #include "misc.moc"
openbr/plugins/output.cpp
@@ -215,9 +215,11 @@ class mtxOutput : public Output @@ -215,9 +215,11 @@ class mtxOutput : public Output
215 215
216 this->rowBlock = rowBlock; 216 this->rowBlock = rowBlock;
217 this->columnBlock = columnBlock; 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 void setRelative(float value, int i, int j) 225 void setRelative(float value, int i, int j)
@@ -237,7 +239,7 @@ class mtxOutput : public Output @@ -237,7 +239,7 @@ class mtxOutput : public Output
237 if (!f.open(QFile::ReadWrite)) 239 if (!f.open(QFile::ReadWrite))
238 qFatal("Unable to open %s for modifying.", qPrintable(file)); 240 qFatal("Unable to open %s for modifying.", qPrintable(file));
239 for (int i=0; i<blockScores.rows; i++) { 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 f.write((const char*)blockScores.row(i).data, sizeof(float)*blockScores.cols); 243 f.write((const char*)blockScores.row(i).data, sizeof(float)*blockScores.cols);
242 } 244 }
243 f.close(); 245 f.close();
openbr/plugins/stream.cpp
@@ -25,6 +25,7 @@ class Idiocy : public QObject @@ -25,6 +25,7 @@ class Idiocy : public QObject
25 public: 25 public:
26 enum StreamModes { StreamVideo, 26 enum StreamModes { StreamVideo,
27 DistributeFrames, 27 DistributeFrames,
  28 + StreamGallery,
28 Auto}; 29 Auto};
29 30
30 Q_ENUMS(StreamModes) 31 Q_ENUMS(StreamModes)
@@ -288,6 +289,75 @@ protected: @@ -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 class DirectReturn : public TemplateProcessor 361 class DirectReturn : public TemplateProcessor
292 { 362 {
293 public: 363 public:
@@ -731,6 +801,11 @@ protected: @@ -731,6 +801,11 @@ protected:
731 if (!frameSource) 801 if (!frameSource)
732 frameSource = new DirectReturn(); 802 frameSource = new DirectReturn();
733 } 803 }
  804 + else if (mode == br::Idiocy::StreamGallery)
  805 + {
  806 + if (!frameSource)
  807 + frameSource = new StreamGallery();
  808 + }
734 else if (mode == br::Idiocy::StreamVideo) 809 else if (mode == br::Idiocy::StreamVideo)
735 { 810 {
736 if (!frameSource) { 811 if (!frameSource) {