diff --git a/app/br/br.cpp b/app/br/br.cpp index 5f8060c..abeeab1 100644 --- a/app/br/br.cpp +++ b/app/br/br.cpp @@ -167,6 +167,8 @@ public: else if (!strcmp(fun, "help")) { check(parc == 0, "No parameters expected for 'help'."); help(); + } else if (!strcmp(fun, "gui")) { + // Do nothing because we checked for this flag prior to initialization } else if (!strcmp(fun, "objects")) { check(parc <= 2, "Incorrect parameter count for 'objects'."); printf("%s\n", br_objects(parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*")); @@ -180,11 +182,10 @@ public: check(parc == 1, "Incorrect parameter count for 'daemon'."); daemon = true; daemon_pipe = parv[0]; - } else if (!strcmp(fun,"slave")) { + } else if (!strcmp(fun, "slave")) { check(parc == 1, "Incorrect parameter count for 'slave'"); br_slave_process(parv[0]); - } - else if (!strcmp(fun, "exit")) { + } else if (!strcmp(fun, "exit")) { check(parc == 0, "No parameters expected for 'exit'."); daemon = false; } else if (!strcmp(fun, "getHeader")) { @@ -248,6 +249,7 @@ private: "\n" "==== Miscellaneous ====\n" "-help\n" + "-gui\n" "-objects [abstraction [implementation]]\n" "-about\n" "-version\n" @@ -258,7 +260,7 @@ private: int main(int argc, char *argv[]) { - br_initialize(argc, argv); + br_initialize(argc, argv, "", argc >= 2 && !strcmp(argv[1], "-gui")); FakeMain *fakeMain = new FakeMain(argc, argv); QThreadPool::globalInstance()->start(fakeMain); diff --git a/openbr/core/core.cpp b/openbr/core/core.cpp index 28b213d..962d5b6 100644 --- a/openbr/core/core.cpp +++ b/openbr/core/core.cpp @@ -65,6 +65,9 @@ struct AlgorithmCore downcast->train(data); if (!distance.isNull()) { + if (Globals->crossValidate > 0) + for (int i=data.size()-1; i>=0; i--) if (data[i].file.get("allPartitions",false)) data.removeAt(i); + qDebug("Projecting Enrollment"); downcast->projectUpdate(data,data); diff --git a/openbr/janus b/openbr/janus index 02fd545..f8d9c86 160000 --- a/openbr/janus +++ b/openbr/janus @@ -1 +1 @@ -Subproject commit 02fd545b2dbb8ea2ba10dbf67e429da598545d75 +Subproject commit f8d9c869c821cc032d092ab1274da8f3cabf5eb7 diff --git a/openbr/janus.cpp b/openbr/janus.cpp index 50e402b..3a567fb 100644 --- a/openbr/janus.cpp +++ b/openbr/janus.cpp @@ -13,7 +13,7 @@ static QSharedPointer distance; size_t janus_max_template_size() { - return JANUS_MAX_TEMPLATE_SIZE_LIMIT; + return 33554432; // 32 MB } janus_error janus_initialize(const char *sdk_path, const char *model_file) diff --git a/openbr/openbr.cpp b/openbr/openbr.cpp index 23efde0..5582f8d 100644 --- a/openbr/openbr.cpp +++ b/openbr/openbr.cpp @@ -122,9 +122,9 @@ void br_fuse(int num_input_simmats, const char *input_simmats[], Fuse(QtUtils::toStringList(num_input_simmats, input_simmats), normalization, fusion, output_simmat); } -void br_initialize(int &argc, char *argv[], const char *sdk_path) +void br_initialize(int &argc, char *argv[], const char *sdk_path, bool use_gui) { - Context::initialize(argc, argv, sdk_path); + Context::initialize(argc, argv, sdk_path, use_gui); } void br_initialize_default() @@ -382,10 +382,9 @@ bool br_img_is_empty(br_template tmpl) const char* br_get_filename(br_template tmpl) { - Template *t = reinterpret_cast(tmpl); - QByteArray s = t->file.name.toLocal8Bit(); - char *buffer = s.data(); - return buffer; + static QByteArray buffer; + buffer = reinterpret_cast(tmpl)->file.name.toLocal8Bit(); + return buffer.data(); } void br_set_filename(br_template tmpl, const char *filename) diff --git a/openbr/openbr.h b/openbr/openbr.h index da3fd13..d1bd2c2 100644 --- a/openbr/openbr.h +++ b/openbr/openbr.h @@ -224,7 +224,7 @@ BR_EXPORT void br_fuse(int num_input_simmats, const char *input_simmats[], * \brief Wraps br::Context::initialize() * \see br_finalize */ -BR_EXPORT void br_initialize(int &argc, char *argv[], const char *sdk_path = ""); +BR_EXPORT void br_initialize(int &argc, char *argv[], const char *sdk_path = "", bool use_gui = false); /*! * \brief Wraps br::Context::initialize() with default arguments. * \see br_finalize diff --git a/openbr/openbr_plugin.cpp b/openbr/openbr_plugin.cpp index 80f0559..91c4d70 100644 --- a/openbr/openbr_plugin.cpp +++ b/openbr/openbr_plugin.cpp @@ -899,8 +899,12 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool useG { qInstallMessageHandler(messageHandler); + QString sep; #ifndef _WIN32 useGui = useGui && (getenv("DISPLAY") != NULL); + sep = ":"; +#else + sep = ";"; #endif // not _WIN32 // We take in argc as a reference due to: @@ -944,6 +948,7 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool useG // Search for SDK if (sdkPath.isEmpty()) { QStringList checkPaths; checkPaths << QDir::currentPath() << QCoreApplication::applicationDirPath(); + checkPaths << QString(getenv("PATH")).split(sep, QString::SkipEmptyParts); bool foundSDK = false; foreach (const QString &path, checkPaths) { diff --git a/openbr/plugins/gui.cpp b/openbr/plugins/gui.cpp index a508d26..0653eeb 100644 --- a/openbr/plugins/gui.cpp +++ b/openbr/plugins/gui.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -182,6 +183,149 @@ public slots: } }; +class RectMarkingWindow : public DisplayWindow +{ +public: + RectMarkingWindow() : DisplayWindow() + { + drawingRect = false; + } + + bool drawingRect; + QVector rects; + QList rectLabels; + + QPointF rectOrigin; + QPointF currentEnd; + QRectF currentRect; + bool disableAccept; + + bool eventFilter(QObject *obj, QEvent *event) + { + if (disableAccept) + return QObject::eventFilter(obj, event); + + + if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseMove) + { + event->accept(); + + QMouseEvent *mouseEvent = (QMouseEvent*)event; + + if (event->type() == QEvent::MouseButtonPress) + { + + if (mouseEvent->button() == Qt::LeftButton) { + if (!drawingRect) + { + drawingRect = true; + rectOrigin = mouseEvent->pos(); + return true; + } + else + { + drawingRect = false; + + rects.append(QRectF(rectOrigin, mouseEvent->pos())); + rects.last() = rects.last().normalized(); + // If no labels were provided, we store everything as anonymous rectangles + if (promptKeys.empty()) + rectLabels.append("rects"); + // otherwise, prompt the user to select a label + else + { + // get a label from the user + bool ok = false; + + // Don't intercept events while the sub-dialog is up (if we take the events, then it will not work correctly) + disableAccept = true; + QString res = QInputDialog::getItem(this, "Select a label", "", promptKeys, next_idx, false, &ok); + + disableAccept = false; + if (ok) { + rectLabels.append(res); + for (int i=0; i < promptKeys.size(); i++) + { + if (res == promptKeys[i]) { + next_idx = (i + 1) % promptKeys.size(); + break; + } + } + } + else { + rects.removeLast(); + } + } + } + } + // rclick -- reset state if drawing, remove last rect if done + else if (mouseEvent->button() == Qt::RightButton && (!rects.isEmpty() || drawingRect)) + { + if(drawingRect) + drawingRect = false; + else + { + rects.removeLast(); + rectLabels.removeLast(); + } + } + } + else + currentEnd = mouseEvent->pos(); + QPixmap pixmapBuffer = pixmap; + + QPainter painter(&pixmapBuffer); + painter.setPen(Qt::red); + + painter.drawRects(rects); + + if (drawingRect) + { + currentRect = QRectF(rectOrigin, currentEnd); + painter.setPen(Qt::green); + painter.drawRect(currentRect); + } + + setPixmap(pixmapBuffer); + + return true; + } else { + if (event->type() == QEvent::KeyPress) + { + QKeyEvent * kevent = (QKeyEvent *) event; + if (kevent->key() == Qt::Key_Enter || kevent->key() == Qt::Key_Return) { + event->accept(); + return true; + } + } + return DisplayWindow::eventFilter(obj, event); + } + } + + + QList waitForKey() + { + + rects.clear(); + drawingRect = false; + disableAccept = false; + next_idx = 0; + DisplayWindow::waitForKey(); + + return QList(); + } + + void setKeys(const QStringList & keys) + { + promptKeys = keys; + } + + int next_idx; +private: + QStringList promptKeys; + +}; + class PointMarkingWindow : public DisplayWindow { bool eventFilter(QObject *obj, QEvent *event) @@ -556,6 +700,87 @@ BR_REGISTER(Transform, ManualTransform) /*! * \ingroup transforms + * \brief Manual select rectangular regions on an image. + * Stores marked rectangles as anonymous rectangles, or if a set of labels is provided, prompt the user + * to select one of those labels after drawing each rectangle. + * \author Charles Otto \cite caotto + */ +class ManualRectsTransform : public ShowTransform +{ + Q_OBJECT + +public: + + Q_PROPERTY(QStringList labels READ get_labels WRITE set_labels RESET reset_labels STORED false) + BR_PROPERTY(QStringList, labels, QStringList()) + + void projectUpdate(const TemplateList &src, TemplateList &dst) + { + + dst = src; + + if (src.empty()) + return; + + for (int i = 0; i < dst.size(); i++) { + foreach(const cv::Mat &m, dst[i]) { + qImageBuffer = toQImage(m); + displayBuffer->convertFromImage(qImageBuffer); + + emit updateImage(displayBuffer->copy(displayBuffer->rect())); + + // Blocking wait for a key-press + if (this->waitInput) { + window->waitForKey(); + QVector rectSet = trueWindow->rects; + QList labelSet= trueWindow->rectLabels; + + for (int idx = 0; idx < rectSet.size(); idx++) + { + if (dst[i].file.contains(labelSet[idx])) + { + QVariant currentProp = dst[i].file.value(labelSet[idx]); + QList currentPropList; + + if (currentProp.canConvert >() ) + { + currentPropList = currentProp.toList(); + } + else if (currentProp.canConvert()) + { + currentPropList.append(currentProp); + } + else + { + qFatal("Unknown type of property"); + } + + currentPropList.append(rectSet[idx]); + dst[i].file.set(labelSet[idx], QVariant::fromValue(currentPropList)); + } + else + { + dst[i].file.set(labelSet[idx], rectSet[idx]); + } + } + } + + } + } + } + RectMarkingWindow * trueWindow; + void init() + { + initActual(); + trueWindow = dynamic_cast (this->window); + trueWindow->setKeys(this->keys); + } +}; + +BR_REGISTER(Transform, ManualRectsTransform) + +/*! + * \ingroup transforms * \brief Elicits metadata for templates in a pretty GUI * \author Scott Klum \cite sklum */ diff --git a/openbr/plugins/output.cpp b/openbr/plugins/output.cpp index 512a7bb..b9a290a 100644 --- a/openbr/plugins/output.cpp +++ b/openbr/plugins/output.cpp @@ -268,7 +268,7 @@ class rrOutput : public MatrixOutput for (int i=0; i Pair; foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector(data.row(i)), true, limit)) { @@ -276,7 +276,7 @@ class rrOutput : public MatrixOutput if (pair.first < threshold) break; File target = targetFiles[pair.second]; target.set("Score", QString::number(pair.first)); - if (simple) files.append(target.baseName() + " " + QString::number(pair.first)); + if (simple) files.append(target.fileName() + " " + QString::number(pair.first)); else files.append(target.flat()); } } diff --git a/openbr/plugins/validate.cpp b/openbr/plugins/validate.cpp index d1f1dc0..f5eaf19 100644 --- a/openbr/plugins/validate.cpp +++ b/openbr/plugins/validate.cpp @@ -108,6 +108,7 @@ class CrossValidateTransform : public MetaTransform // If we want to duplicate templates but use the same training data // for all partitions (i.e. transforms.size() == 1), we need to // restrict the partition + int partition = src.file.get("Partition", 0); partition = (partition >= transforms.size()) ? 0 : partition; transforms[partition]->project(src, dst);