Commit 8058f81d2176b0281b4c2fc4094f6020e5211ded
1 parent
8f957ce1
Added ElicitTransform
Showing
3 changed files
with
185 additions
and
6 deletions
openbr/plugins/gui.cpp
| ... | ... | @@ -5,6 +5,11 @@ |
| 5 | 5 | #include <QMutex> |
| 6 | 6 | #include <QMouseEvent> |
| 7 | 7 | #include <QPainter> |
| 8 | +#include <QMainWindow> | |
| 9 | +#include <QPushButton> | |
| 10 | +#include <QHBoxLayout> | |
| 11 | +#include <QFormLayout> | |
| 12 | +#include <QLineEdit> | |
| 8 | 13 | |
| 9 | 14 | #include <opencv2/imgproc/imgproc.hpp> |
| 10 | 15 | #include "openbr_internal.h" |
| ... | ... | @@ -188,6 +193,85 @@ private: |
| 188 | 193 | |
| 189 | 194 | }; |
| 190 | 195 | |
| 196 | +class DisplayGUI : public QMainWindow | |
| 197 | +{ | |
| 198 | + Q_OBJECT | |
| 199 | + | |
| 200 | +public: | |
| 201 | + | |
| 202 | + DisplayGUI(QWidget * parent = NULL) : QMainWindow(parent) | |
| 203 | + { | |
| 204 | + centralWidget = new QWidget(); | |
| 205 | + layout = new QHBoxLayout(); | |
| 206 | + inputLayout = new QVBoxLayout(); | |
| 207 | + | |
| 208 | + button.setText("Set Template Metadata"); | |
| 209 | + | |
| 210 | + layout->addWidget(&label); | |
| 211 | + | |
| 212 | + inputLayout->addWidget(&button); | |
| 213 | + layout->addLayout(inputLayout); | |
| 214 | + | |
| 215 | + centralWidget->setLayout(layout); | |
| 216 | + | |
| 217 | + setCentralWidget(centralWidget); | |
| 218 | + | |
| 219 | + connect(&button, SIGNAL(clicked()), this, SLOT(buttonPressed())); | |
| 220 | + } | |
| 221 | + | |
| 222 | +public slots: | |
| 223 | + void showImage(const QPixmap & input) | |
| 224 | + { | |
| 225 | + pixmap = input; | |
| 226 | + foreach(const QString& label, keys) { | |
| 227 | + QLineEdit *edit = new QLineEdit; | |
| 228 | + fields.append(edit); | |
| 229 | + QFormLayout *form = new QFormLayout; | |
| 230 | + form->addRow(label, edit); | |
| 231 | + inputLayout->addLayout(form); | |
| 232 | + } | |
| 233 | + | |
| 234 | + show(); | |
| 235 | + label.setPixmap(pixmap); | |
| 236 | + label.setFixedSize(input.size()); | |
| 237 | + } | |
| 238 | + | |
| 239 | + QStringList waitForButtonPress() | |
| 240 | + { | |
| 241 | + QMutexLocker locker(&lock); | |
| 242 | + wait.wait(&lock); | |
| 243 | + | |
| 244 | + QStringList values; | |
| 245 | + for(int i = 0; i<fields.size(); i++) values.append(fields.at(i)->text()); | |
| 246 | + return values; | |
| 247 | + } | |
| 248 | + | |
| 249 | +public slots: | |
| 250 | + | |
| 251 | + void buttonPressed() | |
| 252 | + { | |
| 253 | + wait.wakeAll(); | |
| 254 | + } | |
| 255 | + | |
| 256 | + void setKeys(const QStringList& k) | |
| 257 | + { | |
| 258 | + keys = k; | |
| 259 | + } | |
| 260 | + | |
| 261 | +private: | |
| 262 | + | |
| 263 | + QWidget *centralWidget; | |
| 264 | + QStringList keys; | |
| 265 | + QList<QLineEdit*> fields; | |
| 266 | + QPushButton button; | |
| 267 | + QMutex lock; | |
| 268 | + QWaitCondition wait; | |
| 269 | + QPixmap pixmap; | |
| 270 | + QLabel label; | |
| 271 | + QHBoxLayout *layout; | |
| 272 | + QVBoxLayout *inputLayout; | |
| 273 | + | |
| 274 | +}; | |
| 191 | 275 | |
| 192 | 276 | // I want a template class that doesn't look like a template class |
| 193 | 277 | class NominalCreation |
| ... | ... | @@ -298,7 +382,7 @@ public: |
| 298 | 382 | { |
| 299 | 383 | dst = src; |
| 300 | 384 | |
| 301 | - if (src.empty() || !Globals->useGui) | |
| 385 | + if (src.empty()) | |
| 302 | 386 | return; |
| 303 | 387 | |
| 304 | 388 | foreach (const Template & t, src) { |
| ... | ... | @@ -429,6 +513,104 @@ public: |
| 429 | 513 | |
| 430 | 514 | BR_REGISTER(Transform, ManualTransform) |
| 431 | 515 | |
| 516 | +/*! | |
| 517 | + * \ingroup transforms | |
| 518 | + * \brief Elicits metadata for templates in a pretty GUI | |
| 519 | + * \author Scott Klum \cite sklum | |
| 520 | + */ | |
| 521 | +class ElicitTransform : public TimeVaryingTransform | |
| 522 | +{ | |
| 523 | + Q_PROPERTY(QStringList keys READ get_keys WRITE set_keys RESET reset_keys STORED false) | |
| 524 | + BR_PROPERTY(QStringList, keys, QStringList()) | |
| 525 | + | |
| 526 | + Q_OBJECT | |
| 527 | + | |
| 528 | + MainThreadCreator creator; | |
| 529 | + DisplayGUI *gui; | |
| 530 | + QImage qImageBuffer; | |
| 531 | + QPixmap *displayBuffer; | |
| 532 | + | |
| 533 | +public: | |
| 534 | + ElicitTransform() : TimeVaryingTransform(false, false) | |
| 535 | + { | |
| 536 | + displayBuffer = NULL; | |
| 537 | + gui = NULL; | |
| 538 | + } | |
| 539 | + | |
| 540 | + ~ElicitTransform() | |
| 541 | + { | |
| 542 | + delete displayBuffer; | |
| 543 | + delete gui; | |
| 544 | + } | |
| 545 | + | |
| 546 | + void train(const TemplateList &data) { (void) data; } | |
| 547 | + | |
| 548 | + void project(const TemplateList &src, TemplateList &dst) const | |
| 549 | + { | |
| 550 | + Transform * non_const = (ShowTransform *) this; | |
| 551 | + non_const->projectUpdate(src,dst); | |
| 552 | + } | |
| 553 | + | |
| 554 | + void projectUpdate(const TemplateList &src, TemplateList &dst) | |
| 555 | + { | |
| 556 | + dst = src; | |
| 557 | + | |
| 558 | + if (src.empty()) return; | |
| 559 | + | |
| 560 | + for (int i = 0; i < dst.size(); i++) { | |
| 561 | + foreach(const cv::Mat &m, dst[i]) { | |
| 562 | + qImageBuffer = toQImage(m); | |
| 563 | + displayBuffer->convertFromImage(qImageBuffer); | |
| 564 | + | |
| 565 | + emit updateImage(displayBuffer->copy(displayBuffer->rect())); | |
| 566 | + | |
| 567 | + QStringList metadata = gui->waitForButtonPress(); | |
| 568 | + for(int j = 0; j < keys.size(); j++) dst[i].file.set(keys[j],metadata[j]); | |
| 569 | + } | |
| 570 | + } | |
| 571 | + } | |
| 572 | + | |
| 573 | + void finalize(TemplateList & output) | |
| 574 | + { | |
| 575 | + (void) output; | |
| 576 | + emit hideWindow(); | |
| 577 | + } | |
| 578 | + | |
| 579 | + void init() | |
| 580 | + { | |
| 581 | + initActual<DisplayGUI>(); | |
| 582 | + } | |
| 583 | + | |
| 584 | + template<typename GUIType> | |
| 585 | + void initActual() | |
| 586 | + { | |
| 587 | + if (!Globals->useGui) | |
| 588 | + return; | |
| 589 | + | |
| 590 | + TimeVaryingTransform::init(); | |
| 591 | + | |
| 592 | + if (displayBuffer) | |
| 593 | + delete displayBuffer; | |
| 594 | + | |
| 595 | + displayBuffer = new QPixmap(); | |
| 596 | + | |
| 597 | + if (gui) | |
| 598 | + delete gui; | |
| 599 | + | |
| 600 | + gui = creator.getItem<GUIType>(); | |
| 601 | + gui->setKeys(keys); | |
| 602 | + // Connect our signals to the window's slots | |
| 603 | + connect(this, SIGNAL(updateImage(QPixmap)), gui,SLOT(showImage(QPixmap))); | |
| 604 | + connect(this, SIGNAL(hideWindow()), gui, SLOT(hide())); | |
| 605 | + } | |
| 606 | + | |
| 607 | +signals: | |
| 608 | + | |
| 609 | + void updateImage(const QPixmap & input); | |
| 610 | + void hideWindow(); | |
| 611 | + | |
| 612 | +}; | |
| 613 | +BR_REGISTER(Transform, ElicitTransform) | |
| 432 | 614 | |
| 433 | 615 | /*! |
| 434 | 616 | * \ingroup transforms | ... | ... |
openbr/plugins/misc.cpp
| ... | ... | @@ -332,11 +332,9 @@ class AnonymizeTransform : public UntrainableMetaTransform |
| 332 | 332 | |
| 333 | 333 | BR_REGISTER(Transform, AnonymizeTransform) |
| 334 | 334 | |
| 335 | -// TODO: Use a global Mutex to prevent concurrent reads from stdin | |
| 336 | -#if 0 | |
| 337 | 335 | /*! |
| 338 | 336 | * \ingroup transforms |
| 339 | - * \brief Name a point | |
| 337 | + * \brief Name a metadata value | |
| 340 | 338 | * \author Scott Klum \cite sklum |
| 341 | 339 | */ |
| 342 | 340 | class ElicitMetadataTransform : public UntrainableMetaTransform |
| ... | ... | @@ -381,7 +379,6 @@ class ElicitMetadataTransform : public UntrainableMetaTransform |
| 381 | 379 | }; |
| 382 | 380 | |
| 383 | 381 | BR_REGISTER(Transform, ElicitMetadataTransform) |
| 384 | -#endif | |
| 385 | 382 | |
| 386 | 383 | /*! |
| 387 | 384 | * \ingroup transforms | ... | ... |