Commit e6ad9c2274ce1248cd833074296cfeea5200afb3
Merge branch 'master' of https://github.com/biometrics/openbr
Showing
10 changed files
with
250 additions
and
15 deletions
app/br/br.cpp
| ... | ... | @@ -167,6 +167,8 @@ public: |
| 167 | 167 | else if (!strcmp(fun, "help")) { |
| 168 | 168 | check(parc == 0, "No parameters expected for 'help'."); |
| 169 | 169 | help(); |
| 170 | + } else if (!strcmp(fun, "gui")) { | |
| 171 | + // Do nothing because we checked for this flag prior to initialization | |
| 170 | 172 | } else if (!strcmp(fun, "objects")) { |
| 171 | 173 | check(parc <= 2, "Incorrect parameter count for 'objects'."); |
| 172 | 174 | printf("%s\n", br_objects(parc >= 1 ? parv[0] : ".*", parc >= 2 ? parv[1] : ".*")); |
| ... | ... | @@ -180,11 +182,10 @@ public: |
| 180 | 182 | check(parc == 1, "Incorrect parameter count for 'daemon'."); |
| 181 | 183 | daemon = true; |
| 182 | 184 | daemon_pipe = parv[0]; |
| 183 | - } else if (!strcmp(fun,"slave")) { | |
| 185 | + } else if (!strcmp(fun, "slave")) { | |
| 184 | 186 | check(parc == 1, "Incorrect parameter count for 'slave'"); |
| 185 | 187 | br_slave_process(parv[0]); |
| 186 | - } | |
| 187 | - else if (!strcmp(fun, "exit")) { | |
| 188 | + } else if (!strcmp(fun, "exit")) { | |
| 188 | 189 | check(parc == 0, "No parameters expected for 'exit'."); |
| 189 | 190 | daemon = false; |
| 190 | 191 | } else if (!strcmp(fun, "getHeader")) { |
| ... | ... | @@ -248,6 +249,7 @@ private: |
| 248 | 249 | "\n" |
| 249 | 250 | "==== Miscellaneous ====\n" |
| 250 | 251 | "-help\n" |
| 252 | + "-gui\n" | |
| 251 | 253 | "-objects [abstraction [implementation]]\n" |
| 252 | 254 | "-about\n" |
| 253 | 255 | "-version\n" |
| ... | ... | @@ -258,7 +260,7 @@ private: |
| 258 | 260 | |
| 259 | 261 | int main(int argc, char *argv[]) |
| 260 | 262 | { |
| 261 | - br_initialize(argc, argv); | |
| 263 | + br_initialize(argc, argv, "", argc >= 2 && !strcmp(argv[1], "-gui")); | |
| 262 | 264 | |
| 263 | 265 | FakeMain *fakeMain = new FakeMain(argc, argv); |
| 264 | 266 | QThreadPool::globalInstance()->start(fakeMain); | ... | ... |
openbr/core/core.cpp
| ... | ... | @@ -65,6 +65,9 @@ struct AlgorithmCore |
| 65 | 65 | downcast->train(data); |
| 66 | 66 | |
| 67 | 67 | if (!distance.isNull()) { |
| 68 | + if (Globals->crossValidate > 0) | |
| 69 | + for (int i=data.size()-1; i>=0; i--) if (data[i].file.get<bool>("allPartitions",false)) data.removeAt(i); | |
| 70 | + | |
| 68 | 71 | qDebug("Projecting Enrollment"); |
| 69 | 72 | downcast->projectUpdate(data,data); |
| 70 | 73 | ... | ... |
openbr/janus.cpp
| ... | ... | @@ -13,7 +13,7 @@ static QSharedPointer<Distance> distance; |
| 13 | 13 | |
| 14 | 14 | size_t janus_max_template_size() |
| 15 | 15 | { |
| 16 | - return JANUS_MAX_TEMPLATE_SIZE_LIMIT; | |
| 16 | + return 33554432; // 32 MB | |
| 17 | 17 | } |
| 18 | 18 | |
| 19 | 19 | janus_error janus_initialize(const char *sdk_path, const char *model_file) | ... | ... |
openbr/openbr.cpp
| ... | ... | @@ -122,9 +122,9 @@ void br_fuse(int num_input_simmats, const char *input_simmats[], |
| 122 | 122 | Fuse(QtUtils::toStringList(num_input_simmats, input_simmats), normalization, fusion, output_simmat); |
| 123 | 123 | } |
| 124 | 124 | |
| 125 | -void br_initialize(int &argc, char *argv[], const char *sdk_path) | |
| 125 | +void br_initialize(int &argc, char *argv[], const char *sdk_path, bool use_gui) | |
| 126 | 126 | { |
| 127 | - Context::initialize(argc, argv, sdk_path); | |
| 127 | + Context::initialize(argc, argv, sdk_path, use_gui); | |
| 128 | 128 | } |
| 129 | 129 | |
| 130 | 130 | void br_initialize_default() |
| ... | ... | @@ -382,10 +382,9 @@ bool br_img_is_empty(br_template tmpl) |
| 382 | 382 | |
| 383 | 383 | const char* br_get_filename(br_template tmpl) |
| 384 | 384 | { |
| 385 | - Template *t = reinterpret_cast<Template*>(tmpl); | |
| 386 | - QByteArray s = t->file.name.toLocal8Bit(); | |
| 387 | - char *buffer = s.data(); | |
| 388 | - return buffer; | |
| 385 | + static QByteArray buffer; | |
| 386 | + buffer = reinterpret_cast<Template*>(tmpl)->file.name.toLocal8Bit(); | |
| 387 | + return buffer.data(); | |
| 389 | 388 | } |
| 390 | 389 | |
| 391 | 390 | void br_set_filename(br_template tmpl, const char *filename) | ... | ... |
openbr/openbr.h
| ... | ... | @@ -224,7 +224,7 @@ BR_EXPORT void br_fuse(int num_input_simmats, const char *input_simmats[], |
| 224 | 224 | * \brief Wraps br::Context::initialize() |
| 225 | 225 | * \see br_finalize |
| 226 | 226 | */ |
| 227 | -BR_EXPORT void br_initialize(int &argc, char *argv[], const char *sdk_path = ""); | |
| 227 | +BR_EXPORT void br_initialize(int &argc, char *argv[], const char *sdk_path = "", bool use_gui = false); | |
| 228 | 228 | /*! |
| 229 | 229 | * \brief Wraps br::Context::initialize() with default arguments. |
| 230 | 230 | * \see br_finalize | ... | ... |
openbr/openbr_plugin.cpp
| ... | ... | @@ -899,8 +899,12 @@ void br::Context::initialize(int &argc, char *argv[], QString sdkPath, bool useG |
| 899 | 899 | { |
| 900 | 900 | qInstallMessageHandler(messageHandler); |
| 901 | 901 | |
| 902 | + QString sep; | |
| 902 | 903 | #ifndef _WIN32 |
| 903 | 904 | useGui = useGui && (getenv("DISPLAY") != NULL); |
| 905 | + sep = ":"; | |
| 906 | +#else | |
| 907 | + sep = ";"; | |
| 904 | 908 | #endif // not _WIN32 |
| 905 | 909 | |
| 906 | 910 | // 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 |
| 944 | 948 | // Search for SDK |
| 945 | 949 | if (sdkPath.isEmpty()) { |
| 946 | 950 | QStringList checkPaths; checkPaths << QDir::currentPath() << QCoreApplication::applicationDirPath(); |
| 951 | + checkPaths << QString(getenv("PATH")).split(sep, QString::SkipEmptyParts); | |
| 947 | 952 | |
| 948 | 953 | bool foundSDK = false; |
| 949 | 954 | foreach (const QString &path, checkPaths) { | ... | ... |
openbr/plugins/gui.cpp
| 1 | 1 | #include <QApplication> |
| 2 | 2 | #include <QLabel> |
| 3 | 3 | #include <QElapsedTimer> |
| 4 | +#include <QInputDialog> | |
| 4 | 5 | #include <QWaitCondition> |
| 5 | 6 | #include <QMutex> |
| 6 | 7 | #include <QMouseEvent> |
| ... | ... | @@ -182,6 +183,149 @@ public slots: |
| 182 | 183 | } |
| 183 | 184 | }; |
| 184 | 185 | |
| 186 | +class RectMarkingWindow : public DisplayWindow | |
| 187 | +{ | |
| 188 | +public: | |
| 189 | + RectMarkingWindow() : DisplayWindow() | |
| 190 | + { | |
| 191 | + drawingRect = false; | |
| 192 | + } | |
| 193 | + | |
| 194 | + bool drawingRect; | |
| 195 | + QVector<QRectF> rects; | |
| 196 | + QList<QString> rectLabels; | |
| 197 | + | |
| 198 | + QPointF rectOrigin; | |
| 199 | + QPointF currentEnd; | |
| 200 | + QRectF currentRect; | |
| 201 | + bool disableAccept; | |
| 202 | + | |
| 203 | + bool eventFilter(QObject *obj, QEvent *event) | |
| 204 | + { | |
| 205 | + if (disableAccept) | |
| 206 | + return QObject::eventFilter(obj, event); | |
| 207 | + | |
| 208 | + | |
| 209 | + if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseMove) | |
| 210 | + { | |
| 211 | + event->accept(); | |
| 212 | + | |
| 213 | + QMouseEvent *mouseEvent = (QMouseEvent*)event; | |
| 214 | + | |
| 215 | + if (event->type() == QEvent::MouseButtonPress) | |
| 216 | + { | |
| 217 | + | |
| 218 | + if (mouseEvent->button() == Qt::LeftButton) { | |
| 219 | + if (!drawingRect) | |
| 220 | + { | |
| 221 | + drawingRect = true; | |
| 222 | + rectOrigin = mouseEvent->pos(); | |
| 223 | + return true; | |
| 224 | + } | |
| 225 | + else | |
| 226 | + { | |
| 227 | + drawingRect = false; | |
| 228 | + | |
| 229 | + rects.append(QRectF(rectOrigin, mouseEvent->pos())); | |
| 230 | + rects.last() = rects.last().normalized(); | |
| 231 | + // If no labels were provided, we store everything as anonymous rectangles | |
| 232 | + if (promptKeys.empty()) | |
| 233 | + rectLabels.append("rects"); | |
| 234 | + // otherwise, prompt the user to select a label | |
| 235 | + else | |
| 236 | + { | |
| 237 | + // get a label from the user | |
| 238 | + bool ok = false; | |
| 239 | + | |
| 240 | + // Don't intercept events while the sub-dialog is up (if we take the events, then it will not work correctly) | |
| 241 | + disableAccept = true; | |
| 242 | + QString res = QInputDialog::getItem(this, "Select a label", "", promptKeys, next_idx, false, &ok); | |
| 243 | + | |
| 244 | + disableAccept = false; | |
| 245 | + if (ok) { | |
| 246 | + rectLabels.append(res); | |
| 247 | + for (int i=0; i < promptKeys.size(); i++) | |
| 248 | + { | |
| 249 | + if (res == promptKeys[i]) { | |
| 250 | + next_idx = (i + 1) % promptKeys.size(); | |
| 251 | + break; | |
| 252 | + } | |
| 253 | + } | |
| 254 | + } | |
| 255 | + else { | |
| 256 | + rects.removeLast(); | |
| 257 | + } | |
| 258 | + } | |
| 259 | + } | |
| 260 | + } | |
| 261 | + // rclick -- reset state if drawing, remove last rect if done | |
| 262 | + else if (mouseEvent->button() == Qt::RightButton && (!rects.isEmpty() || drawingRect)) | |
| 263 | + { | |
| 264 | + if(drawingRect) | |
| 265 | + drawingRect = false; | |
| 266 | + else | |
| 267 | + { | |
| 268 | + rects.removeLast(); | |
| 269 | + rectLabels.removeLast(); | |
| 270 | + } | |
| 271 | + } | |
| 272 | + } | |
| 273 | + else | |
| 274 | + currentEnd = mouseEvent->pos(); | |
| 275 | + QPixmap pixmapBuffer = pixmap; | |
| 276 | + | |
| 277 | + QPainter painter(&pixmapBuffer); | |
| 278 | + painter.setPen(Qt::red); | |
| 279 | + | |
| 280 | + painter.drawRects(rects); | |
| 281 | + | |
| 282 | + if (drawingRect) | |
| 283 | + { | |
| 284 | + currentRect = QRectF(rectOrigin, currentEnd); | |
| 285 | + painter.setPen(Qt::green); | |
| 286 | + painter.drawRect(currentRect); | |
| 287 | + } | |
| 288 | + | |
| 289 | + setPixmap(pixmapBuffer); | |
| 290 | + | |
| 291 | + return true; | |
| 292 | + } else { | |
| 293 | + if (event->type() == QEvent::KeyPress) | |
| 294 | + { | |
| 295 | + QKeyEvent * kevent = (QKeyEvent *) event; | |
| 296 | + if (kevent->key() == Qt::Key_Enter || kevent->key() == Qt::Key_Return) { | |
| 297 | + event->accept(); | |
| 298 | + return true; | |
| 299 | + } | |
| 300 | + } | |
| 301 | + return DisplayWindow::eventFilter(obj, event); | |
| 302 | + } | |
| 303 | + } | |
| 304 | + | |
| 305 | + | |
| 306 | + QList<QPointF> waitForKey() | |
| 307 | + { | |
| 308 | + | |
| 309 | + rects.clear(); | |
| 310 | + drawingRect = false; | |
| 311 | + disableAccept = false; | |
| 312 | + next_idx = 0; | |
| 313 | + DisplayWindow::waitForKey(); | |
| 314 | + | |
| 315 | + return QList<QPointF>(); | |
| 316 | + } | |
| 317 | + | |
| 318 | + void setKeys(const QStringList & keys) | |
| 319 | + { | |
| 320 | + promptKeys = keys; | |
| 321 | + } | |
| 322 | + | |
| 323 | + int next_idx; | |
| 324 | +private: | |
| 325 | + QStringList promptKeys; | |
| 326 | + | |
| 327 | +}; | |
| 328 | + | |
| 185 | 329 | class PointMarkingWindow : public DisplayWindow |
| 186 | 330 | { |
| 187 | 331 | bool eventFilter(QObject *obj, QEvent *event) |
| ... | ... | @@ -556,6 +700,87 @@ BR_REGISTER(Transform, ManualTransform) |
| 556 | 700 | |
| 557 | 701 | /*! |
| 558 | 702 | * \ingroup transforms |
| 703 | + * \brief Manual select rectangular regions on an image. | |
| 704 | + * Stores marked rectangles as anonymous rectangles, or if a set of labels is provided, prompt the user | |
| 705 | + * to select one of those labels after drawing each rectangle. | |
| 706 | + * \author Charles Otto \cite caotto | |
| 707 | + */ | |
| 708 | +class ManualRectsTransform : public ShowTransform | |
| 709 | +{ | |
| 710 | + Q_OBJECT | |
| 711 | + | |
| 712 | +public: | |
| 713 | + | |
| 714 | + Q_PROPERTY(QStringList labels READ get_labels WRITE set_labels RESET reset_labels STORED false) | |
| 715 | + BR_PROPERTY(QStringList, labels, QStringList()) | |
| 716 | + | |
| 717 | + void projectUpdate(const TemplateList &src, TemplateList &dst) | |
| 718 | + { | |
| 719 | + | |
| 720 | + dst = src; | |
| 721 | + | |
| 722 | + if (src.empty()) | |
| 723 | + return; | |
| 724 | + | |
| 725 | + for (int i = 0; i < dst.size(); i++) { | |
| 726 | + foreach(const cv::Mat &m, dst[i]) { | |
| 727 | + qImageBuffer = toQImage(m); | |
| 728 | + displayBuffer->convertFromImage(qImageBuffer); | |
| 729 | + | |
| 730 | + emit updateImage(displayBuffer->copy(displayBuffer->rect())); | |
| 731 | + | |
| 732 | + // Blocking wait for a key-press | |
| 733 | + if (this->waitInput) { | |
| 734 | + window->waitForKey(); | |
| 735 | + QVector<QRectF> rectSet = trueWindow->rects; | |
| 736 | + QList<QString> labelSet= trueWindow->rectLabels; | |
| 737 | + | |
| 738 | + for (int idx = 0; idx < rectSet.size(); idx++) | |
| 739 | + { | |
| 740 | + if (dst[i].file.contains(labelSet[idx])) | |
| 741 | + { | |
| 742 | + QVariant currentProp = dst[i].file.value(labelSet[idx]); | |
| 743 | + QList<QVariant> currentPropList; | |
| 744 | + | |
| 745 | + if (currentProp.canConvert<QList<QVariant> >() ) | |
| 746 | + { | |
| 747 | + currentPropList = currentProp.toList(); | |
| 748 | + } | |
| 749 | + else if (currentProp.canConvert<QRectF>()) | |
| 750 | + { | |
| 751 | + currentPropList.append(currentProp); | |
| 752 | + } | |
| 753 | + else | |
| 754 | + { | |
| 755 | + qFatal("Unknown type of property"); | |
| 756 | + } | |
| 757 | + | |
| 758 | + currentPropList.append(rectSet[idx]); | |
| 759 | + dst[i].file.set(labelSet[idx], QVariant::fromValue(currentPropList)); | |
| 760 | + } | |
| 761 | + else | |
| 762 | + { | |
| 763 | + dst[i].file.set(labelSet[idx], rectSet[idx]); | |
| 764 | + } | |
| 765 | + } | |
| 766 | + } | |
| 767 | + | |
| 768 | + } | |
| 769 | + } | |
| 770 | + } | |
| 771 | + RectMarkingWindow * trueWindow; | |
| 772 | + void init() | |
| 773 | + { | |
| 774 | + initActual<RectMarkingWindow>(); | |
| 775 | + trueWindow = dynamic_cast<RectMarkingWindow *> (this->window); | |
| 776 | + trueWindow->setKeys(this->keys); | |
| 777 | + } | |
| 778 | +}; | |
| 779 | + | |
| 780 | +BR_REGISTER(Transform, ManualRectsTransform) | |
| 781 | + | |
| 782 | +/*! | |
| 783 | + * \ingroup transforms | |
| 559 | 784 | * \brief Elicits metadata for templates in a pretty GUI |
| 560 | 785 | * \author Scott Klum \cite sklum |
| 561 | 786 | */ | ... | ... |
openbr/plugins/output.cpp
| ... | ... | @@ -268,7 +268,7 @@ class rrOutput : public MatrixOutput |
| 268 | 268 | |
| 269 | 269 | for (int i=0; i<queryFiles.size(); i++) { |
| 270 | 270 | QStringList files; |
| 271 | - if (simple) files.append(queryFiles[i]); | |
| 271 | + if (simple) files.append(queryFiles[i].fileName()); | |
| 272 | 272 | |
| 273 | 273 | typedef QPair<float,int> Pair; |
| 274 | 274 | foreach (const Pair &pair, Common::Sort(OpenCVUtils::matrixToVector<float>(data.row(i)), true, limit)) { |
| ... | ... | @@ -276,7 +276,7 @@ class rrOutput : public MatrixOutput |
| 276 | 276 | if (pair.first < threshold) break; |
| 277 | 277 | File target = targetFiles[pair.second]; |
| 278 | 278 | target.set("Score", QString::number(pair.first)); |
| 279 | - if (simple) files.append(target.baseName() + " " + QString::number(pair.first)); | |
| 279 | + if (simple) files.append(target.fileName() + " " + QString::number(pair.first)); | |
| 280 | 280 | else files.append(target.flat()); |
| 281 | 281 | } |
| 282 | 282 | } | ... | ... |
openbr/plugins/validate.cpp
| ... | ... | @@ -108,6 +108,7 @@ class CrossValidateTransform : public MetaTransform |
| 108 | 108 | // If we want to duplicate templates but use the same training data |
| 109 | 109 | // for all partitions (i.e. transforms.size() == 1), we need to |
| 110 | 110 | // restrict the partition |
| 111 | + | |
| 111 | 112 | int partition = src.file.get<int>("Partition", 0); |
| 112 | 113 | partition = (partition >= transforms.size()) ? 0 : partition; |
| 113 | 114 | transforms[partition]->project(src, dst); | ... | ... |