Commit 5b3c7a8e3f84b7b1a74e239aac740aed90c9b1dc
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
3 changed files
with
93 additions
and
9 deletions
openbr/plugins/gui.cpp
| ... | ... | @@ -70,6 +70,7 @@ public: |
| 70 | 70 | |
| 71 | 71 | DisplayWindow(QWidget * parent = NULL) : QLabel(parent) |
| 72 | 72 | { |
| 73 | + setFixedSize(200,200); | |
| 73 | 74 | QApplication::instance()->installEventFilter(this); |
| 74 | 75 | } |
| 75 | 76 | |
| ... | ... | @@ -80,7 +81,13 @@ public slots: |
| 80 | 81 | |
| 81 | 82 | show(); |
| 82 | 83 | setPixmap(pixmap); |
| 83 | - setFixedSize(input.size()); | |
| 84 | + | |
| 85 | + // We appear to get a warning on windows if we set window width < 104. This is of course not | |
| 86 | + // reflected in the Qt min size settings, and I don't know how to query it. | |
| 87 | + QSize temp = input.size(); | |
| 88 | + if (temp.width() < 104) | |
| 89 | + temp.setWidth(104); | |
| 90 | + setFixedSize(temp); | |
| 84 | 91 | } |
| 85 | 92 | |
| 86 | 93 | ... | ... |
openbr/plugins/misc.cpp
| ... | ... | @@ -354,27 +354,31 @@ BR_REGISTER(Transform, AsTransform) |
| 354 | 354 | |
| 355 | 355 | /*! |
| 356 | 356 | * \ingroup transforms |
| 357 | - * \brief Change the template subject using a regular expresion matched to the file's base name. | |
| 358 | - * \author Josh Klontz \cite jklontz | |
| 357 | + * \brief Apply the input regular expression to the value of inputProperty, store the matched portion in outputProperty. | |
| 358 | + * \author Charles Otto \cite caotto | |
| 359 | 359 | */ |
| 360 | -class SubjectTransform : public UntrainableMetaTransform | |
| 360 | +class RegexPropertyTransform : public UntrainableMetaTransform | |
| 361 | 361 | { |
| 362 | 362 | Q_OBJECT |
| 363 | 363 | Q_PROPERTY(QString regexp READ get_regexp WRITE set_regexp RESET reset_regexp STORED false) |
| 364 | + Q_PROPERTY(QString inputProperty READ get_inputProperty WRITE set_inputProperty RESET reset_inputProperty STORED false) | |
| 365 | + Q_PROPERTY(QString outputProperty READ get_outputProperty WRITE set_outputProperty RESET reset_outputProperty STORED false) | |
| 364 | 366 | BR_PROPERTY(QString, regexp, "(.*)") |
| 367 | + BR_PROPERTY(QString, inputProperty, "name") | |
| 368 | + BR_PROPERTY(QString, outputProperty, "Label") | |
| 365 | 369 | |
| 366 | 370 | void project(const Template &src, Template &dst) const |
| 367 | 371 | { |
| 368 | 372 | dst = src; |
| 369 | 373 | QRegularExpression re(regexp); |
| 370 | - QRegularExpressionMatch match = re.match(dst.file.baseName()); | |
| 374 | + QRegularExpressionMatch match = re.match(dst.file.get<QString>(inputProperty)); | |
| 371 | 375 | if (!match.hasMatch()) |
| 372 | - qFatal("Unable to match regular expression \"%s\" to base name \"%s\"!", qPrintable(regexp), qPrintable(dst.file.baseName())); | |
| 373 | - dst.file.set("Subject", match.captured(match.lastCapturedIndex())); | |
| 376 | + qFatal("Unable to match regular expression \"%s\" to base name \"%s\"!", qPrintable(regexp), qPrintable(dst.file.get<QString>(inputProperty))); | |
| 377 | + dst.file.set(outputProperty, match.captured(match.lastCapturedIndex())); | |
| 374 | 378 | } |
| 375 | 379 | }; |
| 376 | 380 | |
| 377 | -BR_REGISTER(Transform, SubjectTransform) | |
| 381 | +BR_REGISTER(Transform, RegexPropertyTransform) | |
| 378 | 382 | |
| 379 | 383 | /*! |
| 380 | 384 | * \ingroup transforms |
| ... | ... | @@ -470,6 +474,73 @@ class RestoreMatTransform : public UntrainableMetaTransform |
| 470 | 474 | BR_REGISTER(Transform, RestoreMatTransform) |
| 471 | 475 | |
| 472 | 476 | |
| 477 | +/*! | |
| 478 | + * \ingroup transforms | |
| 479 | + * \brief Incrementally output templates received to a gallery, based on the current filename | |
| 480 | + * When a template is received in projectUpdate for the first time since a finalize, open a new gallery based on the | |
| 481 | + * template's filename, and the galleryFormat property. | |
| 482 | + * Templates received in projectUpdate will be output to the gallery with a filename combining their original filename and | |
| 483 | + * their FrameNumber property, with the file extension specified by the fileFormat property. | |
| 484 | + * \author Charles Otto \cite caotto | |
| 485 | + */ | |
| 486 | +class IncrementalOutputTransform : public TimeVaryingTransform | |
| 487 | +{ | |
| 488 | + Q_OBJECT | |
| 489 | + | |
| 490 | + Q_PROPERTY(QString galleryFormat READ get_galleryFormat WRITE set_galleryFormat RESET reset_galleryFormat STORED false) | |
| 491 | + Q_PROPERTY(QString fileFormat READ get_fileFormat WRITE set_fileFormat RESET reset_fileFormat STORED false) | |
| 492 | + BR_PROPERTY(QString, galleryFormat, "") | |
| 493 | + BR_PROPERTY(QString, fileFormat, ".png") | |
| 494 | + | |
| 495 | + bool galleryUp; | |
| 496 | + | |
| 497 | + void projectUpdate(const TemplateList &src, TemplateList &dst) | |
| 498 | + { | |
| 499 | + if (src.empty()) | |
| 500 | + return; | |
| 501 | + | |
| 502 | + if (!galleryUp) { | |
| 503 | + QFileInfo finfo(src[0].file.name); | |
| 504 | + QString galleryName = finfo.baseName() + galleryFormat; | |
| 505 | + | |
| 506 | + writer = QSharedPointer<Gallery> (Factory<Gallery>::make(galleryName)); | |
| 507 | + galleryUp = true; | |
| 508 | + } | |
| 509 | + | |
| 510 | + dst = src; | |
| 511 | + foreach(const Template & t, src) { | |
| 512 | + if (t.empty()) | |
| 513 | + continue; | |
| 514 | + | |
| 515 | + // Build the output filename for this template | |
| 516 | + QFileInfo finfo(t.file.name); | |
| 517 | + QString outputName = finfo.baseName() +"_" + t.file.get<QString>("FrameNumber") + fileFormat; | |
| 518 | + | |
| 519 | + Template out = t; | |
| 520 | + out.file.name = outputName; | |
| 521 | + writer->write(out); | |
| 522 | + } | |
| 523 | + } | |
| 524 | + | |
| 525 | + void train(const TemplateList& data) | |
| 526 | + { | |
| 527 | + (void) data; | |
| 528 | + } | |
| 529 | + | |
| 530 | + // Drop the current gallery. | |
| 531 | + void finalize(TemplateList & data) | |
| 532 | + { | |
| 533 | + (void) data; | |
| 534 | + galleryUp = false; | |
| 535 | + } | |
| 536 | + | |
| 537 | + QSharedPointer<Gallery> writer; | |
| 538 | +public: | |
| 539 | + IncrementalOutputTransform() : TimeVaryingTransform(false,false) {galleryUp = false;} | |
| 540 | +}; | |
| 541 | + | |
| 542 | +BR_REGISTER(Transform, IncrementalOutputTransform) | |
| 543 | + | |
| 473 | 544 | class EventTransform : public UntrainableMetaTransform |
| 474 | 545 | { |
| 475 | 546 | Q_OBJECT | ... | ... |
openbr/plugins/stream.cpp
| ... | ... | @@ -364,6 +364,7 @@ protected: |
| 364 | 364 | QMutex last_frame_update; |
| 365 | 365 | }; |
| 366 | 366 | |
| 367 | +static QMutex openLock; | |
| 367 | 368 | // Read a video frame by frame using cv::VideoCapture |
| 368 | 369 | class VideoDataSource : public DataSource |
| 369 | 370 | { |
| ... | ... | @@ -396,6 +397,8 @@ public: |
| 396 | 397 | // Yes, we should specify absolute path: |
| 397 | 398 | // http://stackoverflow.com/questions/9396459/loading-a-video-in-opencv-in-python |
| 398 | 399 | QString fileName = (Globals->path.isEmpty() ? "" : Globals->path + "/") + input.file.name; |
| 400 | + // On windows, this appears to not be thread-safe | |
| 401 | + QMutexLocker lock(&openLock); | |
| 399 | 402 | video.open(QFileInfo(fileName).absoluteFilePath().toStdString()); |
| 400 | 403 | } |
| 401 | 404 | |
| ... | ... | @@ -1057,7 +1060,10 @@ public: |
| 1057 | 1060 | dst = src; |
| 1058 | 1061 | |
| 1059 | 1062 | bool res = readStage->dataSource.open(dst); |
| 1060 | - if (!res) return; | |
| 1063 | + if (!res) { | |
| 1064 | + qDebug("stream failed to open %s", qPrintable(dst[0].file.name)); | |
| 1065 | + return; | |
| 1066 | + } | |
| 1061 | 1067 | |
| 1062 | 1068 | // Start the first thread in the stream. |
| 1063 | 1069 | QWriteLocker lock(&readStage->statusLock); | ... | ... |