diff --git a/openbr/plugins/gui.cpp b/openbr/plugins/gui.cpp index 386772d..cd56e7a 100644 --- a/openbr/plugins/gui.cpp +++ b/openbr/plugins/gui.cpp @@ -70,6 +70,7 @@ public: DisplayWindow(QWidget * parent = NULL) : QLabel(parent) { + setFixedSize(200,200); QApplication::instance()->installEventFilter(this); } @@ -80,7 +81,13 @@ public slots: show(); setPixmap(pixmap); - setFixedSize(input.size()); + + // We appear to get a warning on windows if we set window width < 104. This is of course not + // reflected in the Qt min size settings, and I don't know how to query it. + QSize temp = input.size(); + if (temp.width() < 104) + temp.setWidth(104); + setFixedSize(temp); } diff --git a/openbr/plugins/misc.cpp b/openbr/plugins/misc.cpp index 9699c9e..09c214b 100644 --- a/openbr/plugins/misc.cpp +++ b/openbr/plugins/misc.cpp @@ -354,27 +354,31 @@ BR_REGISTER(Transform, AsTransform) /*! * \ingroup transforms - * \brief Change the template subject using a regular expresion matched to the file's base name. - * \author Josh Klontz \cite jklontz + * \brief Apply the input regular expression to the value of inputProperty, store the matched portion in outputProperty. + * \author Charles Otto \cite caotto */ -class SubjectTransform : public UntrainableMetaTransform +class RegexPropertyTransform : public UntrainableMetaTransform { Q_OBJECT Q_PROPERTY(QString regexp READ get_regexp WRITE set_regexp RESET reset_regexp STORED false) + Q_PROPERTY(QString inputProperty READ get_inputProperty WRITE set_inputProperty RESET reset_inputProperty STORED false) + Q_PROPERTY(QString outputProperty READ get_outputProperty WRITE set_outputProperty RESET reset_outputProperty STORED false) BR_PROPERTY(QString, regexp, "(.*)") + BR_PROPERTY(QString, inputProperty, "name") + BR_PROPERTY(QString, outputProperty, "Label") void project(const Template &src, Template &dst) const { dst = src; QRegularExpression re(regexp); - QRegularExpressionMatch match = re.match(dst.file.baseName()); + QRegularExpressionMatch match = re.match(dst.file.get(inputProperty)); if (!match.hasMatch()) - qFatal("Unable to match regular expression \"%s\" to base name \"%s\"!", qPrintable(regexp), qPrintable(dst.file.baseName())); - dst.file.set("Subject", match.captured(match.lastCapturedIndex())); + qFatal("Unable to match regular expression \"%s\" to base name \"%s\"!", qPrintable(regexp), qPrintable(dst.file.get(inputProperty))); + dst.file.set(outputProperty, match.captured(match.lastCapturedIndex())); } }; -BR_REGISTER(Transform, SubjectTransform) +BR_REGISTER(Transform, RegexPropertyTransform) /*! * \ingroup transforms @@ -470,6 +474,73 @@ class RestoreMatTransform : public UntrainableMetaTransform BR_REGISTER(Transform, RestoreMatTransform) +/*! + * \ingroup transforms + * \brief Incrementally output templates received to a gallery, based on the current filename + * When a template is received in projectUpdate for the first time since a finalize, open a new gallery based on the + * template's filename, and the galleryFormat property. + * Templates received in projectUpdate will be output to the gallery with a filename combining their original filename and + * their FrameNumber property, with the file extension specified by the fileFormat property. + * \author Charles Otto \cite caotto + */ +class IncrementalOutputTransform : public TimeVaryingTransform +{ + Q_OBJECT + + Q_PROPERTY(QString galleryFormat READ get_galleryFormat WRITE set_galleryFormat RESET reset_galleryFormat STORED false) + Q_PROPERTY(QString fileFormat READ get_fileFormat WRITE set_fileFormat RESET reset_fileFormat STORED false) + BR_PROPERTY(QString, galleryFormat, "") + BR_PROPERTY(QString, fileFormat, ".png") + + bool galleryUp; + + void projectUpdate(const TemplateList &src, TemplateList &dst) + { + if (src.empty()) + return; + + if (!galleryUp) { + QFileInfo finfo(src[0].file.name); + QString galleryName = finfo.baseName() + galleryFormat; + + writer = QSharedPointer (Factory::make(galleryName)); + galleryUp = true; + } + + dst = src; + foreach(const Template & t, src) { + if (t.empty()) + continue; + + // Build the output filename for this template + QFileInfo finfo(t.file.name); + QString outputName = finfo.baseName() +"_" + t.file.get("FrameNumber") + fileFormat; + + Template out = t; + out.file.name = outputName; + writer->write(out); + } + } + + void train(const TemplateList& data) + { + (void) data; + } + + // Drop the current gallery. + void finalize(TemplateList & data) + { + (void) data; + galleryUp = false; + } + + QSharedPointer writer; +public: + IncrementalOutputTransform() : TimeVaryingTransform(false,false) {galleryUp = false;} +}; + +BR_REGISTER(Transform, IncrementalOutputTransform) + class EventTransform : public UntrainableMetaTransform { Q_OBJECT diff --git a/openbr/plugins/stream.cpp b/openbr/plugins/stream.cpp index 15944be..4550baa 100644 --- a/openbr/plugins/stream.cpp +++ b/openbr/plugins/stream.cpp @@ -364,6 +364,7 @@ protected: QMutex last_frame_update; }; +static QMutex openLock; // Read a video frame by frame using cv::VideoCapture class VideoDataSource : public DataSource { @@ -396,6 +397,8 @@ public: // Yes, we should specify absolute path: // http://stackoverflow.com/questions/9396459/loading-a-video-in-opencv-in-python QString fileName = (Globals->path.isEmpty() ? "" : Globals->path + "/") + input.file.name; + // On windows, this appears to not be thread-safe + QMutexLocker lock(&openLock); video.open(QFileInfo(fileName).absoluteFilePath().toStdString()); } @@ -1057,7 +1060,10 @@ public: dst = src; bool res = readStage->dataSource.open(dst); - if (!res) return; + if (!res) { + qDebug("stream failed to open %s", qPrintable(dst[0].file.name)); + return; + } // Start the first thread in the stream. QWriteLocker lock(&readStage->statusLock);