Commit 4c595c32fc754cad409a292dd0eb97095cf57483
1 parent
40b8933d
Add a transform for manually marking rectangles
Showing
1 changed file
with
225 additions
and
0 deletions
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 | */ | ... | ... |