Commit 36d2607d60d85383c75edfd11a401aa4b8baece7

Authored by caotto
2 parents 496bc87c 5c6a8fab

Merge pull request #216 from biometrics/serialization_update

Better support for serializing algorithms in memory
CMakeLists.txt
@@ -121,7 +121,7 @@ else() @@ -121,7 +121,7 @@ else()
121 set(CMAKE_EXE_LINKER_FLAGS "-Wl,--enable-auto-import") # Fixes a linker warning 121 set(CMAKE_EXE_LINKER_FLAGS "-Wl,--enable-auto-import") # Fixes a linker warning
122 set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--enable-auto-import") 122 set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--enable-auto-import")
123 elseif(MSVC) 123 elseif(MSVC)
124 - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /DNOMINMAX /D_CRT_SECURE_NO_WARNINGS /wd4018 /wd4244 /wd4267 /wd4305 /wd4308 /wd4307 /wd4554 /wd4996 /nologo /MP") 124 + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W3 /DNOMINMAX /D_CRT_SECURE_NO_WARNINGS /wd4018 /wd4244 /wd4267 /wd4305 /wd4308 /wd4307 /wd4554 /wd4996 /w34100 /nologo /MP")
125 endif() 125 endif()
126 endif() 126 endif()
127 127
openbr/core/core.cpp
@@ -23,24 +23,36 @@ @@ -23,24 +23,36 @@
23 23
24 namespace br { 24 namespace br {
25 25
  26 +void noDelete(Transform *target)
  27 +{
  28 + (void) target;
  29 +}
  30 +
26 struct AlgorithmCore 31 struct AlgorithmCore
27 { 32 {
  33 + enum CompareMode
  34 + {
  35 + None,
  36 + DistanceCompare,
  37 + TransformCompare,
  38 + };
  39 +
28 QSharedPointer<Transform> transform; 40 QSharedPointer<Transform> transform;
  41 + QSharedPointer<Transform> simplifiedTransform;
  42 + QSharedPointer<Transform> comparison;
29 QSharedPointer<Distance> distance; 43 QSharedPointer<Distance> distance;
30 - QString galleryCompareString;  
31 -  
32 - QString transformString;  
33 - QString distanceString; 44 + QSharedPointer<Transform> progressCounter;
34 45
35 AlgorithmCore(const QString &name) 46 AlgorithmCore(const QString &name)
36 { 47 {
37 this->name = name; 48 this->name = name;
38 init(name); 49 init(name);
  50 + progressCounter = QSharedPointer<Transform>(Transform::make("ProgressCounter", NULL));
39 } 51 }
40 52
41 bool isClassifier() const 53 bool isClassifier() const
42 { 54 {
43 - return distance.isNull(); 55 + return comparison.isNull();
44 } 56 }
45 57
46 void train(const File &input, const QString &model) 58 void train(const File &input, const QString &model)
@@ -48,15 +60,7 @@ struct AlgorithmCore @@ -48,15 +60,7 @@ struct AlgorithmCore
48 qDebug("Training on %s%s", qPrintable(input.flat()), 60 qDebug("Training on %s%s", qPrintable(input.flat()),
49 model.isEmpty() ? "" : qPrintable(" to " + model)); 61 model.isEmpty() ? "" : qPrintable(" to " + model));
50 62
51 - QScopedPointer<Transform> trainingWrapper(Transform::make("DirectStream(readMode=DistributeFrames)", NULL));  
52 -  
53 - CompositeTransform *downcast = dynamic_cast<CompositeTransform *>(trainingWrapper.data());  
54 - if (downcast == NULL)  
55 - qFatal("downcast failed?");  
56 - downcast->transforms.append(this->transform.data());  
57 -  
58 - downcast->init();  
59 - 63 + QScopedPointer<Transform> trainingWrapper(br::wrapTransform(transform.data(), "Stream(readMode=DistributeFrames)"));
60 TemplateList data(TemplateList::fromGallery(input)); 64 TemplateList data(TemplateList::fromGallery(input));
61 65
62 if (transform.isNull()) qFatal("Null transform."); 66 if (transform.isNull()) qFatal("Null transform.");
@@ -65,14 +69,14 @@ struct AlgorithmCore @@ -65,14 +69,14 @@ struct AlgorithmCore
65 Globals->startTime.start(); 69 Globals->startTime.start();
66 70
67 qDebug("Training Enrollment"); 71 qDebug("Training Enrollment");
68 - downcast->train(data); 72 + trainingWrapper->train(data);
69 73
70 if (!distance.isNull()) { 74 if (!distance.isNull()) {
71 if (Globals->crossValidate > 0) 75 if (Globals->crossValidate > 0)
72 for (int i=data.size()-1; i>=0; i--) if (data[i].file.get<bool>("allPartitions",false)) data.removeAt(i); 76 for (int i=data.size()-1; i>=0; i--) if (data[i].file.get<bool>("allPartitions",false)) data.removeAt(i);
73 77
74 qDebug("Projecting Enrollment"); 78 qDebug("Projecting Enrollment");
75 - downcast->projectUpdate(data,data); 79 + trainingWrapper->projectUpdate(data,data);
76 80
77 qDebug("Training Comparison"); 81 qDebug("Training Comparison");
78 distance->train(data); 82 distance->train(data);
@@ -84,6 +88,18 @@ struct AlgorithmCore @@ -84,6 +88,18 @@ struct AlgorithmCore
84 } 88 }
85 89
86 qDebug("Training Time: %s", qPrintable(QtUtils::toTime(Globals->startTime.elapsed()/1000.0f))); 90 qDebug("Training Time: %s", qPrintable(QtUtils::toTime(Globals->startTime.elapsed()/1000.0f)));
  91 +
  92 + simplifyTransform();
  93 + }
  94 +
  95 + void simplifyTransform()
  96 + {
  97 + bool newTForm = false;
  98 + Transform *temp = transform->simplify(newTForm);
  99 + if (newTForm)
  100 + simplifiedTransform = QSharedPointer<Transform>(temp);
  101 + else
  102 + simplifiedTransform = QSharedPointer<Transform>(temp, noDelete);
87 } 103 }
88 104
89 void store(const QString &model) const 105 void store(const QString &model) const
@@ -93,11 +109,21 @@ struct AlgorithmCore @@ -93,11 +109,21 @@ struct AlgorithmCore
93 QDataStream out(&data, QFile::WriteOnly); 109 QDataStream out(&data, QFile::WriteOnly);
94 110
95 // Serialize algorithm to stream 111 // Serialize algorithm to stream
96 - out << name;  
97 - transform->store(out);  
98 - const bool hasComparer = !distance.isNull();  
99 - out << hasComparer;  
100 - if (hasComparer) distance->store(out); 112 + transform->serialize(out);
  113 +
  114 + qint32 mode = None;
  115 + if (!distance.isNull())
  116 + mode = DistanceCompare;
  117 + else if (!comparison.isNull())
  118 + mode = TransformCompare;
  119 +
  120 + out << mode;
  121 +
  122 + if (mode == DistanceCompare)
  123 + distance->serialize(out);
  124 +
  125 + if (mode == TransformCompare)
  126 + comparison->serialize(out);
101 127
102 // Compress and save to file 128 // Compress and save to file
103 QtUtils::writeFile(model, data, -1); 129 QtUtils::writeFile(model, data, -1);
@@ -113,10 +139,21 @@ struct AlgorithmCore @@ -113,10 +139,21 @@ struct AlgorithmCore
113 QDataStream in(&data, QFile::ReadOnly); 139 QDataStream in(&data, QFile::ReadOnly);
114 140
115 // Load algorithm 141 // Load algorithm
116 - in >> name; init(Globals->abbreviations.contains(name) ? Globals->abbreviations[name] : name);  
117 - transform->load(in);  
118 - bool hasDistance; in >> hasDistance;  
119 - if (hasDistance) distance->load(in); 142 + transform = QSharedPointer<Transform>(Transform::deserialize(in));
  143 +
  144 + qint32 mode;
  145 + in >> mode;
  146 +
  147 + if (mode == DistanceCompare) {
  148 + QString distanceDescription;
  149 + in >> distanceDescription;
  150 + distance = QSharedPointer<Distance>(Distance::make(distanceDescription, NULL));
  151 + distance->load(in);
  152 + comparison = QSharedPointer<Transform>(Transform::make("GalleryCompare", NULL));
  153 + comparison->setPropertyRecursive("distance", QVariant::fromValue(distance.data()));
  154 + }
  155 + if (mode == TransformCompare)
  156 + comparison = QSharedPointer<Transform>(Transform::deserialize(in));
120 } 157 }
121 158
122 File getMemoryGallery(const File &file) const 159 File getMemoryGallery(const File &file) const
@@ -148,54 +185,38 @@ struct AlgorithmCore @@ -148,54 +185,38 @@ struct AlgorithmCore
148 Gallery *temp = Gallery::make(input); 185 Gallery *temp = Gallery::make(input);
149 qint64 total = temp->totalSize(); 186 qint64 total = temp->totalSize();
150 187
151 - QScopedPointer<Transform> basePipe;  
152 -  
153 - QString pipeDesc = "GalleryOutput("+gallery.flat()+")+ProgressCounter("+QString::number(total)+")+Discard"; 188 + Transform *enroll = simplifiedTransform.data();
154 189
155 - if (!multiProcess) {  
156 - basePipe.reset(Transform::make(pipeDesc,NULL));  
157 - CompositeTransform *downcast = dynamic_cast<CompositeTransform *>(basePipe.data()); 190 + if (multiProcess)
  191 + enroll = wrapTransform(enroll, "ProcessWrapper");
158 192
159 - if (downcast == NULL) qFatal("downcast failed?");  
160 -  
161 - downcast->transforms.prepend(this->transform.data());  
162 - if (fileExclusion) {  
163 - Transform *temp = Transform::make("FileExclusion(" + gallery.flat() + ")", downcast);  
164 - downcast->transforms.prepend(temp);  
165 - }  
166 -  
167 - // call init on the pipe to collapse the algorithm (if its top level is a pipe)  
168 - downcast->init();  
169 - }  
170 - else {  
171 - pipeDesc = "ProcessWrapper("+transformString+")+"+pipeDesc;  
172 - if (fileExclusion)  
173 - pipeDesc = "FileExclusion(" + gallery.flat() +")+" + pipeDesc;  
174 -  
175 - basePipe.reset(Transform::make(pipeDesc,NULL));  
176 - } 193 + QList<Transform *> stages;
  194 + stages.append(enroll);
177 195
178 - // Next, we make a Stream (with placeholder transform)  
179 - QString streamDesc = "Stream(readMode=StreamGallery)";  
180 - QScopedPointer<Transform> baseStream(Transform::make(streamDesc, NULL));  
181 - WrapperTransform *wrapper = dynamic_cast<WrapperTransform *> (baseStream.data()); 196 + QString outputDesc;
  197 + if (fileExclusion)
  198 + outputDesc = "FileExclusion(" + gallery.flat() + ")+";
  199 + outputDesc.append("GalleryOutput("+gallery.flat()+")");
  200 + QScopedPointer<Transform> outputTform(Transform::make(outputDesc, NULL));
  201 + stages.append(outputTform.data());
  202 + stages.append(progressCounter.data());
  203 + QScopedPointer<Transform> discard(Transform::make("Discard",NULL));
  204 + stages.append(discard.data());
182 205
183 - // replace that placeholder with the pipe we built  
184 - wrapper->transform = basePipe.data(); 206 + QScopedPointer<Transform> pipeline(br::pipeTransforms(stages));
185 207
186 - // and get the final stream's stages by reinterpreting the pipe. Perfectly straightforward.  
187 - wrapper->init();  
188 -  
189 - Globals->startTime.start();  
190 - Globals->currentStep = 0;  
191 - Globals->totalSteps = total; 208 + QScopedPointer<Transform> stream(br::wrapTransform(pipeline.data(), "Stream(readMode=StreamGallery)"));
192 209
193 TemplateList data, output; 210 TemplateList data, output;
194 data.append(input); 211 data.append(input);
195 - wrapper->projectUpdate(data, output); 212 + progressCounter->setPropertyRecursive("totalProgress", QString::number(total));
  213 + stream->projectUpdate(data, output);
196 214
197 files.append(output.files()); 215 files.append(output.files());
198 216
  217 + if (multiProcess)
  218 + delete enroll;
  219 +
199 return files; 220 return files;
200 } 221 }
201 222
@@ -364,7 +385,6 @@ struct AlgorithmCore @@ -364,7 +385,6 @@ struct AlgorithmCore
364 targetMetadata = FileList::fromGallery(targetGallery, true); 385 targetMetadata = FileList::fromGallery(targetGallery, true);
365 queryMetadata = FileList::fromGallery(queryGallery, true); 386 queryMetadata = FileList::fromGallery(queryGallery, true);
366 387
367 -  
368 // 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) 388 // 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)
369 transposeMode = targetMetadata.size() > queryMetadata.size(); 389 transposeMode = targetMetadata.size() > queryMetadata.size();
370 390
@@ -389,12 +409,12 @@ struct AlgorithmCore @@ -389,12 +409,12 @@ struct AlgorithmCore
389 // simple make sure the enrolled data is stored in a memGallery, but in multi-process mode we save the enrolled 409 // simple make sure the enrolled data is stored in a memGallery, but in multi-process mode we save the enrolled
390 // data to disk (as a .gal file) so that each worker process can read it without re-doing enrollment. 410 // data to disk (as a .gal file) so that each worker process can read it without re-doing enrollment.
391 File colEnrolledGallery = colGallery; 411 File colEnrolledGallery = colGallery;
392 - QString targetExtension = multiProcess ? "gal" : "mem"; 412 + QString targetExtension = "mem";
393 413
394 // If the column gallery is not already of the appropriate type, we need to do something 414 // If the column gallery is not already of the appropriate type, we need to do something
395 if (colGallery.suffix() != targetExtension) { 415 if (colGallery.suffix() != targetExtension) {
396 // Build the name of a gallery containing the enrolled data, of the appropriate type. 416 // Build the name of a gallery containing the enrolled data, of the appropriate type.
397 - colEnrolledGallery = colGallery.baseName() + colGallery.hash() + (multiProcess ? ".gal" : ".mem"); 417 + colEnrolledGallery = colGallery.baseName() + colGallery.hash() + '.' + targetExtension;
398 418
399 // Check if we have to do real enrollment, and not just convert the gallery's type. 419 // Check if we have to do real enrollment, and not just convert the gallery's type.
400 if (!(QStringList() << "gal" << "template" << "mem").contains(colGallery.suffix())) 420 if (!(QStringList() << "gal" << "template" << "mem").contains(colGallery.suffix()))
@@ -435,37 +455,24 @@ struct AlgorithmCore @@ -435,37 +455,24 @@ struct AlgorithmCore
435 // The actual comparison step is done by a GalleryCompare transform, which has a Distance, and a gallery as data. 455 // The actual comparison step is done by a GalleryCompare transform, which has a Distance, and a gallery as data.
436 // Incoming templates are compared against the templates in the gallery, and the output is the resulting score 456 // Incoming templates are compared against the templates in the gallery, and the output is the resulting score
437 // vector. 457 // vector.
  458 + TemplateList tlist = TemplateList::fromGallery(colEnrolledGallery);
  459 + comparison->train(tlist);
  460 + comparison->setPropertyRecursive("galleryName","");
  461 +
438 QString compareRegionDesc; 462 QString compareRegionDesc;
  463 + QList<Transform *> enrollCompare;
  464 + enrollCompare.append(comparison.data());
439 465
440 - if (this->galleryCompareString.isEmpty() )  
441 - compareRegionDesc = "Pipe([GalleryCompare("+Globals->algorithm+",galleryName="+colEnrolledGallery.flat()+")])";  
442 - else  
443 - compareRegionDesc = "Pipe(["+galleryCompareString+"(galleryName="+colEnrolledGallery.flat()+")])";  
444 -  
445 - QScopedPointer<Transform> compareRegion;  
446 - // If we need to enroll the row set, we add the current algorithm's enrollment transform before the  
447 - // GalleryCompare in a pipe.  
448 - if (needEnrollRows) {  
449 - if (!multiProcess) {  
450 - compareRegionDesc = compareRegionDesc;  
451 - compareRegion.reset(Transform::make(compareRegionDesc,NULL));  
452 - CompositeTransform *downcast = dynamic_cast<CompositeTransform *> (compareRegion.data());  
453 - if (downcast == NULL)  
454 - qFatal("Pipe downcast failed in compare");  
455 -  
456 - downcast->transforms.prepend(this->transform.data());  
457 - downcast->init();  
458 - }  
459 - else {  
460 - compareRegionDesc = "ProcessWrapper(" + this->transformString + "+" + compareRegionDesc + ")";  
461 - compareRegion.reset(Transform::make(compareRegionDesc, NULL));  
462 - }  
463 - }  
464 - else {  
465 - if (multiProcess)  
466 - compareRegionDesc = "ProcessWrapper(" + compareRegionDesc + ")";  
467 - compareRegion.reset(Transform::make(compareRegionDesc,NULL));  
468 - } 466 + // if we have to enroll the row gallery, add that transform to the list
  467 + if (needEnrollRows)
  468 + enrollCompare.prepend(simplifiedTransform.data());
  469 +
  470 + Transform *compareRegionBase = pipeTransforms(enrollCompare);
  471 + // If in multi-process mode, wrap the enroll+compare structure in a ProcessWrapper.
  472 + if (multiProcess)
  473 + compareRegionBase = wrapTransform(compareRegionBase, "ProcessWrapper");
  474 +
  475 + QScopedPointer<Transform> compareRegion(compareRegionBase);
469 476
470 // At this point, compareRegion is a transform, which optionally does enrollment, then compares the row 477 // At this point, compareRegion is a transform, which optionally does enrollment, then compares the row
471 // set against the column set. If in multi-process mode, the enrollment and comparison are wrapped in a 478 // set against the column set. If in multi-process mode, the enrollment and comparison are wrapped in a
@@ -473,47 +480,36 @@ struct AlgorithmCore @@ -473,47 +480,36 @@ struct AlgorithmCore
473 480
474 // We also need to add Output and progress counting to the algorithm we are building, so we will assign them to 481 // We also need to add Output and progress counting to the algorithm we are building, so we will assign them to
475 // two stages of a pipe. 482 // two stages of a pipe.
476 - QString joinDesc = "Pipe()";  
477 - QScopedPointer<Transform> join(Transform::make(joinDesc, NULL)); 483 + QList<Transform *> compareOutput;
  484 + compareOutput.append(compareRegion.data());
478 485
479 // The output transform takes the metadata memGalleries we set up previously as input, along with the 486 // The output transform takes the metadata memGalleries we set up previously as input, along with the
480 // output specification we were passed. Gallery metadata is necessary for some Outputs to function correctly. 487 // output specification we were passed. Gallery metadata is necessary for some Outputs to function correctly.
481 QString outputString = output.flat().isEmpty() ? "Empty" : output.flat(); 488 QString outputString = output.flat().isEmpty() ? "Empty" : output.flat();
482 QString outputRegionDesc = "Output("+ outputString +"," + targetGallery.flat() +"," + queryGallery.flat() + ","+ QString::number(transposeMode ? 1 : 0) + ")"; 489 QString outputRegionDesc = "Output("+ outputString +"," + targetGallery.flat() +"," + queryGallery.flat() + ","+ QString::number(transposeMode ? 1 : 0) + ")";
483 - // The ProgressCounter transform will simply provide a display about the number of rows completed.  
484 - outputRegionDesc += "+ProgressCounter("+QString::number(rowSize)+")+Discard";  
485 - QScopedPointer<Transform> outputTform(Transform::make(outputRegionDesc, NULL)); 490 + QScopedPointer<Transform> outputTForm(Transform::make(outputRegionDesc,NULL));
  491 + compareOutput.append(outputTForm.data());
486 492
487 - // Assign the comparison transform we previously built, and the output transform we just built to  
488 - // two stages of a pipe.  
489 - CompositeTransform *downcast = dynamic_cast<CompositeTransform *> (join.data());  
490 - downcast->transforms.append(compareRegion.data());  
491 - downcast->transforms.append(outputTform.data()); 493 + // The ProgressCounter transform will simply provide a display about the number of rows completed.
  494 + compareOutput.append(progressCounter.data());
  495 + QScopedPointer<Transform> discard(Transform::make("Discard",NULL));
  496 + compareOutput.append(discard.data());
492 497
493 // With this, we have set up a transform which (optionally) enrolls templates, compares them 498 // With this, we have set up a transform which (optionally) enrolls templates, compares them
494 // against a gallery, and outputs them. 499 // against a gallery, and outputs them.
495 - join->init(); 500 + Transform *pipeline = br::pipeTransforms(compareOutput);
496 501
497 // Now, we will give that base transform to a stream, which will incrementally read the row gallery 502 // Now, we will give that base transform to a stream, which will incrementally read the row gallery
498 // and pass the transforms it reads through the base algorithm. 503 // and pass the transforms it reads through the base algorithm.
499 - QString streamDesc = "Stream(readMode=StreamGallery)";  
500 - QScopedPointer<Transform> streamBase(Transform::make(streamDesc, NULL));  
501 - WrapperTransform *streamWrapper = dynamic_cast<WrapperTransform *> (streamBase.data());  
502 - streamWrapper->transform = join.data();  
503 -  
504 - // The transform we will use is now complete.  
505 - streamWrapper->init(); 504 + QScopedPointer<Transform> streamWrapper(br::wrapTransform(pipeline, "Stream(readMode=StreamGallery)"));
506 505
507 // We set up a template containing the rowGallery we want to compare. 506 // We set up a template containing the rowGallery we want to compare.
508 TemplateList rowGalleryTemplate; 507 TemplateList rowGalleryTemplate;
509 rowGalleryTemplate.append(Template(rowGallery)); 508 rowGalleryTemplate.append(Template(rowGallery));
510 TemplateList outputGallery; 509 TemplateList outputGallery;
511 510
512 - // Set up progress counting variables  
513 - Globals->currentStep = 0;  
514 - Globals->currentProgress = 0;  
515 - Globals->totalSteps = rowSize;  
516 - Globals->startTime.start(); 511 + // initialize the progress counter
  512 + progressCounter->setPropertyRecursive("totalProgress", QString::number(rowSize));
517 513
518 // Do the actual comparisons 514 // Do the actual comparisons
519 streamWrapper->projectUpdate(rowGalleryTemplate, outputGallery); 515 streamWrapper->projectUpdate(rowGalleryTemplate, outputGallery);
@@ -547,37 +543,39 @@ private: @@ -547,37 +543,39 @@ private:
547 543
548 void init(const QString &description) 544 void init(const QString &description)
549 { 545 {
550 - if (loadOrExpand(description)) 546 + bool newTForm = false;
  547 +
  548 + if (loadOrExpand(description)) {
  549 + simplifyTransform();
551 return; 550 return;
  551 + }
552 552
553 // check if the description is an abbreviation or model file with additional arguments supplied 553 // check if the description is an abbreviation or model file with additional arguments supplied
554 File parsed("."+description); 554 File parsed("."+description);
555 if (loadOrExpand(parsed.suffix())) { 555 if (loadOrExpand(parsed.suffix())) {
556 applyAdditionalProperties(parsed, transform.data()); 556 applyAdditionalProperties(parsed, transform.data());
  557 + simplifyTransform();
557 return; 558 return;
558 } 559 }
559 560
  561 + //! [Parsing the algorithm description]
560 const bool compareTransform = description.contains('!'); 562 const bool compareTransform = description.contains('!');
561 QStringList words = QtUtils::parse(description, compareTransform ? '!' : ':'); 563 QStringList words = QtUtils::parse(description, compareTransform ? '!' : ':');
562 564
563 if ((words.size() < 1) || (words.size() > 2)) qFatal("Invalid algorithm format."); 565 if ((words.size() < 1) || (words.size() > 2)) qFatal("Invalid algorithm format.");
564 566
565 - //! [Parsing the algorithm description]  
566 - transformString = words[0];  
567 -  
568 //! [Creating the template generation and comparison methods] 567 //! [Creating the template generation and comparison methods]
569 transform = QSharedPointer<Transform>(Transform::make(words[0], NULL)); 568 transform = QSharedPointer<Transform>(Transform::make(words[0], NULL));
  569 + simplifyTransform();
  570 +
570 if (words.size() > 1) { 571 if (words.size() > 1) {
571 if (!compareTransform) { 572 if (!compareTransform) {
572 distance = QSharedPointer<Distance>(Distance::make(words[1], NULL)); 573 distance = QSharedPointer<Distance>(Distance::make(words[1], NULL));
573 - distanceString = words[1];  
574 - galleryCompareString.clear();  
575 - }  
576 - else {  
577 - galleryCompareString = words[1];  
578 - distanceString.clear(); 574 + comparison = QSharedPointer<Transform>(Transform::make("GalleryCompare", NULL));
  575 + comparison->setPropertyRecursive("distance", QVariant::fromValue(distance.data()));
579 } 576 }
580 - 577 + else
  578 + comparison = QSharedPointer<Transform>(Transform::make(words[1], NULL));
581 } 579 }
582 //! [Creating the template generation and comparison methods] 580 //! [Creating the template generation and comparison methods]
583 } 581 }
openbr/core/eval.cpp
@@ -81,6 +81,8 @@ static cv::Mat constructMatchingMask(const cv::Mat &amp;scores, const FileList &amp;targ @@ -81,6 +81,8 @@ static cv::Mat constructMatchingMask(const cv::Mat &amp;scores, const FileList &amp;targ
81 // otherwise, we fail 81 // otherwise, we fail
82 else 82 else
83 qFatal("Unable to construct mask for %d by %d score matrix from %d element query set, and %d element target set ", scores.rows, scores.cols, query.length(), target.length()); 83 qFatal("Unable to construct mask for %d by %d score matrix from %d element query set, and %d element target set ", scores.rows, scores.cols, query.length(), target.length());
  84 +
  85 + return cv::Mat();
84 } 86 }
85 87
86 float Evaluate(const cv::Mat &scores, const FileList &target, const FileList &query, const QString &csv, int partition) 88 float Evaluate(const cv::Mat &scores, const FileList &target, const FileList &query, const QString &csv, int partition)
openbr/core/qtutils.cpp
@@ -105,7 +105,7 @@ void writeFile(const QString &amp;file, const QStringList &amp;lines) @@ -105,7 +105,7 @@ void writeFile(const QString &amp;file, const QStringList &amp;lines)
105 if (!f.open(QFile::WriteOnly)) 105 if (!f.open(QFile::WriteOnly))
106 qFatal("Failed to open %s for writing.", qPrintable(file)); 106 qFatal("Failed to open %s for writing.", qPrintable(file));
107 107
108 - foreach (const QString & line, lines) 108 + foreach (const QString &line, lines)
109 f.write((line+"\n").toLocal8Bit() ); 109 f.write((line+"\n").toLocal8Bit() );
110 110
111 f.close(); 111 f.close();
openbr/openbr.cpp
@@ -28,7 +28,7 @@ @@ -28,7 +28,7 @@
28 28
29 using namespace br; 29 using namespace br;
30 30
31 -static int partialCopy(const QString & string, char * buffer, int buffer_length) 31 +static int partialCopy(const QString &string, char *buffer, int buffer_length)
32 { 32 {
33 33
34 QByteArray byteArray = string.toLocal8Bit(); 34 QByteArray byteArray = string.toLocal8Bit();
@@ -109,7 +109,7 @@ float br_eval(const char *simmat, const char *mask, const char *csv) @@ -109,7 +109,7 @@ float br_eval(const char *simmat, const char *mask, const char *csv)
109 return Evaluate(simmat, mask, csv); 109 return Evaluate(simmat, mask, csv);
110 } 110 }
111 111
112 -float br_inplace_eval(const char * simmat, const char *target, const char *query, const char *csv) 112 +float br_inplace_eval(const char *simmat, const char *target, const char *query, const char *csv)
113 { 113 {
114 return InplaceEval(simmat, target, query, csv); 114 return InplaceEval(simmat, target, query, csv);
115 } 115 }
@@ -119,7 +119,7 @@ void br_eval_classification(const char *predicted_gallery, const char *truth_gal @@ -119,7 +119,7 @@ void br_eval_classification(const char *predicted_gallery, const char *truth_gal
119 EvalClassification(predicted_gallery, truth_gallery, predicted_property, truth_property); 119 EvalClassification(predicted_gallery, truth_gallery, predicted_property, truth_property);
120 } 120 }
121 121
122 -void br_eval_clustering(const char *csv, const char *gallery, const char * truth_property) 122 +void br_eval_clustering(const char *csv, const char *gallery, const char *truth_property)
123 { 123 {
124 EvalClustering(csv, gallery, truth_property); 124 EvalClustering(csv, gallery, truth_property);
125 } 125 }
@@ -178,12 +178,12 @@ void br_make_pairwise_mask(const char *target_input, const char *query_input, co @@ -178,12 +178,12 @@ void br_make_pairwise_mask(const char *target_input, const char *query_input, co
178 BEE::makePairwiseMask(target_input, query_input, mask); 178 BEE::makePairwiseMask(target_input, query_input, mask);
179 } 179 }
180 180
181 -int br_most_recent_message(char * buffer, int buffer_length) 181 +int br_most_recent_message(char *buffer, int buffer_length)
182 { 182 {
183 return partialCopy(Globals->mostRecentMessage, buffer, buffer_length); 183 return partialCopy(Globals->mostRecentMessage, buffer, buffer_length);
184 } 184 }
185 185
186 -int br_objects(char * buffer, int buffer_length, const char *abstractions, const char *implementations, bool parameters) 186 +int br_objects(char *buffer, int buffer_length, const char *abstractions, const char *implementations, bool parameters)
187 { 187 {
188 return partialCopy(br::Context::objects(abstractions, implementations, parameters).join('\n'), buffer, buffer_length); 188 return partialCopy(br::Context::objects(abstractions, implementations, parameters).join('\n'), buffer, buffer_length);
189 } 189 }
@@ -240,7 +240,7 @@ void br_read_pipe(const char *pipe, int *argc, char ***argv) @@ -240,7 +240,7 @@ void br_read_pipe(const char *pipe, int *argc, char ***argv)
240 *argv = rawCharArrayList.data(); 240 *argv = rawCharArrayList.data();
241 } 241 }
242 242
243 -int br_scratch_path(char * buffer, int buffer_length) 243 +int br_scratch_path(char *buffer, int buffer_length)
244 { 244 {
245 return partialCopy(Context::scratchPath(), buffer, buffer_length); 245 return partialCopy(Context::scratchPath(), buffer, buffer_length);
246 } 246 }
@@ -298,9 +298,9 @@ const char *br_version() @@ -298,9 +298,9 @@ const char *br_version()
298 return version.data(); 298 return version.data();
299 } 299 }
300 300
301 -void br_slave_process(const char * baseName) 301 +void br_slave_process(const char *baseName)
302 { 302 {
303 - WorkerProcess * worker = new WorkerProcess; 303 + WorkerProcess *worker = new WorkerProcess;
304 worker->transform = Globals->algorithm; 304 worker->transform = Globals->algorithm;
305 worker->baseName = baseName; 305 worker->baseName = baseName;
306 worker->mainLoop(); 306 worker->mainLoop();
@@ -371,7 +371,7 @@ bool br_img_is_empty(br_template tmpl) @@ -371,7 +371,7 @@ bool br_img_is_empty(br_template tmpl)
371 return t->m().empty(); 371 return t->m().empty();
372 } 372 }
373 373
374 -int br_get_filename(char * buffer, int buffer_length, br_template tmpl) 374 +int br_get_filename(char *buffer, int buffer_length, br_template tmpl)
375 { 375 {
376 return partialCopy(reinterpret_cast<Template*>(tmpl)->file.name, buffer, buffer_length); 376 return partialCopy(reinterpret_cast<Template*>(tmpl)->file.name, buffer, buffer_length);
377 } 377 }
@@ -382,7 +382,7 @@ void br_set_filename(br_template tmpl, const char *filename) @@ -382,7 +382,7 @@ void br_set_filename(br_template tmpl, const char *filename)
382 t->file.name = filename; 382 t->file.name = filename;
383 } 383 }
384 384
385 -int br_get_metadata_string(char * buffer, int buffer_length, br_template tmpl, const char *key) 385 +int br_get_metadata_string(char *buffer, int buffer_length, br_template tmpl, const char *key)
386 { 386 {
387 Template *t = reinterpret_cast<Template*>(tmpl); 387 Template *t = reinterpret_cast<Template*>(tmpl);
388 QVariant qvar = t->file.value(key); 388 QVariant qvar = t->file.value(key);
openbr/openbr_plugin.cpp
@@ -585,16 +585,51 @@ QStringList Object::parameters() const @@ -585,16 +585,51 @@ QStringList Object::parameters() const
585 return parameters; 585 return parameters;
586 } 586 }
587 587
588 -QStringList Object::arguments() const 588 +QStringList Object::prunedArguments(bool expanded) const
589 { 589 {
590 QStringList arguments; 590 QStringList arguments;
591 - for (int i=metaObject()->propertyOffset(); i<metaObject()->propertyCount(); i++)  
592 - arguments.append(argument(i)); 591 + QString className = this->metaObject()->className();
  592 + QScopedPointer<Object> shellObject;
  593 +
  594 + if (className.startsWith("br::"))
  595 + className = className.mid(4);
  596 + if (!className.startsWith("."))
  597 + className = "." + className;
  598 +
  599 + if (className.endsWith("Distance")) {
  600 + className.chop(QString("Distance").size());
  601 + shellObject.reset(Factory<Distance>::make(className));
  602 + }
  603 + else if (className.endsWith("Transform")) {
  604 + className.chop(QString("Transform").size());
  605 + shellObject.reset(Factory<Transform>::make(className));
  606 + }
  607 + else if (className.endsWith("Format")) {
  608 + className.chop(QString("Format").size());
  609 + shellObject.reset(Factory<Format>::make(className));
  610 + }
  611 + else if (className.endsWith("Initializer")) {
  612 + className.chop(QString("Initializer").size());
  613 + shellObject.reset(Factory<Initializer>::make(className));
  614 + }
  615 + else if (className.endsWith("Output")) {
  616 + className.chop(QString("Output").size());
  617 + shellObject.reset(Factory<Output>::make(className));
  618 + }
  619 +
  620 + for (int i=firstAvailablePropertyIdx; i<metaObject()->propertyCount(); i++) {
  621 + const char *name = metaObject()->property(i).name();
  622 +
  623 + QVariant defaultVal = shellObject->property(name);
  624 +
  625 + if (defaultVal != property(name))
  626 + arguments.append(name + QString("=") + argument(i, expanded));
  627 + }
593 628
594 return arguments; 629 return arguments;
595 } 630 }
596 631
597 -QString Object::argument(int index) const 632 +QString Object::argument(int index, bool expanded) const
598 { 633 {
599 if ((index < 0) || (index > metaObject()->propertyCount())) return ""; 634 if ((index < 0) || (index > metaObject()->propertyCount())) return "";
600 const QMetaProperty property = metaObject()->property(index); 635 const QMetaProperty property = metaObject()->property(index);
@@ -612,19 +647,19 @@ QString Object::argument(int index) const @@ -612,19 +647,19 @@ QString Object::argument(int index) const
612 strings.append(QString::number(value)); 647 strings.append(QString::number(value));
613 } else if (type == "QList<br::Transform*>") { 648 } else if (type == "QList<br::Transform*>") {
614 foreach (Transform *transform, variant.value< QList<Transform*> >()) 649 foreach (Transform *transform, variant.value< QList<Transform*> >())
615 - strings.append(transform->description()); 650 + strings.append(transform->description(expanded));
616 } else if (type == "QList<br::Distance*>") { 651 } else if (type == "QList<br::Distance*>") {
617 foreach (Distance *distance, variant.value< QList<Distance*> >()) 652 foreach (Distance *distance, variant.value< QList<Distance*> >())
618 - strings.append(distance->description()); 653 + strings.append(distance->description(expanded));
619 } else { 654 } else {
620 qFatal("Unrecognized type: %s", qPrintable(type)); 655 qFatal("Unrecognized type: %s", qPrintable(type));
621 } 656 }
622 657
623 return "[" + strings.join(",") + "]"; 658 return "[" + strings.join(",") + "]";
624 } else if (type == "br::Transform*") { 659 } else if (type == "br::Transform*") {
625 - return variant.value<Transform*>()->description(); 660 + return variant.value<Transform*>()->description(expanded);
626 } else if (type == "br::Distance*") { 661 } else if (type == "br::Distance*") {
627 - return variant.value<Distance*>()->description(); 662 + return variant.value<Distance*>()->description(expanded);
628 } else if (type == "QStringList") { 663 } else if (type == "QStringList") {
629 return "[" + variant.toStringList().join(",") + "]"; 664 return "[" + variant.toStringList().join(",") + "]";
630 } 665 }
@@ -632,9 +667,12 @@ QString Object::argument(int index) const @@ -632,9 +667,12 @@ QString Object::argument(int index) const
632 return variant.toString(); 667 return variant.toString();
633 } 668 }
634 669
635 -QString Object::description() const 670 +QString Object::description(bool expanded) const
636 { 671 {
637 - QString argumentString = arguments().join(","); 672 + QString argumentString = prunedArguments(expanded).join(",");
  673 + if (argumentString.endsWith(","))
  674 + argumentString.chop(1);
  675 +
638 return objectName() + (argumentString.isEmpty() ? "" : ("(" + argumentString + ")")); 676 return objectName() + (argumentString.isEmpty() ? "" : ("(" + argumentString + ")"));
639 } 677 }
640 678
@@ -1292,7 +1330,7 @@ Transform *Transform::make(QString str, QObject *parent) @@ -1292,7 +1330,7 @@ Transform *Transform::make(QString str, QObject *parent)
1292 1330
1293 Transform *Transform::clone() const 1331 Transform *Transform::clone() const
1294 { 1332 {
1295 - Transform *clone = Factory<Transform>::make(file.flat()); 1333 + Transform *clone = Factory<Transform>::make("."+description(false));
1296 return clone; 1334 return clone;
1297 } 1335 }
1298 1336
@@ -1461,3 +1499,17 @@ void br::applyAdditionalProperties(const File &amp;temp, Transform *target) @@ -1461,3 +1499,17 @@ void br::applyAdditionalProperties(const File &amp;temp, Transform *target)
1461 target->setPropertyRecursive(i.key(), i.value() ); 1499 target->setPropertyRecursive(i.key(), i.value() );
1462 } 1500 }
1463 } 1501 }
  1502 +
  1503 +Transform *br::wrapTransform(Transform *base, const QString &target)
  1504 +{
  1505 + Transform *res = Transform::make(target, NULL);
  1506 + res->setPropertyRecursive("transform", QVariant::fromValue(base));
  1507 + return res;
  1508 +}
  1509 +
  1510 +Transform *br::pipeTransforms(QList<Transform *> &transforms)
  1511 +{
  1512 + Transform *res = Transform::make("Pipe",NULL);
  1513 + res->setPropertyRecursive("transforms", QVariant::fromValue(transforms));
  1514 + return res;
  1515 +}
openbr/openbr_plugin.h
@@ -593,10 +593,18 @@ public: @@ -593,10 +593,18 @@ public:
593 virtual void store(QDataStream &stream) const; /*!< \brief Serialize the object. */ 593 virtual void store(QDataStream &stream) const; /*!< \brief Serialize the object. */
594 virtual void load(QDataStream &stream); /*!< \brief Deserialize the object. Default implementation calls init() after deserialization. */ 594 virtual void load(QDataStream &stream); /*!< \brief Deserialize the object. Default implementation calls init() after deserialization. */
595 595
  596 + /*!< \brief Serialize an object created via the plugin system, including the string used to build the base object, allowing re-creation of the object without knowledge of its base string*/
  597 + virtual void serialize(QDataStream &stream) const
  598 + {
  599 + stream << description();
  600 + store(stream);
  601 + }
  602 +
596 QStringList parameters() const; /*!< \brief A string describing the parameters the object takes. */ 603 QStringList parameters() const; /*!< \brief A string describing the parameters the object takes. */
597 - QStringList arguments() const; /*!< \brief A string describing the values the object has. */  
598 - QString argument(int index) const; /*!< \brief A string value for the argument at the specified index. */  
599 - QString description() const; /*!< \brief Returns a string description of the object. */ 604 + QStringList prunedArguments(bool expanded = false) const; /*!< \brief A string describing the values the object has, default valued parameters will not be listed. If expanded is true, all abbreviations and model file names should be replaced with a description of the object generated from those names. */
  605 + QString argument(int index, bool expanded) const; /*!< \brief A string value for the argument at the specified index. */
  606 + virtual QString description(bool expanded = false) const; /*!< \brief Returns a string description of the object. */
  607 +
600 void setProperty(const QString &name, QVariant value); /*!< \brief Overload of QObject::setProperty to handle OpenBR data types. */ 608 void setProperty(const QString &name, QVariant value); /*!< \brief Overload of QObject::setProperty to handle OpenBR data types. */
601 virtual bool setPropertyRecursive(const QString &name, QVariant value); /*!< \brief Recursive version of setProperty, try to set the property on this object, or its children, returns true if successful. */ 609 virtual bool setPropertyRecursive(const QString &name, QVariant value); /*!< \brief Recursive version of setProperty, try to set the property on this object, or its children, returns true if successful. */
602 610
@@ -1274,6 +1282,21 @@ public: @@ -1274,6 +1282,21 @@ public:
1274 */ 1282 */
1275 QList<Transform *> getChildren() const; 1283 QList<Transform *> getChildren() const;
1276 1284
  1285 + static Transform *deserialize(QDataStream &stream)
  1286 + {
  1287 + QString desc;
  1288 + stream >> desc;
  1289 + Transform *res = Transform::make(desc, NULL);
  1290 + res->load(stream);
  1291 + return res;
  1292 + }
  1293 +
  1294 + /*!
  1295 + * \brief Return a pointer to a simplified version of this transform (if possible). Transforms which are only active during training should remove
  1296 + * themselves by either returning their child transforms (where relevant) or returning NULL. Set newTransform to true if the transform returned is newly allocated.
  1297 + */
  1298 + virtual Transform * simplify(bool & newTransform) { newTransform = false; return this; }
  1299 +
1277 protected: 1300 protected:
1278 Transform(bool independent = true, bool trainable = true); /*!< \brief Construct a transform. */ 1301 Transform(bool independent = true, bool trainable = true); /*!< \brief Construct a transform. */
1279 inline Transform *make(const QString &description) { return make(description, this); } /*!< \brief Make a subtransform. */ 1302 inline Transform *make(const QString &description) { return make(description, this); } /*!< \brief Make a subtransform. */
openbr/plugins/distance.cpp
@@ -251,6 +251,7 @@ private: @@ -251,6 +251,7 @@ private:
251 default: 251 default:
252 qFatal("Invalid operation."); 252 qFatal("Invalid operation.");
253 } 253 }
  254 + return 0;
254 } 255 }
255 256
256 void store(QDataStream &stream) const 257 void store(QDataStream &stream) const
@@ -460,13 +461,12 @@ BR_REGISTER(Distance, SumDistance) @@ -460,13 +461,12 @@ BR_REGISTER(Distance, SumDistance)
460 class GalleryCompareTransform : public Transform 461 class GalleryCompareTransform : public Transform
461 { 462 {
462 Q_OBJECT 463 Q_OBJECT
463 - Q_PROPERTY(QString distanceAlgorithm READ get_distanceAlgorithm WRITE set_distanceAlgorithm RESET reset_distanceAlgorithm STORED false) 464 + Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance STORED true)
464 Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false) 465 Q_PROPERTY(QString galleryName READ get_galleryName WRITE set_galleryName RESET reset_galleryName STORED false)
465 - BR_PROPERTY(QString, distanceAlgorithm, "") 466 + BR_PROPERTY(br::Distance*, distance, NULL)
466 BR_PROPERTY(QString, galleryName, "") 467 BR_PROPERTY(QString, galleryName, "")
467 468
468 TemplateList gallery; 469 TemplateList gallery;
469 - QSharedPointer<Distance> distance;  
470 470
471 void project(const Template &src, Template &dst) const 471 void project(const Template &src, Template &dst) const
472 { 472 {
@@ -480,16 +480,29 @@ class GalleryCompareTransform : public Transform @@ -480,16 +480,29 @@ class GalleryCompareTransform : public Transform
480 480
481 void init() 481 void init()
482 { 482 {
483 - if (!galleryName.isEmpty()) { 483 + if (!galleryName.isEmpty())
484 gallery = TemplateList::fromGallery(galleryName); 484 gallery = TemplateList::fromGallery(galleryName);
485 - }  
486 - if (!distanceAlgorithm.isEmpty())  
487 - {  
488 - distance = Distance::fromAlgorithm(distanceAlgorithm);  
489 - }  
490 } 485 }
  486 +
  487 + void train(const TemplateList &data)
  488 + {
  489 + gallery = data;
  490 + }
  491 +
  492 + void store(QDataStream &stream) const
  493 + {
  494 + br::Object::store(stream);
  495 + stream << gallery;
  496 + }
  497 +
  498 + void load(QDataStream &stream)
  499 + {
  500 + br::Object::load(stream);
  501 + stream >> gallery;
  502 + }
  503 +
491 public: 504 public:
492 - GalleryCompareTransform() : Transform(false, false) {} 505 + GalleryCompareTransform() : Transform(false, true) {}
493 }; 506 };
494 507
495 BR_REGISTER(Transform, GalleryCompareTransform) 508 BR_REGISTER(Transform, GalleryCompareTransform)
openbr/plugins/frames.cpp
@@ -37,7 +37,7 @@ private: @@ -37,7 +37,7 @@ private:
37 dst.append(out); 37 dst.append(out);
38 } 38 }
39 39
40 - void finalize(TemplateList & output) 40 + void finalize(TemplateList &output)
41 { 41 {
42 (void) output; 42 (void) output;
43 buffer.clear(); 43 buffer.clear();
openbr/plugins/independent.cpp
@@ -94,6 +94,12 @@ class DownsampleTrainingTransform : public Transform @@ -94,6 +94,12 @@ class DownsampleTrainingTransform : public Transform
94 BR_PROPERTY(QStringList, subjects, QStringList()) 94 BR_PROPERTY(QStringList, subjects, QStringList())
95 95
96 96
  97 + Transform *simplify(bool &newTForm)
  98 + {
  99 + Transform *res = transform->simplify(newTForm);
  100 + return res;
  101 + }
  102 +
97 void project(const Template &src, Template &dst) const 103 void project(const Template &src, Template &dst) const
98 { 104 {
99 transform->project(src,dst); 105 transform->project(src,dst);
@@ -126,6 +132,10 @@ class IndependentTransform : public MetaTransform @@ -126,6 +132,10 @@ class IndependentTransform : public MetaTransform
126 132
127 QList<Transform*> transforms; 133 QList<Transform*> transforms;
128 134
  135 + QString description(bool expanded) const
  136 + {
  137 + return transform->description(expanded);
  138 + }
129 139
130 bool setPropertyRecursive(const QString &name, QVariant value) 140 bool setPropertyRecursive(const QString &name, QVariant value)
131 { 141 {
@@ -141,6 +151,54 @@ class IndependentTransform : public MetaTransform @@ -141,6 +151,54 @@ class IndependentTransform : public MetaTransform
141 return true; 151 return true;
142 } 152 }
143 153
  154 + Transform *simplify(bool &newTransform)
  155 + {
  156 + newTransform = false;
  157 + bool newChild = false;
  158 + Transform *temp = transform->simplify(newChild);
  159 + if (temp == transform) {
  160 + return this;
  161 + }
  162 + IndependentTransform* indep = new IndependentTransform();
  163 + indep->transform = temp;
  164 +
  165 + bool subInd = false;
  166 + IndependentTransform *test = dynamic_cast<IndependentTransform *> (temp);
  167 + if (test) {
  168 + // child was independent? this changes things...
  169 + subInd = true;
  170 + indep->transform = test->transform;
  171 + for (int i=0; i < transforms.size(); i++) {
  172 + bool newThing = false;
  173 + IndependentTransform *probe = dynamic_cast<IndependentTransform *> (transforms[i]->simplify(newThing));
  174 + indep->transforms.append(probe->transform);
  175 + if (newThing)
  176 + probe->setParent(indep);
  177 + }
  178 + indep->file = indep->transform->file;
  179 + indep->trainable = indep->transform->trainable;
  180 + indep->setObjectName(indep->transform->objectName());
  181 +
  182 + return indep;
  183 + }
  184 +
  185 + if (newChild)
  186 + indep->transform->setParent(indep);
  187 +
  188 + for (int i=0; i < transforms.size();i++) {
  189 + bool subTform = false;
  190 + indep->transforms.append(transforms[i]->simplify(subTform));
  191 + if (subTform)
  192 + indep->transforms[i]->setParent(indep);
  193 + }
  194 +
  195 + indep->file = indep->transform->file;
  196 + indep->trainable = indep->transform->trainable;
  197 + indep->setObjectName(indep->transform->objectName());
  198 +
  199 + return indep;
  200 + }
  201 +
144 void init() 202 void init()
145 { 203 {
146 transforms.clear(); 204 transforms.clear();
openbr/plugins/meta.cpp
@@ -482,17 +482,32 @@ BR_REGISTER(Transform, CacheTransform) @@ -482,17 +482,32 @@ BR_REGISTER(Transform, CacheTransform)
482 class LoadStoreTransform : public MetaTransform 482 class LoadStoreTransform : public MetaTransform
483 { 483 {
484 Q_OBJECT 484 Q_OBJECT
485 - Q_PROPERTY(QString description READ get_description WRITE set_description RESET reset_description STORED false) 485 + Q_PROPERTY(QString transformString READ get_transformString WRITE set_transformString RESET reset_transformString STORED false)
486 Q_PROPERTY(QString fileName READ get_fileName WRITE set_fileName RESET reset_fileName STORED false) 486 Q_PROPERTY(QString fileName READ get_fileName WRITE set_fileName RESET reset_fileName STORED false)
487 - BR_PROPERTY(QString, description, "Identity") 487 + BR_PROPERTY(QString, transformString, "Identity")
488 BR_PROPERTY(QString, fileName, QString()) 488 BR_PROPERTY(QString, fileName, QString())
489 489
  490 +public:
490 Transform *transform; 491 Transform *transform;
491 QString baseName; 492 QString baseName;
492 493
493 -public:  
494 LoadStoreTransform() : transform(NULL) {} 494 LoadStoreTransform() : transform(NULL) {}
495 495
  496 + QString description(bool expanded = false) const
  497 + {
  498 + if (expanded) {
  499 + QString res = transform->description(expanded);
  500 + return res;
  501 + }
  502 + return br::Object::description(expanded);
  503 + }
  504 +
  505 + Transform *simplify(bool &newTForm)
  506 + {
  507 + Transform *res = transform->simplify(newTForm);
  508 + return res;
  509 + }
  510 +
496 bool setPropertyRecursive(const QString &name, QVariant value) 511 bool setPropertyRecursive(const QString &name, QVariant value)
497 { 512 {
498 if (br::Object::setPropertyRecursive(name, value)) 513 if (br::Object::setPropertyRecursive(name, value))
@@ -500,13 +515,16 @@ public: @@ -500,13 +515,16 @@ public:
500 return transform->setPropertyRecursive(name, value); 515 return transform->setPropertyRecursive(name, value);
501 } 516 }
502 private: 517 private:
  518 +
503 void init() 519 void init()
504 { 520 {
505 if (transform != NULL) return; 521 if (transform != NULL) return;
506 - if (fileName.isEmpty()) baseName = QRegExp("^[a-zA-Z0-9]+$").exactMatch(description) ? description : QtUtils::shortTextHash(description); 522 + if (fileName.isEmpty()) baseName = QRegExp("^[a-zA-Z0-9]+$").exactMatch(transformString) ? transformString : QtUtils::shortTextHash(transformString);
507 else baseName = fileName; 523 else baseName = fileName;
508 - if (!tryLoad()) transform = make(description);  
509 - else trainable = false; 524 + if (!tryLoad())
  525 + transform = make(transformString);
  526 + else
  527 + trainable = false;
510 } 528 }
511 529
512 bool timeVarying() const 530 bool timeVarying() const
@@ -524,7 +542,7 @@ private: @@ -524,7 +542,7 @@ private:
524 qDebug("Storing %s", qPrintable(baseName)); 542 qDebug("Storing %s", qPrintable(baseName));
525 QByteArray byteArray; 543 QByteArray byteArray;
526 QDataStream stream(&byteArray, QFile::WriteOnly); 544 QDataStream stream(&byteArray, QFile::WriteOnly);
527 - stream << description; 545 + stream << transform->description();
528 transform->store(stream); 546 transform->store(stream);
529 QtUtils::writeFile(baseName, byteArray, -1); 547 QtUtils::writeFile(baseName, byteArray, -1);
530 } 548 }
@@ -570,8 +588,8 @@ private: @@ -570,8 +588,8 @@ private:
570 QByteArray data; 588 QByteArray data;
571 QtUtils::readFile(file, data, true); 589 QtUtils::readFile(file, data, true);
572 QDataStream stream(&data, QFile::ReadOnly); 590 QDataStream stream(&data, QFile::ReadOnly);
573 - stream >> description;  
574 - transform = Transform::make(description); 591 + stream >> transformString;
  592 + transform = Transform::make(transformString);
575 transform->load(stream); 593 transform->load(stream);
576 return true; 594 return true;
577 } 595 }
openbr/plugins/misc.cpp
@@ -617,8 +617,8 @@ class ProgressCounterTransform : public TimeVaryingTransform @@ -617,8 +617,8 @@ class ProgressCounterTransform : public TimeVaryingTransform
617 { 617 {
618 Q_OBJECT 618 Q_OBJECT
619 619
620 - Q_PROPERTY(int totalTemplates READ get_totalTemplates WRITE set_totalTemplates RESET reset_totalTemplates STORED false)  
621 - BR_PROPERTY(int, totalTemplates, 1) 620 + Q_PROPERTY(int totalProgress READ get_totalProgress WRITE set_totalProgress RESET reset_totalProgress STORED false)
  621 + BR_PROPERTY(int, totalProgress, 1)
622 622
623 void projectUpdate(const TemplateList &src, TemplateList &dst) 623 void projectUpdate(const TemplateList &src, TemplateList &dst)
624 { 624 {
@@ -658,16 +658,20 @@ class ProgressCounterTransform : public TimeVaryingTransform @@ -658,16 +658,20 @@ class ProgressCounterTransform : public TimeVaryingTransform
658 (void) data; 658 (void) data;
659 float p = br_progress(); 659 float p = br_progress();
660 qDebug("\r%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), Globals->currentStep); 660 qDebug("\r%05.2f%% ELAPSED=%s REMAINING=%s COUNT=%g", p*100, QtUtils::toTime(Globals->startTime.elapsed()/1000.0f).toStdString().c_str(), QtUtils::toTime(0).toStdString().c_str(), Globals->currentStep);
  661 + timer.start();
  662 + Globals->startTime.start();
661 Globals->currentStep = 0; 663 Globals->currentStep = 0;
662 Globals->currentProgress = 0; 664 Globals->currentProgress = 0;
663 - Globals->totalSteps = 0; 665 + Globals->totalSteps = totalProgress;
664 } 666 }
665 667
666 void init() 668 void init()
667 { 669 {
668 timer.start(); 670 timer.start();
  671 + Globals->startTime.start();
669 Globals->currentStep = 0; 672 Globals->currentStep = 0;
670 Globals->currentProgress = 0; 673 Globals->currentProgress = 0;
  674 + Globals->totalSteps = totalProgress;
671 } 675 }
672 676
673 public: 677 public:
openbr/plugins/openbr_internal.h
@@ -201,6 +201,33 @@ public: @@ -201,6 +201,33 @@ public:
201 this->trainable = transform->trainable; 201 this->trainable = transform->trainable;
202 } 202 }
203 203
  204 + virtual Transform *simplify(bool &newTransform)
  205 + {
  206 + newTransform = false;
  207 + bool newChild = false;
  208 + Transform *temp = transform->simplify(newTransform);
  209 + if (temp == transform)
  210 + return this;
  211 +
  212 + if (!temp)
  213 + return NULL;
  214 +
  215 + // else make a copy to point at the new transform
  216 + Transform *child = transform;
  217 + transform = NULL;
  218 + WrapperTransform *output = dynamic_cast<WrapperTransform *>(Transform::make(description(), NULL));
  219 + transform = child;
  220 +
  221 + output->transform = temp;
  222 +
  223 + if (newChild)
  224 + temp->setParent(output);
  225 +
  226 + newTransform = true;
  227 + return output;
  228 + }
  229 +
  230 +
204 bool setPropertyRecursive(const QString &name, QVariant value) 231 bool setPropertyRecursive(const QString &name, QVariant value)
205 { 232 {
206 if (br::Object::setPropertyRecursive(name, value)) 233 if (br::Object::setPropertyRecursive(name, value))
@@ -212,6 +239,34 @@ public: @@ -212,6 +239,34 @@ public:
212 } 239 }
213 return false; 240 return false;
214 } 241 }
  242 +
  243 + Transform *smartCopy(bool &newTransform)
  244 + {
  245 + if (!timeVarying()) {
  246 + newTransform = false;
  247 + return this;
  248 + }
  249 + newTransform = true;
  250 + Transform *temp = transform;
  251 + transform = NULL;
  252 + WrapperTransform *output = dynamic_cast<WrapperTransform *>(Transform::make(description(), NULL));
  253 + transform = temp;
  254 +
  255 + if (output == NULL)
  256 + qFatal("Dynamic cast failed!");
  257 +
  258 + bool newItem = false;
  259 + Transform *maybe_copy = transform->smartCopy(newItem);
  260 + if (newItem)
  261 + maybe_copy->setParent(output);
  262 + output->transform = maybe_copy;
  263 +
  264 + output->file = this->file;
  265 + output->init();
  266 +
  267 + return output;
  268 + }
  269 +
215 }; 270 };
216 271
217 /*! 272 /*!
@@ -270,21 +325,10 @@ public: @@ -270,21 +325,10 @@ public:
270 } 325 }
271 newTransform = true; 326 newTransform = true;
272 327
273 - QString name = metaObject()->className();  
274 -  
275 - name.replace("Transform","");  
276 - name += "([]";  
277 -  
278 - QStringList arguments = this->arguments();  
279 - if (!arguments.isEmpty()) {  
280 - name += ",";  
281 - name += this->arguments().join(",");  
282 - }  
283 -  
284 - name += ")";  
285 - name.replace("br::","");  
286 -  
287 - CompositeTransform *output = dynamic_cast<CompositeTransform *>(Transform::make(name, NULL)); 328 + QList<Transform *> temp = transforms;
  329 + transforms = QList<Transform *>();
  330 + CompositeTransform *output = dynamic_cast<CompositeTransform *>(Transform::make(description(), NULL));
  331 + transforms = temp;
288 332
289 if (output == NULL) 333 if (output == NULL)
290 qFatal("Dynamic cast failed!"); 334 qFatal("Dynamic cast failed!");
@@ -303,6 +347,51 @@ public: @@ -303,6 +347,51 @@ public:
303 return output; 347 return output;
304 } 348 }
305 349
  350 + virtual Transform *simplify(bool &newTransform)
  351 + {
  352 + newTransform = false;
  353 + QList<Transform *> newTransforms;
  354 + bool anyNew = false;
  355 +
  356 + QList<bool> newChildren;
  357 + for (int i=0; i < transforms.size();i++)
  358 + {
  359 + bool newChild = false;
  360 + Transform *temp = transforms[i]->simplify(newChild);
  361 + if (temp == NULL) {
  362 + anyNew = true;
  363 + continue;
  364 + }
  365 + newTransforms.append(temp);
  366 + newChildren.append(newChild);
  367 + if (temp != transforms[i])
  368 + anyNew = true;
  369 + }
  370 +
  371 + if (newTransforms.empty() )
  372 + return NULL;
  373 +
  374 + if (!anyNew)
  375 + return this;
  376 +
  377 + // make a copy of the current object, with empty transforms
  378 + QList<Transform *> children = transforms;
  379 + transforms = QList<Transform *> ();
  380 + CompositeTransform *output = dynamic_cast<CompositeTransform *>(Transform::make(description(false), NULL));
  381 + transforms = children;
  382 +
  383 + output->transforms = newTransforms;
  384 + for (int i=0;i < newChildren.size();i++)
  385 + {
  386 + if (newChildren[i])
  387 + output->transforms[i]->setParent(output);
  388 + }
  389 + output->init();
  390 +
  391 + newTransform = true;
  392 + return output;
  393 + }
  394 +
306 bool setPropertyRecursive(const QString &name, QVariant value) 395 bool setPropertyRecursive(const QString &name, QVariant value)
307 { 396 {
308 if (br::Object::setPropertyRecursive(name, value)) 397 if (br::Object::setPropertyRecursive(name, value))
@@ -388,6 +477,10 @@ public: @@ -388,6 +477,10 @@ public:
388 477
389 void applyAdditionalProperties(const File &temp, Transform *target); 478 void applyAdditionalProperties(const File &temp, Transform *target);
390 479
  480 +Transform *wrapTransform(Transform *base, const QString &target);
  481 +
  482 +Transform *pipeTransforms(QList<Transform *> &transforms);
  483 +
391 } 484 }
392 485
393 #endif // OPENBR_INTERNAL_H 486 #endif // OPENBR_INTERNAL_H
openbr/plugins/pp5.cpp
@@ -450,8 +450,9 @@ class PP5GalleryTransform: public UntrainableMetaTransform @@ -450,8 +450,9 @@ class PP5GalleryTransform: public UntrainableMetaTransform
450 450
451 ppr_gallery_type target; 451 ppr_gallery_type target;
452 QList<int> targetIDs; 452 QList<int> targetIDs;
  453 + TemplateList gallery;
453 454
454 - void project(const Template & src, Template & dst) const 455 + void project(const Template &src, Template &dst) const
455 { 456 {
456 TemplateList temp, output; 457 TemplateList temp, output;
457 temp.append(src); 458 temp.append(src);
@@ -460,7 +461,7 @@ class PP5GalleryTransform: public UntrainableMetaTransform @@ -460,7 +461,7 @@ class PP5GalleryTransform: public UntrainableMetaTransform
460 dst = output[0]; 461 dst = output[0];
461 } 462 }
462 463
463 - void project(const TemplateList & src, TemplateList & dst) const 464 + void project(const TemplateList &src, TemplateList &dst) const
464 { 465 {
465 dst.clear(); 466 dst.clear();
466 QList<int> queryIDs; 467 QList<int> queryIDs;
@@ -495,11 +496,33 @@ class PP5GalleryTransform: public UntrainableMetaTransform @@ -495,11 +496,33 @@ class PP5GalleryTransform: public UntrainableMetaTransform
495 496
496 void init() 497 void init()
497 { 498 {
498 - // set up the gallery  
499 - ppr_create_gallery(context, &target);  
500 - TemplateList templates = TemplateList::fromGallery(galleryName);  
501 - enroll(templates,&target, targetIDs); 499 + if (!galleryName.isEmpty() || !gallery.isEmpty()) {
  500 + // set up the gallery
  501 + ppr_create_gallery(context, &target);
  502 + if (gallery.isEmpty() )
  503 + gallery = TemplateList::fromGallery(galleryName);
  504 + enroll(gallery, &target, targetIDs);
  505 + }
  506 + }
  507 +
  508 + void train(const TemplateList &data)
  509 + {
  510 + gallery = data;
  511 + }
  512 +
  513 + void store(QDataStream &stream) const
  514 + {
  515 + br::Object::store(stream);
  516 + stream << gallery;
  517 + }
  518 +
  519 + void load(QDataStream &stream)
  520 + {
  521 + br::Object::load(stream);
  522 + stream >> gallery;
  523 + init();
502 } 524 }
  525 +
503 }; 526 };
504 527
505 BR_REGISTER(Transform, PP5GalleryTransform) 528 BR_REGISTER(Transform, PP5GalleryTransform)
openbr/plugins/process.cpp
@@ -21,7 +21,7 @@ class CommunicationManager : public QObject @@ -21,7 +21,7 @@ class CommunicationManager : public QObject
21 { 21 {
22 Q_OBJECT 22 Q_OBJECT
23 public: 23 public:
24 - QThread * basis; 24 + QThread *basis;
25 CommunicationManager() 25 CommunicationManager()
26 { 26 {
27 basis = new QThread; 27 basis = new QThread;
@@ -294,7 +294,7 @@ public: @@ -294,7 +294,7 @@ public:
294 QString serverName; 294 QString serverName;
295 QString remoteName; 295 QString remoteName;
296 296
297 - QLocalSocket * inbound; 297 + QLocalSocket *inbound;
298 QLocalSocket outbound; 298 QLocalSocket outbound;
299 QLocalServer server; 299 QLocalServer server;
300 300
@@ -305,13 +305,11 @@ public: @@ -305,13 +305,11 @@ public:
305 while (!inbound || inbound->state() != QLocalSocket::ConnectedState) { 305 while (!inbound || inbound->state() != QLocalSocket::ConnectedState) {
306 bool res = receivedWait.wait(&receivedLock,30*1000); 306 bool res = receivedWait.wait(&receivedLock,30*1000);
307 if (!res) 307 if (!res)
308 - {  
309 qDebug() << key << " " << QThread::currentThread() << " waiting timed out, server thread is " << server.thread() << " base thread " << basis; 308 qDebug() << key << " " << QThread::currentThread() << " waiting timed out, server thread is " << server.thread() << " base thread " << basis;
310 - }  
311 } 309 }
312 } 310 }
313 311
314 - void connectToRemote(const QString & remoteName) 312 + void connectToRemote(const QString &remoteName)
315 { 313 {
316 emit pulseOutboundConnect(remoteName); 314 emit pulseOutboundConnect(remoteName);
317 315
@@ -330,7 +328,7 @@ public: @@ -330,7 +328,7 @@ public:
330 328
331 329
332 template<typename T> 330 template<typename T>
333 - bool readData(T & input) 331 + bool readData(T &input)
334 { 332 {
335 emit pulseReadSerialized(); 333 emit pulseReadSerialized();
336 QDataStream deserializer(readArray); 334 QDataStream deserializer(readArray);
@@ -338,8 +336,18 @@ public: @@ -338,8 +336,18 @@ public:
338 return true; 336 return true;
339 } 337 }
340 338
  339 + Transform *readTForm()
  340 + {
  341 + emit pulseReadSerialized();
  342 +
  343 + QByteArray data = readArray;
  344 + QDataStream deserializer(data);
  345 + Transform *res = Transform::deserialize(deserializer);
  346 + return res;
  347 + }
  348 +
341 template<typename T> 349 template<typename T>
342 - bool sendData(const T & output) 350 + bool sendData(const T &output)
343 { 351 {
344 QBuffer buffer; 352 QBuffer buffer;
345 buffer.open(QBuffer::ReadWrite); 353 buffer.open(QBuffer::ReadWrite);
@@ -378,7 +386,7 @@ class EnrollmentWorker : public QObject @@ -378,7 +386,7 @@ class EnrollmentWorker : public QObject
378 { 386 {
379 Q_OBJECT 387 Q_OBJECT
380 public: 388 public:
381 - CommunicationManager * comm; 389 + CommunicationManager *comm;
382 QString name; 390 QString name;
383 391
384 ~EnrollmentWorker() 392 ~EnrollmentWorker()
@@ -389,10 +397,10 @@ public: @@ -389,10 +397,10 @@ public:
389 delete comm; 397 delete comm;
390 } 398 }
391 399
392 - br::Transform * transform; 400 + br::Transform *transform;
393 401
394 public: 402 public:
395 - void connections(const QString & baseName) 403 + void connections(const QString &baseName)
396 { 404 {
397 comm = new CommunicationManager(); 405 comm = new CommunicationManager();
398 name = baseName; 406 name = baseName;
@@ -401,6 +409,8 @@ public: @@ -401,6 +409,8 @@ public:
401 comm->connectToRemote(baseName+"_master"); 409 comm->connectToRemote(baseName+"_master");
402 410
403 comm->waitForInbound(); 411 comm->waitForInbound();
  412 +
  413 + transform = comm->readTForm();
404 } 414 }
405 415
406 void workerLoop() 416 void workerLoop()
@@ -428,7 +438,7 @@ public: @@ -428,7 +438,7 @@ public:
428 void WorkerProcess::mainLoop() 438 void WorkerProcess::mainLoop()
429 { 439 {
430 processInterface = new EnrollmentWorker(); 440 processInterface = new EnrollmentWorker();
431 - processInterface->transform = Transform::make(this->transform,NULL); 441 + processInterface->transform = NULL;
432 processInterface->connections(baseName); 442 processInterface->connections(baseName);
433 processInterface->workerLoop(); 443 processInterface->workerLoop();
434 delete processInterface; 444 delete processInterface;
@@ -478,63 +488,99 @@ protected slots: @@ -478,63 +488,99 @@ protected slots:
478 } 488 }
479 }; 489 };
480 490
  491 +struct ProcessData
  492 +{
  493 + CommunicationManager comm;
  494 + ProcessInterface proc;
  495 + bool initialized;
  496 + ProcessData()
  497 + {
  498 + initialized = false;
  499 + }
  500 +
  501 + ~ProcessData()
  502 + {
  503 + comm.sendSignal(CommunicationManager::SHOULD_END);
  504 + proc.endProcess();
  505 + comm.shutdown();
  506 + comm.shutDownThread();
  507 + }
  508 +};
  509 +
  510 +
481 /*! 511 /*!
482 * \ingroup transforms 512 * \ingroup transforms
483 * \brief Interface to a separate process 513 * \brief Interface to a separate process
484 * \author Charles Otto \cite caotto 514 * \author Charles Otto \cite caotto
485 */ 515 */
486 -class ProcessWrapperTransform : public TimeVaryingTransform 516 +class ProcessWrapperTransform : public WrapperTransform
487 { 517 {
488 Q_OBJECT 518 Q_OBJECT
489 519
490 - Q_PROPERTY(QString transform READ get_transform WRITE set_transform RESET reset_transform)  
491 - BR_PROPERTY(QString, transform, "")  
492 -  
493 QString baseKey; 520 QString baseKey;
494 521
495 - ProcessInterface workerProcess;  
496 - CommunicationManager * comm; 522 + Resource<ProcessData> processes;
497 523
498 - void projectUpdate(const TemplateList &src, TemplateList &dst) 524 + Transform *smartCopy(bool &newTransform)
  525 + {
  526 + newTransform = false;
  527 + return this;
  528 + }
  529 +
  530 + void project(const TemplateList &src, TemplateList &dst) const
499 { 531 {
500 if (src.empty()) 532 if (src.empty())
501 return; 533 return;
  534 +
  535 + ProcessData *data = processes.acquire();
  536 + if (!data->initialized)
  537 + activateProcess(data);
502 538
503 - if (!processActive)  
504 - {  
505 - activateProcess();  
506 - }  
507 - comm->sendSignal(CommunicationManager::INPUT_AVAILABLE);  
508 -  
509 - comm->sendData(src); 539 + CommunicationManager *localComm = &(data->comm);
  540 + localComm->sendSignal(CommunicationManager::INPUT_AVAILABLE);
510 541
511 - comm->readData(dst); 542 + localComm->sendData(src);
  543 + localComm->readData(dst);
  544 + processes.release(data);
512 } 545 }
513 546
514 -  
515 void train(const TemplateList& data) 547 void train(const TemplateList& data)
516 { 548 {
517 (void) data; 549 (void) data;
518 } 550 }
519 551
520 - // create the process  
521 void init() 552 void init()
522 { 553 {
523 processActive = false; 554 processActive = false;
  555 + serialized.clear();
  556 + if (transform) {
  557 + QDataStream out(&serialized, QFile::WriteOnly);
  558 + transform->serialize(out);
  559 + }
524 } 560 }
525 561
526 - void activateProcess() 562 + QByteArray serialized;
  563 + void transmitTForm(CommunicationManager *localComm) const
527 { 564 {
528 - comm = new CommunicationManager();  
529 - processActive = true; 565 + if (serialized.isEmpty() )
  566 + qFatal("Trying to transmit empty transform!");
  567 +
  568 + localComm->writeArray = serialized;
  569 + emit localComm->pulseSendSerialized();
  570 + }
530 571
  572 + void activateProcess(ProcessData *data) const
  573 + {
  574 + data->initialized = true;
531 // generate a uuid for our local servers 575 // generate a uuid for our local servers
532 QUuid id = QUuid::createUuid(); 576 QUuid id = QUuid::createUuid();
533 - baseKey = id.toString(); 577 + QString baseKey = id.toString();
534 578
535 QStringList argumentList; 579 QStringList argumentList;
  580 + // We serialize and transmit the transform directly, so algorithm doesn't matter.
  581 + argumentList.append("-quiet");
536 argumentList.append("-algorithm"); 582 argumentList.append("-algorithm");
537 - argumentList.append(transform); 583 + argumentList.append("Identity");
538 if (!Globals->path.isEmpty()) { 584 if (!Globals->path.isEmpty()) {
539 argumentList.append("-path"); 585 argumentList.append("-path");
540 argumentList.append(Globals->path); 586 argumentList.append(Globals->path);
@@ -544,36 +590,25 @@ class ProcessWrapperTransform : public TimeVaryingTransform @@ -544,36 +590,25 @@ class ProcessWrapperTransform : public TimeVaryingTransform
544 argumentList.append("-slave"); 590 argumentList.append("-slave");
545 argumentList.append(baseKey); 591 argumentList.append(baseKey);
546 592
547 - comm->key = "master_"+baseKey.mid(1,5); 593 + data->comm.key = "master_"+baseKey.mid(1,5);
548 594
549 - comm->startServer(baseKey+"_master");  
550 - workerProcess.startProcess(argumentList);  
551 - comm->waitForInbound();  
552 - comm->connectToRemote(baseKey+"_worker");  
553 - } 595 + data->comm.startServer(baseKey+"_master");
554 596
555 - bool timeVarying() const {  
556 - return false; 597 + data->proc.startProcess(argumentList);
  598 + data->comm.waitForInbound();
  599 + data->comm.connectToRemote(baseKey+"_worker");
  600 +
  601 + transmitTForm(&(data->comm));
557 } 602 }
558 603
559 - ~ProcessWrapperTransform() 604 + bool timeVarying() const
560 { 605 {
561 - // end the process  
562 - if (this->processActive) {  
563 - comm->sendSignal(CommunicationManager::SHOULD_END);  
564 -  
565 - workerProcess.endProcess();  
566 - processActive = false;  
567 - comm->shutdown();  
568 - comm->shutDownThread();  
569 -  
570 - delete comm;  
571 - } 606 + return false;
572 } 607 }
573 608
574 public: 609 public:
575 bool processActive; 610 bool processActive;
576 - ProcessWrapperTransform() : TimeVaryingTransform(false,false) { processActive = false; } 611 + ProcessWrapperTransform() : WrapperTransform(false) { processActive = false; }
577 }; 612 };
578 613
579 BR_REGISTER(Transform, ProcessWrapperTransform) 614 BR_REGISTER(Transform, ProcessWrapperTransform)
openbr/plugins/validate.cpp
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 namespace br 7 namespace br
8 { 8 {
9 9
10 -static void _train(Transform * transform, TemplateList data) // think data has to be a copy -cao 10 +static void _train(Transform *transform, TemplateList data) // think data has to be a copy -cao
11 { 11 {
12 transform->train(data); 12 transform->train(data);
13 } 13 }
1 -Subproject commit bcbff8c485f19daddb2e6b2abd5a505ed8c1e526 1 +Subproject commit 79938fe401faafead086b4711dd0b8f898a7a21e