Commit 36d2607d60d85383c75edfd11a401aa4b8baece7
Merge pull request #216 from biometrics/serialization_update
Better support for serializing algorithms in memory
Showing
17 changed files
with
573 additions
and
254 deletions
CMakeLists.txt
| ... | ... | @@ -121,7 +121,7 @@ else() |
| 121 | 121 | set(CMAKE_EXE_LINKER_FLAGS "-Wl,--enable-auto-import") # Fixes a linker warning |
| 122 | 122 | set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--enable-auto-import") |
| 123 | 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 | 125 | endif() |
| 126 | 126 | endif() |
| 127 | 127 | ... | ... |
openbr/core/core.cpp
| ... | ... | @@ -23,24 +23,36 @@ |
| 23 | 23 | |
| 24 | 24 | namespace br { |
| 25 | 25 | |
| 26 | +void noDelete(Transform *target) | |
| 27 | +{ | |
| 28 | + (void) target; | |
| 29 | +} | |
| 30 | + | |
| 26 | 31 | struct AlgorithmCore |
| 27 | 32 | { |
| 33 | + enum CompareMode | |
| 34 | + { | |
| 35 | + None, | |
| 36 | + DistanceCompare, | |
| 37 | + TransformCompare, | |
| 38 | + }; | |
| 39 | + | |
| 28 | 40 | QSharedPointer<Transform> transform; |
| 41 | + QSharedPointer<Transform> simplifiedTransform; | |
| 42 | + QSharedPointer<Transform> comparison; | |
| 29 | 43 | QSharedPointer<Distance> distance; |
| 30 | - QString galleryCompareString; | |
| 31 | - | |
| 32 | - QString transformString; | |
| 33 | - QString distanceString; | |
| 44 | + QSharedPointer<Transform> progressCounter; | |
| 34 | 45 | |
| 35 | 46 | AlgorithmCore(const QString &name) |
| 36 | 47 | { |
| 37 | 48 | this->name = name; |
| 38 | 49 | init(name); |
| 50 | + progressCounter = QSharedPointer<Transform>(Transform::make("ProgressCounter", NULL)); | |
| 39 | 51 | } |
| 40 | 52 | |
| 41 | 53 | bool isClassifier() const |
| 42 | 54 | { |
| 43 | - return distance.isNull(); | |
| 55 | + return comparison.isNull(); | |
| 44 | 56 | } |
| 45 | 57 | |
| 46 | 58 | void train(const File &input, const QString &model) |
| ... | ... | @@ -48,15 +60,7 @@ struct AlgorithmCore |
| 48 | 60 | qDebug("Training on %s%s", qPrintable(input.flat()), |
| 49 | 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 | 64 | TemplateList data(TemplateList::fromGallery(input)); |
| 61 | 65 | |
| 62 | 66 | if (transform.isNull()) qFatal("Null transform."); |
| ... | ... | @@ -65,14 +69,14 @@ struct AlgorithmCore |
| 65 | 69 | Globals->startTime.start(); |
| 66 | 70 | |
| 67 | 71 | qDebug("Training Enrollment"); |
| 68 | - downcast->train(data); | |
| 72 | + trainingWrapper->train(data); | |
| 69 | 73 | |
| 70 | 74 | if (!distance.isNull()) { |
| 71 | 75 | if (Globals->crossValidate > 0) |
| 72 | 76 | for (int i=data.size()-1; i>=0; i--) if (data[i].file.get<bool>("allPartitions",false)) data.removeAt(i); |
| 73 | 77 | |
| 74 | 78 | qDebug("Projecting Enrollment"); |
| 75 | - downcast->projectUpdate(data,data); | |
| 79 | + trainingWrapper->projectUpdate(data,data); | |
| 76 | 80 | |
| 77 | 81 | qDebug("Training Comparison"); |
| 78 | 82 | distance->train(data); |
| ... | ... | @@ -84,6 +88,18 @@ struct AlgorithmCore |
| 84 | 88 | } |
| 85 | 89 | |
| 86 | 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 | 105 | void store(const QString &model) const |
| ... | ... | @@ -93,11 +109,21 @@ struct AlgorithmCore |
| 93 | 109 | QDataStream out(&data, QFile::WriteOnly); |
| 94 | 110 | |
| 95 | 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 | 128 | // Compress and save to file |
| 103 | 129 | QtUtils::writeFile(model, data, -1); |
| ... | ... | @@ -113,10 +139,21 @@ struct AlgorithmCore |
| 113 | 139 | QDataStream in(&data, QFile::ReadOnly); |
| 114 | 140 | |
| 115 | 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 | 159 | File getMemoryGallery(const File &file) const |
| ... | ... | @@ -148,54 +185,38 @@ struct AlgorithmCore |
| 148 | 185 | Gallery *temp = Gallery::make(input); |
| 149 | 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 | 210 | TemplateList data, output; |
| 194 | 211 | data.append(input); |
| 195 | - wrapper->projectUpdate(data, output); | |
| 212 | + progressCounter->setPropertyRecursive("totalProgress", QString::number(total)); | |
| 213 | + stream->projectUpdate(data, output); | |
| 196 | 214 | |
| 197 | 215 | files.append(output.files()); |
| 198 | 216 | |
| 217 | + if (multiProcess) | |
| 218 | + delete enroll; | |
| 219 | + | |
| 199 | 220 | return files; |
| 200 | 221 | } |
| 201 | 222 | |
| ... | ... | @@ -364,7 +385,6 @@ struct AlgorithmCore |
| 364 | 385 | targetMetadata = FileList::fromGallery(targetGallery, true); |
| 365 | 386 | queryMetadata = FileList::fromGallery(queryGallery, true); |
| 366 | 387 | |
| 367 | - | |
| 368 | 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 | 389 | transposeMode = targetMetadata.size() > queryMetadata.size(); |
| 370 | 390 | |
| ... | ... | @@ -389,12 +409,12 @@ struct AlgorithmCore |
| 389 | 409 | // simple make sure the enrolled data is stored in a memGallery, but in multi-process mode we save the enrolled |
| 390 | 410 | // data to disk (as a .gal file) so that each worker process can read it without re-doing enrollment. |
| 391 | 411 | File colEnrolledGallery = colGallery; |
| 392 | - QString targetExtension = multiProcess ? "gal" : "mem"; | |
| 412 | + QString targetExtension = "mem"; | |
| 393 | 413 | |
| 394 | 414 | // If the column gallery is not already of the appropriate type, we need to do something |
| 395 | 415 | if (colGallery.suffix() != targetExtension) { |
| 396 | 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 | 419 | // Check if we have to do real enrollment, and not just convert the gallery's type. |
| 400 | 420 | if (!(QStringList() << "gal" << "template" << "mem").contains(colGallery.suffix())) |
| ... | ... | @@ -435,37 +455,24 @@ struct AlgorithmCore |
| 435 | 455 | // The actual comparison step is done by a GalleryCompare transform, which has a Distance, and a gallery as data. |
| 436 | 456 | // Incoming templates are compared against the templates in the gallery, and the output is the resulting score |
| 437 | 457 | // vector. |
| 458 | + TemplateList tlist = TemplateList::fromGallery(colEnrolledGallery); | |
| 459 | + comparison->train(tlist); | |
| 460 | + comparison->setPropertyRecursive("galleryName",""); | |
| 461 | + | |
| 438 | 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 | 477 | // At this point, compareRegion is a transform, which optionally does enrollment, then compares the row |
| 471 | 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 | 480 | |
| 474 | 481 | // We also need to add Output and progress counting to the algorithm we are building, so we will assign them to |
| 475 | 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 | 486 | // The output transform takes the metadata memGalleries we set up previously as input, along with the |
| 480 | 487 | // output specification we were passed. Gallery metadata is necessary for some Outputs to function correctly. |
| 481 | 488 | QString outputString = output.flat().isEmpty() ? "Empty" : output.flat(); |
| 482 | 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 | 498 | // With this, we have set up a transform which (optionally) enrolls templates, compares them |
| 494 | 499 | // against a gallery, and outputs them. |
| 495 | - join->init(); | |
| 500 | + Transform *pipeline = br::pipeTransforms(compareOutput); | |
| 496 | 501 | |
| 497 | 502 | // Now, we will give that base transform to a stream, which will incrementally read the row gallery |
| 498 | 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 | 506 | // We set up a template containing the rowGallery we want to compare. |
| 508 | 507 | TemplateList rowGalleryTemplate; |
| 509 | 508 | rowGalleryTemplate.append(Template(rowGallery)); |
| 510 | 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 | 514 | // Do the actual comparisons |
| 519 | 515 | streamWrapper->projectUpdate(rowGalleryTemplate, outputGallery); |
| ... | ... | @@ -547,37 +543,39 @@ private: |
| 547 | 543 | |
| 548 | 544 | void init(const QString &description) |
| 549 | 545 | { |
| 550 | - if (loadOrExpand(description)) | |
| 546 | + bool newTForm = false; | |
| 547 | + | |
| 548 | + if (loadOrExpand(description)) { | |
| 549 | + simplifyTransform(); | |
| 551 | 550 | return; |
| 551 | + } | |
| 552 | 552 | |
| 553 | 553 | // check if the description is an abbreviation or model file with additional arguments supplied |
| 554 | 554 | File parsed("."+description); |
| 555 | 555 | if (loadOrExpand(parsed.suffix())) { |
| 556 | 556 | applyAdditionalProperties(parsed, transform.data()); |
| 557 | + simplifyTransform(); | |
| 557 | 558 | return; |
| 558 | 559 | } |
| 559 | 560 | |
| 561 | + //! [Parsing the algorithm description] | |
| 560 | 562 | const bool compareTransform = description.contains('!'); |
| 561 | 563 | QStringList words = QtUtils::parse(description, compareTransform ? '!' : ':'); |
| 562 | 564 | |
| 563 | 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 | 567 | //! [Creating the template generation and comparison methods] |
| 569 | 568 | transform = QSharedPointer<Transform>(Transform::make(words[0], NULL)); |
| 569 | + simplifyTransform(); | |
| 570 | + | |
| 570 | 571 | if (words.size() > 1) { |
| 571 | 572 | if (!compareTransform) { |
| 572 | 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 | 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 &scores, const FileList &targ |
| 81 | 81 | // otherwise, we fail |
| 82 | 82 | else |
| 83 | 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 | 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 &file, const QStringList &lines) |
| 105 | 105 | if (!f.open(QFile::WriteOnly)) |
| 106 | 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 | 109 | f.write((line+"\n").toLocal8Bit() ); |
| 110 | 110 | |
| 111 | 111 | f.close(); | ... | ... |
openbr/openbr.cpp
| ... | ... | @@ -28,7 +28,7 @@ |
| 28 | 28 | |
| 29 | 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 | 34 | QByteArray byteArray = string.toLocal8Bit(); |
| ... | ... | @@ -109,7 +109,7 @@ float br_eval(const char *simmat, const char *mask, const char *csv) |
| 109 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 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 | 245 | return partialCopy(Context::scratchPath(), buffer, buffer_length); |
| 246 | 246 | } |
| ... | ... | @@ -298,9 +298,9 @@ const char *br_version() |
| 298 | 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 | 304 | worker->transform = Globals->algorithm; |
| 305 | 305 | worker->baseName = baseName; |
| 306 | 306 | worker->mainLoop(); |
| ... | ... | @@ -371,7 +371,7 @@ bool br_img_is_empty(br_template tmpl) |
| 371 | 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 | 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 | 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 | 387 | Template *t = reinterpret_cast<Template*>(tmpl); |
| 388 | 388 | QVariant qvar = t->file.value(key); | ... | ... |
openbr/openbr_plugin.cpp
| ... | ... | @@ -585,16 +585,51 @@ QStringList Object::parameters() const |
| 585 | 585 | return parameters; |
| 586 | 586 | } |
| 587 | 587 | |
| 588 | -QStringList Object::arguments() const | |
| 588 | +QStringList Object::prunedArguments(bool expanded) const | |
| 589 | 589 | { |
| 590 | 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 | 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 | 634 | if ((index < 0) || (index > metaObject()->propertyCount())) return ""; |
| 600 | 635 | const QMetaProperty property = metaObject()->property(index); |
| ... | ... | @@ -612,19 +647,19 @@ QString Object::argument(int index) const |
| 612 | 647 | strings.append(QString::number(value)); |
| 613 | 648 | } else if (type == "QList<br::Transform*>") { |
| 614 | 649 | foreach (Transform *transform, variant.value< QList<Transform*> >()) |
| 615 | - strings.append(transform->description()); | |
| 650 | + strings.append(transform->description(expanded)); | |
| 616 | 651 | } else if (type == "QList<br::Distance*>") { |
| 617 | 652 | foreach (Distance *distance, variant.value< QList<Distance*> >()) |
| 618 | - strings.append(distance->description()); | |
| 653 | + strings.append(distance->description(expanded)); | |
| 619 | 654 | } else { |
| 620 | 655 | qFatal("Unrecognized type: %s", qPrintable(type)); |
| 621 | 656 | } |
| 622 | 657 | |
| 623 | 658 | return "[" + strings.join(",") + "]"; |
| 624 | 659 | } else if (type == "br::Transform*") { |
| 625 | - return variant.value<Transform*>()->description(); | |
| 660 | + return variant.value<Transform*>()->description(expanded); | |
| 626 | 661 | } else if (type == "br::Distance*") { |
| 627 | - return variant.value<Distance*>()->description(); | |
| 662 | + return variant.value<Distance*>()->description(expanded); | |
| 628 | 663 | } else if (type == "QStringList") { |
| 629 | 664 | return "[" + variant.toStringList().join(",") + "]"; |
| 630 | 665 | } |
| ... | ... | @@ -632,9 +667,12 @@ QString Object::argument(int index) const |
| 632 | 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 | 676 | return objectName() + (argumentString.isEmpty() ? "" : ("(" + argumentString + ")")); |
| 639 | 677 | } |
| 640 | 678 | |
| ... | ... | @@ -1292,7 +1330,7 @@ Transform *Transform::make(QString str, QObject *parent) |
| 1292 | 1330 | |
| 1293 | 1331 | Transform *Transform::clone() const |
| 1294 | 1332 | { |
| 1295 | - Transform *clone = Factory<Transform>::make(file.flat()); | |
| 1333 | + Transform *clone = Factory<Transform>::make("."+description(false)); | |
| 1296 | 1334 | return clone; |
| 1297 | 1335 | } |
| 1298 | 1336 | |
| ... | ... | @@ -1461,3 +1499,17 @@ void br::applyAdditionalProperties(const File &temp, Transform *target) |
| 1461 | 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 | 593 | virtual void store(QDataStream &stream) const; /*!< \brief Serialize the object. */ |
| 594 | 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 | 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 | 608 | void setProperty(const QString &name, QVariant value); /*!< \brief Overload of QObject::setProperty to handle OpenBR data types. */ |
| 601 | 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 | 1282 | */ |
| 1275 | 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 | 1300 | protected: |
| 1278 | 1301 | Transform(bool independent = true, bool trainable = true); /*!< \brief Construct a transform. */ |
| 1279 | 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 | 251 | default: |
| 252 | 252 | qFatal("Invalid operation."); |
| 253 | 253 | } |
| 254 | + return 0; | |
| 254 | 255 | } |
| 255 | 256 | |
| 256 | 257 | void store(QDataStream &stream) const |
| ... | ... | @@ -460,13 +461,12 @@ BR_REGISTER(Distance, SumDistance) |
| 460 | 461 | class GalleryCompareTransform : public Transform |
| 461 | 462 | { |
| 462 | 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 | 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 | 467 | BR_PROPERTY(QString, galleryName, "") |
| 467 | 468 | |
| 468 | 469 | TemplateList gallery; |
| 469 | - QSharedPointer<Distance> distance; | |
| 470 | 470 | |
| 471 | 471 | void project(const Template &src, Template &dst) const |
| 472 | 472 | { |
| ... | ... | @@ -480,16 +480,29 @@ class GalleryCompareTransform : public Transform |
| 480 | 480 | |
| 481 | 481 | void init() |
| 482 | 482 | { |
| 483 | - if (!galleryName.isEmpty()) { | |
| 483 | + if (!galleryName.isEmpty()) | |
| 484 | 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 | 504 | public: |
| 492 | - GalleryCompareTransform() : Transform(false, false) {} | |
| 505 | + GalleryCompareTransform() : Transform(false, true) {} | |
| 493 | 506 | }; |
| 494 | 507 | |
| 495 | 508 | BR_REGISTER(Transform, GalleryCompareTransform) | ... | ... |
openbr/plugins/frames.cpp
openbr/plugins/independent.cpp
| ... | ... | @@ -94,6 +94,12 @@ class DownsampleTrainingTransform : public Transform |
| 94 | 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 | 103 | void project(const Template &src, Template &dst) const |
| 98 | 104 | { |
| 99 | 105 | transform->project(src,dst); |
| ... | ... | @@ -126,6 +132,10 @@ class IndependentTransform : public MetaTransform |
| 126 | 132 | |
| 127 | 133 | QList<Transform*> transforms; |
| 128 | 134 | |
| 135 | + QString description(bool expanded) const | |
| 136 | + { | |
| 137 | + return transform->description(expanded); | |
| 138 | + } | |
| 129 | 139 | |
| 130 | 140 | bool setPropertyRecursive(const QString &name, QVariant value) |
| 131 | 141 | { |
| ... | ... | @@ -141,6 +151,54 @@ class IndependentTransform : public MetaTransform |
| 141 | 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 | 202 | void init() |
| 145 | 203 | { |
| 146 | 204 | transforms.clear(); | ... | ... |
openbr/plugins/meta.cpp
| ... | ... | @@ -482,17 +482,32 @@ BR_REGISTER(Transform, CacheTransform) |
| 482 | 482 | class LoadStoreTransform : public MetaTransform |
| 483 | 483 | { |
| 484 | 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 | 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 | 488 | BR_PROPERTY(QString, fileName, QString()) |
| 489 | 489 | |
| 490 | +public: | |
| 490 | 491 | Transform *transform; |
| 491 | 492 | QString baseName; |
| 492 | 493 | |
| 493 | -public: | |
| 494 | 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 | 511 | bool setPropertyRecursive(const QString &name, QVariant value) |
| 497 | 512 | { |
| 498 | 513 | if (br::Object::setPropertyRecursive(name, value)) |
| ... | ... | @@ -500,13 +515,16 @@ public: |
| 500 | 515 | return transform->setPropertyRecursive(name, value); |
| 501 | 516 | } |
| 502 | 517 | private: |
| 518 | + | |
| 503 | 519 | void init() |
| 504 | 520 | { |
| 505 | 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 | 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 | 530 | bool timeVarying() const |
| ... | ... | @@ -524,7 +542,7 @@ private: |
| 524 | 542 | qDebug("Storing %s", qPrintable(baseName)); |
| 525 | 543 | QByteArray byteArray; |
| 526 | 544 | QDataStream stream(&byteArray, QFile::WriteOnly); |
| 527 | - stream << description; | |
| 545 | + stream << transform->description(); | |
| 528 | 546 | transform->store(stream); |
| 529 | 547 | QtUtils::writeFile(baseName, byteArray, -1); |
| 530 | 548 | } |
| ... | ... | @@ -570,8 +588,8 @@ private: |
| 570 | 588 | QByteArray data; |
| 571 | 589 | QtUtils::readFile(file, data, true); |
| 572 | 590 | QDataStream stream(&data, QFile::ReadOnly); |
| 573 | - stream >> description; | |
| 574 | - transform = Transform::make(description); | |
| 591 | + stream >> transformString; | |
| 592 | + transform = Transform::make(transformString); | |
| 575 | 593 | transform->load(stream); |
| 576 | 594 | return true; |
| 577 | 595 | } | ... | ... |
openbr/plugins/misc.cpp
| ... | ... | @@ -617,8 +617,8 @@ class ProgressCounterTransform : public TimeVaryingTransform |
| 617 | 617 | { |
| 618 | 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 | 623 | void projectUpdate(const TemplateList &src, TemplateList &dst) |
| 624 | 624 | { |
| ... | ... | @@ -658,16 +658,20 @@ class ProgressCounterTransform : public TimeVaryingTransform |
| 658 | 658 | (void) data; |
| 659 | 659 | float p = br_progress(); |
| 660 | 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 | 663 | Globals->currentStep = 0; |
| 662 | 664 | Globals->currentProgress = 0; |
| 663 | - Globals->totalSteps = 0; | |
| 665 | + Globals->totalSteps = totalProgress; | |
| 664 | 666 | } |
| 665 | 667 | |
| 666 | 668 | void init() |
| 667 | 669 | { |
| 668 | 670 | timer.start(); |
| 671 | + Globals->startTime.start(); | |
| 669 | 672 | Globals->currentStep = 0; |
| 670 | 673 | Globals->currentProgress = 0; |
| 674 | + Globals->totalSteps = totalProgress; | |
| 671 | 675 | } |
| 672 | 676 | |
| 673 | 677 | public: | ... | ... |
openbr/plugins/openbr_internal.h
| ... | ... | @@ -201,6 +201,33 @@ public: |
| 201 | 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 | 231 | bool setPropertyRecursive(const QString &name, QVariant value) |
| 205 | 232 | { |
| 206 | 233 | if (br::Object::setPropertyRecursive(name, value)) |
| ... | ... | @@ -212,6 +239,34 @@ public: |
| 212 | 239 | } |
| 213 | 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 | 325 | } |
| 271 | 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 | 333 | if (output == NULL) |
| 290 | 334 | qFatal("Dynamic cast failed!"); |
| ... | ... | @@ -303,6 +347,51 @@ public: |
| 303 | 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 | 395 | bool setPropertyRecursive(const QString &name, QVariant value) |
| 307 | 396 | { |
| 308 | 397 | if (br::Object::setPropertyRecursive(name, value)) |
| ... | ... | @@ -388,6 +477,10 @@ public: |
| 388 | 477 | |
| 389 | 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 | 486 | #endif // OPENBR_INTERNAL_H | ... | ... |
openbr/plugins/pp5.cpp
| ... | ... | @@ -450,8 +450,9 @@ class PP5GalleryTransform: public UntrainableMetaTransform |
| 450 | 450 | |
| 451 | 451 | ppr_gallery_type target; |
| 452 | 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 | 457 | TemplateList temp, output; |
| 457 | 458 | temp.append(src); |
| ... | ... | @@ -460,7 +461,7 @@ class PP5GalleryTransform: public UntrainableMetaTransform |
| 460 | 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 | 466 | dst.clear(); |
| 466 | 467 | QList<int> queryIDs; |
| ... | ... | @@ -495,11 +496,33 @@ class PP5GalleryTransform: public UntrainableMetaTransform |
| 495 | 496 | |
| 496 | 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 | 528 | BR_REGISTER(Transform, PP5GalleryTransform) | ... | ... |
openbr/plugins/process.cpp
| ... | ... | @@ -21,7 +21,7 @@ class CommunicationManager : public QObject |
| 21 | 21 | { |
| 22 | 22 | Q_OBJECT |
| 23 | 23 | public: |
| 24 | - QThread * basis; | |
| 24 | + QThread *basis; | |
| 25 | 25 | CommunicationManager() |
| 26 | 26 | { |
| 27 | 27 | basis = new QThread; |
| ... | ... | @@ -294,7 +294,7 @@ public: |
| 294 | 294 | QString serverName; |
| 295 | 295 | QString remoteName; |
| 296 | 296 | |
| 297 | - QLocalSocket * inbound; | |
| 297 | + QLocalSocket *inbound; | |
| 298 | 298 | QLocalSocket outbound; |
| 299 | 299 | QLocalServer server; |
| 300 | 300 | |
| ... | ... | @@ -305,13 +305,11 @@ public: |
| 305 | 305 | while (!inbound || inbound->state() != QLocalSocket::ConnectedState) { |
| 306 | 306 | bool res = receivedWait.wait(&receivedLock,30*1000); |
| 307 | 307 | if (!res) |
| 308 | - { | |
| 309 | 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 | 314 | emit pulseOutboundConnect(remoteName); |
| 317 | 315 | |
| ... | ... | @@ -330,7 +328,7 @@ public: |
| 330 | 328 | |
| 331 | 329 | |
| 332 | 330 | template<typename T> |
| 333 | - bool readData(T & input) | |
| 331 | + bool readData(T &input) | |
| 334 | 332 | { |
| 335 | 333 | emit pulseReadSerialized(); |
| 336 | 334 | QDataStream deserializer(readArray); |
| ... | ... | @@ -338,8 +336,18 @@ public: |
| 338 | 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 | 349 | template<typename T> |
| 342 | - bool sendData(const T & output) | |
| 350 | + bool sendData(const T &output) | |
| 343 | 351 | { |
| 344 | 352 | QBuffer buffer; |
| 345 | 353 | buffer.open(QBuffer::ReadWrite); |
| ... | ... | @@ -378,7 +386,7 @@ class EnrollmentWorker : public QObject |
| 378 | 386 | { |
| 379 | 387 | Q_OBJECT |
| 380 | 388 | public: |
| 381 | - CommunicationManager * comm; | |
| 389 | + CommunicationManager *comm; | |
| 382 | 390 | QString name; |
| 383 | 391 | |
| 384 | 392 | ~EnrollmentWorker() |
| ... | ... | @@ -389,10 +397,10 @@ public: |
| 389 | 397 | delete comm; |
| 390 | 398 | } |
| 391 | 399 | |
| 392 | - br::Transform * transform; | |
| 400 | + br::Transform *transform; | |
| 393 | 401 | |
| 394 | 402 | public: |
| 395 | - void connections(const QString & baseName) | |
| 403 | + void connections(const QString &baseName) | |
| 396 | 404 | { |
| 397 | 405 | comm = new CommunicationManager(); |
| 398 | 406 | name = baseName; |
| ... | ... | @@ -401,6 +409,8 @@ public: |
| 401 | 409 | comm->connectToRemote(baseName+"_master"); |
| 402 | 410 | |
| 403 | 411 | comm->waitForInbound(); |
| 412 | + | |
| 413 | + transform = comm->readTForm(); | |
| 404 | 414 | } |
| 405 | 415 | |
| 406 | 416 | void workerLoop() |
| ... | ... | @@ -428,7 +438,7 @@ public: |
| 428 | 438 | void WorkerProcess::mainLoop() |
| 429 | 439 | { |
| 430 | 440 | processInterface = new EnrollmentWorker(); |
| 431 | - processInterface->transform = Transform::make(this->transform,NULL); | |
| 441 | + processInterface->transform = NULL; | |
| 432 | 442 | processInterface->connections(baseName); |
| 433 | 443 | processInterface->workerLoop(); |
| 434 | 444 | delete processInterface; |
| ... | ... | @@ -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 | 512 | * \ingroup transforms |
| 483 | 513 | * \brief Interface to a separate process |
| 484 | 514 | * \author Charles Otto \cite caotto |
| 485 | 515 | */ |
| 486 | -class ProcessWrapperTransform : public TimeVaryingTransform | |
| 516 | +class ProcessWrapperTransform : public WrapperTransform | |
| 487 | 517 | { |
| 488 | 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 | 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 | 532 | if (src.empty()) |
| 501 | 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 | 547 | void train(const TemplateList& data) |
| 516 | 548 | { |
| 517 | 549 | (void) data; |
| 518 | 550 | } |
| 519 | 551 | |
| 520 | - // create the process | |
| 521 | 552 | void init() |
| 522 | 553 | { |
| 523 | 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 | 575 | // generate a uuid for our local servers |
| 532 | 576 | QUuid id = QUuid::createUuid(); |
| 533 | - baseKey = id.toString(); | |
| 577 | + QString baseKey = id.toString(); | |
| 534 | 578 | |
| 535 | 579 | QStringList argumentList; |
| 580 | + // We serialize and transmit the transform directly, so algorithm doesn't matter. | |
| 581 | + argumentList.append("-quiet"); | |
| 536 | 582 | argumentList.append("-algorithm"); |
| 537 | - argumentList.append(transform); | |
| 583 | + argumentList.append("Identity"); | |
| 538 | 584 | if (!Globals->path.isEmpty()) { |
| 539 | 585 | argumentList.append("-path"); |
| 540 | 586 | argumentList.append(Globals->path); |
| ... | ... | @@ -544,36 +590,25 @@ class ProcessWrapperTransform : public TimeVaryingTransform |
| 544 | 590 | argumentList.append("-slave"); |
| 545 | 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 | 609 | public: |
| 575 | 610 | bool processActive; |
| 576 | - ProcessWrapperTransform() : TimeVaryingTransform(false,false) { processActive = false; } | |
| 611 | + ProcessWrapperTransform() : WrapperTransform(false) { processActive = false; } | |
| 577 | 612 | }; |
| 578 | 613 | |
| 579 | 614 | BR_REGISTER(Transform, ProcessWrapperTransform) | ... | ... |
openbr/plugins/validate.cpp
| ... | ... | @@ -7,7 +7,7 @@ |
| 7 | 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 | 12 | transform->train(data); |
| 13 | 13 | } | ... | ... |