00001
00005 #include <Qtcv.h>
00006 #include <Global.h>
00007
00008 #include <QtGui>
00009
00010 class QPixmap;
00011 class QKeySequence;
00012 class QMouseEvent;
00013 class QTime;
00014
00015 #define PAINT_BUTTON_TEXT "Set Corner"
00016
00017
00018 UserInterface::UserInterface()
00019 {
00020 QWidget *widget = new QWidget;
00021 setCentralWidget(widget);
00022
00023
00024 aboutText = new QString(tr(
00025 "<p><b>Recognizing and Drawing Faces with a Humanoid Robot</b> was a "
00026 "student project from AIS at the University of Freiburg in winter term 2010/11.</p>"
00027 "For detailed information, see manual."
00028 "<p><b>Authors:</b> <br/>"
00029 "Ina Baumgarten, Nikolaus Mayer, Niklas Meinzer, Christian Schilling, Julian Schmid, Richard Schneider, Fabian Wenzelmann</p>"));
00030
00031
00032 manualText = new QString(tr(
00033 "Taking the pen<br/>"
00034 "1. Put the pen standing on a surface in front of the PR2 (should be reachable by right gripper).<br/>"
00035 "2. Make sure that no other cylindrical objects are in the surrounding of the PR2.<br/>"
00036 "3. Make sure there is enough room around the PR2 (enough so that the arms can't hit anything).<br/>"
00037 "4. Press the \"Take Pen\" button on the gui on the basestation and make sure that the arm does not hit anything.<br/>"
00038 "5. Wait until the PR2 has taken the pen.<br/><br/>"
00039 "Taking a picture<br/>"
00040 "1. Press the \"Reset head position\" button<br/>"
00041 "2. Let a person stand in front of the cameras<br/>"
00042 "3. You should see a rectangle(s) around the found faces in the gui.<br/>"
00043 "4. Leftclick on the face you want to use. This configures the laser scanner and head.<br/>"
00044 "5. Wait for about 5 seconds, to give the laser scanner time to scan the face. The person in front of the camera must stand still during this period.<br/>"
00045 "6. Rightclick on the rectangle to take a picture and calculate a mask. This could take a while, so be patient.<br/>"
00046 "7. Check if the mask is ok (it should be black around the area of the face and white everywhere else), otherwise take another picture.<br/>"
00047 "8. Now you can press the button \"Compute edges\".<br/><br/>"
00048 "Extracting the face contours<br/>"
00049 "1. After you have taken a picture press the button \"Compute Edges\".<br/>"
00050 "2. Wait until it is done calculating different possibilities.<br/>"
00051 "3. Now it should open a gui which shows you different proposals. Click on the proposal you think is the best.<br/>"
00052 "4. Now you can play around with the parameters, this is a bit tricky. For further information have a look at the \"face_contour_detector\" on ros.org page.<br/>"
00053 "5. You can rate your result, this will improve the third proposal.<br/>"
00054 "6. Press \"Commit\" to send the result back to the main gui. Close the window if you want to discard the result.<br/><br/>"
00055 "Painting the picture<br/>"
00056 "1. Press the button \"Set Corner\"<br/>"
00057 "2. Now you have to take the gripper to the top left corner of your canvas, so that the pen is pressed onto the canvas. Then press the button.<br/>"
00058 "3. Now the same for the other corners (based on the instructions on the screen)<br/>"
00059 "4. Finally press the \"Draw Image\" button and wait until the robot has ended drawing.<br/>"
00060 ));
00061
00062 cameraImageLabel = new QLabel("<i>waiting for stereo image...</i>");
00063 cameraImageLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
00064 cameraImageLabel->setAlignment(Qt::AlignCenter);
00065 cameraImageLabel->setMinimumSize(STREAM_X, STREAM_Y);
00066 cameraImageLabel->setMaximumSize(STREAM_X, STREAM_Y);
00067
00068 photoImageLabel = new QLabel(tr("<i>portrait</i>"));
00069 photoImageLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
00070 photoImageLabel->setAlignment(Qt::AlignCenter);
00071 photoImageLabel->setMaximumSize(PORTRAIT_X, PORTRAIT_Y);
00072
00073 maskImageLabel = new QLabel(tr("<i>mask image</i>"));
00074 maskImageLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
00075 maskImageLabel->setAlignment(Qt::AlignCenter);
00076 maskImageLabel->setMaximumSize(PORTRAIT_X, PORTRAIT_Y);
00077
00078 penButton = new QPushButton(tr("Take Pen"));
00079 edgeButton = new QPushButton(tr("Compute Edges"));
00080 cornerButton = new QPushButton(tr(PAINT_BUTTON_TEXT));
00081 paintButton = new QPushButton(tr("Draw Image"));
00082 paintButton->setEnabled(false);
00083 headButton = new QPushButton(tr("Reset head position"));
00084 abortButton = new QPushButton(tr("Abort and restart"));
00085 edgeButton->setEnabled(false);
00086
00087 mirrorCBox = new QCheckBox(tr("mirror the pointcloud?"));
00088
00089 penGripperLog = new QTextEdit();
00090 penGripperLog->setReadOnly(true);
00091 penGripperLogStarted = false;
00092 contourDetectorLog = new QTextEdit();
00093 contourDetectorLog->setReadOnly(true);
00094 contourDetectorLogStarted = false;
00095 painterLog = new QTextEdit();
00096 painterLog->setReadOnly(true);
00097 painterLogStarted = false;
00098
00099 penLabel = new QLabel(tr("Pen Gripper"));
00100 edgeLabel = new QLabel(tr("Contour Extractor"));
00101 paintLabel = new QLabel(tr("Painter"));
00102
00103 QHBoxLayout *layoutImages = new QHBoxLayout();
00104 layoutImages->addWidget(photoImageLabel);
00105 layoutImages->addWidget(cameraImageLabel);
00106 layoutImages->addWidget(maskImageLabel);
00107
00108 QHBoxLayout *layoutControls = new QHBoxLayout();
00109 layoutControls->addStretch(1);
00110 layoutControls->addWidget(headButton);
00111 layoutControls->addSpacing(50);
00112 layoutControls->addWidget(mirrorCBox);
00113 layoutControls->addSpacing(50);
00114 layoutControls->addWidget(abortButton);
00115 layoutControls->addStretch(1);
00116
00117 QVBoxLayout *layoutLeft = new QVBoxLayout();
00118 QHBoxLayout *miniLeft = new QHBoxLayout();
00119 miniLeft->addWidget(penLabel);
00120 miniLeft->addWidget(penButton);
00121 layoutLeft->addLayout(miniLeft);
00122 layoutLeft->addWidget(penGripperLog);
00123
00124 QVBoxLayout *layoutCenter = new QVBoxLayout();
00125 QHBoxLayout *miniCenter = new QHBoxLayout();
00126 miniCenter->addWidget(edgeLabel);
00127 miniCenter->addWidget(edgeButton);
00128 layoutCenter->addLayout(miniCenter);
00129 layoutCenter->addWidget(contourDetectorLog);
00130
00131 QVBoxLayout *layoutRight = new QVBoxLayout();
00132 QHBoxLayout *miniRight = new QHBoxLayout();
00133 miniRight->addWidget(paintLabel);
00134 miniRight->addWidget(cornerButton);
00135 miniRight->addWidget(paintButton);
00136 layoutRight->addLayout(miniRight);
00137 layoutRight->addWidget(painterLog);
00138
00139 QHBoxLayout *layoutLog = new QHBoxLayout();
00140 layoutLog->addLayout(layoutLeft);
00141 layoutLog->addLayout(layoutCenter);
00142 layoutLog->addLayout(layoutRight);
00143
00144 QVBoxLayout *layoutMain = new QVBoxLayout();
00145 layoutMain->addLayout(layoutImages);
00146 layoutMain->addLayout(layoutControls);
00147 layoutMain->addLayout(layoutLog);
00148
00149 widget->setLayout(layoutMain);
00150
00151 CreateActions();
00152 CreateMenus();
00153
00154 statusLabel = new QLabel();
00155 statusBar()->insertWidget(0, statusLabel, 0);
00156 QString message = tr("Application started. For manual instructions, use the menu.");
00157 statusBar()->showMessage(message);
00158 infoLabel = new QLabel(tr("<i>To take a photo: Left click a face to adjust the head and laser and then right click to take a photo.</i>"));
00159 infoLabel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
00160 infoLabel->setAlignment(Qt::AlignRight);
00161 statusBar()->addPermanentWidget(infoLabel, 0);
00162
00163 connect(mirrorCBox, SIGNAL(stateChanged(int)), this, SLOT(ChangeMirror(int)));
00164 connect(penButton, SIGNAL(clicked()), this, SLOT(PenBClick()));
00165 connect(edgeButton, SIGNAL(clicked()), this, SLOT(EdgeBClick()));
00166 connect(paintButton, SIGNAL(clicked()), this, SLOT(PaintBClick()));
00167 connect(cornerButton, SIGNAL(clicked()), this, SLOT(CornerBClick()));
00168 connect(headButton, SIGNAL(clicked()), this, SLOT(HeadBClick()));
00169 connect(abortButton, SIGNAL(clicked()), this, SLOT(AbortBClick()));
00170
00171 setWindowTitle(tr("Recognizing and Drawing Faces with a Humanoid Robot"));
00172 setMinimumSize(STREAM_X + 2 * PORTRAIT_X - 100, STREAM_Y + 230);
00173
00174 setWindowState(windowState() ^ Qt::WindowMaximized);
00175
00176 cameraImageLabel->setMouseTracking(true);
00177 cameraImageLabel->installEventFilter(this);
00178
00179 drawingAvailable = false;
00180 }
00181
00182
00183 void UserInterface::SetLeftImage(QImage qimage)
00184 {
00185 if(cameraImageLabel->isVisible())
00186 cameraImageLabel->setPixmap(QPixmap::fromImage(qimage));
00187 }
00188
00189
00190 void UserInterface::SetCenterImage(QImage qimage)
00191 {
00192 if(photoImageLabel->isVisible())
00193 photoImageLabel->setPixmap(QPixmap::fromImage(qimage));
00194 }
00195
00196
00197 void UserInterface::SetRightImage(QImage qimage)
00198 {
00199 if(maskImageLabel->isVisible())
00200 maskImageLabel->setPixmap(QPixmap::fromImage(qimage));
00201 }
00202
00203
00204 void UserInterface::SetStatus(QString message)
00205 {
00206 statusBar()->showMessage(message);
00207 }
00208
00209 void UserInterface::SetInfo(QString message)
00210 {
00211 infoLabel->setText(message);
00212 }
00213
00214
00215 void UserInterface::ChangeMirror(int state)
00216 {
00217 Q_EMIT mirror();
00218
00219 QString message;
00220 if (state == 0)
00221 message = tr("Deactivated mirroring the point cloud.");
00222 else
00223 message = tr("Activated mirroring the point cloud.");
00224 statusBar()->showMessage(message);
00225 }
00226
00227
00228 bool UserInterface::eventFilter(QObject *obj, QEvent *event)
00229 {
00230 if (obj == cameraImageLabel)
00231 {
00232 if (event->type() == QEvent::MouseMove)
00233 {
00234 QPointF p = (static_cast<QMouseEvent *>(event))->pos();
00235 p = p.toPoint();
00236
00237 Q_EMIT sendMouseEvent((int)p.x(), (int)p.y(), 0);
00238 }
00239 else if (event->type() == QEvent::MouseButtonPress)
00240 {
00241 QPointF p = (static_cast<QMouseEvent *>(event))->pos();
00242 p = p.toPoint();
00243
00244 if((static_cast<QMouseEvent *>(event))->button() == Qt::LeftButton) {
00245 Q_EMIT sendMouseEvent((int)p.x(), (int)p.y(), 1);
00246 } else if((static_cast<QMouseEvent *>(event))->button() == Qt::RightButton) {
00247 Q_EMIT sendMouseEvent((int)p.x(), (int)p.y(), 2);
00248 }
00249 }
00250 }
00251
00252 return QMainWindow::eventFilter(obj, event);
00253 }
00254
00255
00256 void UserInterface::PenBClick()
00257 {
00258 SetStatus(QString("Sending signal to pen gripper."));
00259
00260 Q_EMIT penButtonClick();
00261 }
00262
00263 void UserInterface::EdgeBClick()
00264 {
00265 SetStatus(QString("Sending signal to contour detector."));
00266
00267 Q_EMIT edgeButtonClick();
00268 }
00269
00270
00271 void UserInterface::CornerBClick()
00272 {
00273 SetStatus(QString("Sending signal to painter."));
00274
00275 Q_EMIT cornerButtonClick();
00276 }
00277
00278 void UserInterface::PaintBClick()
00279 {
00280 SetStatus(QString("Sending signal to painter."));
00281
00282 Q_EMIT paintButtonClick();
00283 }
00284
00285
00286 void UserInterface::HeadBClick()
00287 {
00288 SetStatus(QString("Resetting the head position."));
00289
00290 Q_EMIT headButtonClick();
00291 }
00292
00293
00294 void UserInterface::AbortBClick()
00295 {
00296 penButton->setEnabled(true);
00297
00298
00299 paintButton->setEnabled(false);
00300
00301 Q_EMIT abortButtonClick();
00302 }
00303
00304
00305 void UserInterface::ActivateButton(int buttonID)
00306 {
00307 switch (buttonID)
00308 {
00309 case 1:
00310 penButton->setEnabled(false);
00311 case 2:
00312 edgeButton->setEnabled(true);
00313 break;
00314 case 3:
00315 drawingAvailable = true;
00316
00317
00318
00319 break;
00320 case 4:
00321
00322 paintButton->setEnabled(drawingAvailable);
00323 break;
00324 default:
00325 SetStatus(QString("ERROR: Wrong parameter!"));
00326 break;
00327 }
00328 }
00329
00330 void UserInterface::loadEdgeImageButton() {
00331 QString filename = QFileDialog::getOpenFileName(this, "Load Contour Image from File", "", tr("Images (*.png *.xpm *.jpg);;All Files (*)"));
00332 if(!filename.isEmpty()) Q_EMIT loadEdgeImage(qPrintable(filename));
00333 }
00334 void UserInterface::loadPhotoButton() {
00335 QString filename = QFileDialog::getOpenFileName(this, "Load Photo from File", "", tr("Images (*.png *.xpm *.jpg);;All Files (*)"));
00336 QString filename2 = QFileDialog::getOpenFileName(this, "Load Mask from File", "", tr("Images (*.png *.xpm *.jpg);;All Files (*)"));
00337 if(!filename2.isEmpty() && !filename.isEmpty())
00338 Q_EMIT loadPhoto(qPrintable(filename), qPrintable(filename2));
00339 }
00340
00341 void UserInterface::About()
00342 {
00343 QMessageBox::about(this, tr("About"), *aboutText);
00344 }
00345
00346
00347 void UserInterface::Manual()
00348 {
00349 QWidget* qmb = new QWidget();
00350 QVBoxLayout* l = new QVBoxLayout();
00351 QTextEdit* t = new QTextEdit();
00352 t->setText(*manualText);
00353 l->addWidget(t);
00354 qmb->setLayout(l);
00355 qmb->setWindowTitle(tr("Manual"));
00356 qmb->setMinimumWidth(600);
00357 qmb->setMinimumHeight(480);
00358 QRect desk( QApplication::desktop()->availableGeometry( ) );
00359 qmb->move( (desk.width() - 600) / 2, (desk.height() - 480) / 2 );
00360 qmb->show();
00361 }
00362
00363
00364 void UserInterface::CreateActions()
00365 {
00366 exitAct = new QAction(tr("E&xit"), this);
00367 exitAct->setShortcuts(QKeySequence::Close);
00368 exitAct->setStatusTip(tr("Exit the application."));
00369 connect(exitAct, SIGNAL(triggered()), this, SLOT(close()));
00370
00371 loadEdgeAct = new QAction(tr("&Open Edge Image..."), this);
00372 loadEdgeAct->setShortcut(QString("Strg+E"));
00373 loadEdgeAct->setStatusTip(tr("Load edge image"));
00374 connect(loadEdgeAct, SIGNAL(triggered()), this, SLOT(loadEdgeImageButton()));
00375
00376 loadPhotoAct = new QAction(tr("&Open Photo and Mask..."), this);
00377 loadPhotoAct->setShortcuts(QKeySequence::Open);
00378 loadPhotoAct->setStatusTip(tr("Load Photo and Mask"));
00379 connect(loadPhotoAct, SIGNAL(triggered()), this, SLOT(loadPhotoButton()));
00380
00381 manualAct = new QAction(tr("&Manual"), this);
00382 manualAct->setShortcuts(QKeySequence::HelpContents);
00383 manualAct->setStatusTip(tr("Show the manual."));
00384 connect(manualAct, SIGNAL(triggered()), this, SLOT(Manual()));
00385
00386 aboutAct = new QAction(tr("&About"), this);
00387 aboutAct->setShortcuts(QKeySequence::WhatsThis);
00388 aboutAct->setStatusTip(tr("Show information about this program."));
00389 connect(aboutAct, SIGNAL(triggered()), this, SLOT(About()));
00390 }
00391
00392
00393 void UserInterface::CreateMenus()
00394 {
00395 fileMenu = menuBar()->addMenu(tr("&File"));
00396 fileMenu->addAction(loadPhotoAct);
00397 fileMenu->addAction(loadEdgeAct);
00398 fileMenu->addAction(exitAct);
00399
00400 helpMenu = menuBar()->addMenu(tr("&Help"));
00401 helpMenu->addAction(manualAct);
00402 helpMenu->addAction(aboutAct);
00403 }
00404
00405
00406 void UserInterface::UpdateStatusMessage(int ID, QString message)
00407 {
00408 QString timePrefix = QString("[").append(QString(QTime::currentTime().toString(QString("mm:ss"))).append(QString("] ")));
00409 message = timePrefix.append(message).append(QString("\n"));
00410
00411 switch (ID)
00412 {
00413 case 1: {
00414 if (!penGripperLogStarted)
00415 {
00416 penGripperLog->setHtml(penGripperLog->toPlainText().append(message));
00417 penGripperLogStarted = true;
00418 }
00419 else
00420 penGripperLog->setHtml(penGripperLog->toHtml().append(message));
00421 QTextCursor c1 = penGripperLog->textCursor();
00422 c1.movePosition(QTextCursor::End);
00423 penGripperLog->setTextCursor(c1);
00424 break;
00425 }
00426 case 2: {
00427 if (!contourDetectorLogStarted)
00428 {
00429 contourDetectorLog->setHtml(contourDetectorLog->toPlainText().append(message));
00430 contourDetectorLogStarted = true;
00431 }
00432 else
00433 contourDetectorLog->setHtml(contourDetectorLog->toHtml().append(message));
00434 QTextCursor c2 = contourDetectorLog->textCursor();
00435 c2.movePosition(QTextCursor::End);
00436 contourDetectorLog->setTextCursor(c2);
00437 break;
00438 }
00439 case 3: {
00440 if (!painterLogStarted)
00441 {
00442 painterLog->setHtml(painterLog->toPlainText().append(message));
00443 painterLogStarted = true;
00444 }
00445 else
00446 painterLog->setHtml(painterLog->toHtml().append(message));
00447 QTextCursor c3 = painterLog->textCursor();
00448 c3.movePosition(QTextCursor::End);
00449 painterLog->setTextCursor(c3);
00450 break;
00451 }
00452 default: {
00453 SetStatus("Error: UpdateStatusMessage() called with wrong ID");
00454 }
00455 }
00456 }