1 //IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 2 3 // By downloading, copying, installing or using the software you agree to this license. 4 // If you do not agree to this license, do not download, install, 5 // copy or use the software. 6 7 8 // License Agreement 9 // For Open Source Computer Vision Library 10 11 //Copyright (C) 2000-2008, Intel Corporation, all rights reserved. 12 //Copyright (C) 2008-2010, Willow Garage Inc., all rights reserved. 13 //Third party copyrights are property of their respective owners. 14 15 //Redistribution and use in source and binary forms, with or without modification, 16 //are permitted provided that the following conditions are met: 17 18 // * Redistribution's of source code must retain the above copyright notice, 19 // this list of conditions and the following disclaimer. 20 21 // * Redistribution's in binary form must reproduce the above copyright notice, 22 // this list of conditions and the following disclaimer in the documentation 23 // and/or other materials provided with the distribution. 24 25 // * The name of the copyright holders may not be used to endorse or promote products 26 // derived from this software without specific prior written permission. 27 28 //This software is provided by the copyright holders and contributors "as is" and 29 //any express or implied warranties, including, but not limited to, the implied 30 //warranties of merchantability and fitness for a particular purpose are disclaimed. 31 //In no event shall the Intel Corporation or contributors be liable for any direct, 32 //indirect, incidental, special, exemplary, or consequential damages 33 //(including, but not limited to, procurement of substitute goods or services; 34 //loss of use, data, or profits; or business interruption) however caused 35 //and on any theory of liability, whether in contract, strict liability, 36 //or tort (including negligence or otherwise) arising in any way out of 37 //the use of this software, even if advised of the possibility of such damage. 38 39 //--------------------Google Code 2010 -- Yannick Verdie--------------------// 40 41 #include "precomp.hpp" 42 43 #if defined(HAVE_QT) 44 45 #include <memory> 46 47 #include <window_QT.h> 48 49 #include <math.h> 50 51 #ifdef _WIN32 52 #include <windows.h> 53 #else 54 #include <unistd.h> 55 #endif 56 57 #ifdef HAVE_QT_OPENGL 58 #ifdef Q_WS_X11 59 #include <GL/glx.h> 60 #endif 61 #endif 62 63 64 //Static and global first 65 static GuiReceiver *guiMainThread = NULL; 66 static int parameterSystemC = 1; 67 static char* parameterSystemV[] = {(char*)""}; 68 static bool multiThreads = false; 69 static int last_key = -1; 70 QWaitCondition key_pressed; 71 QMutex mutexKey; 72 static const unsigned int threshold_zoom_img_region = 30; 73 //the minimum zoom value to start displaying the values in the grid 74 //that is also the number of pixel per grid 75 76 static CvWinProperties* global_control_panel = NULL; 77 //end static and global 78 79 // Declaration 80 Qt::ConnectionType autoBlockingConnection(); 81 82 // Implementation - this allows us to do blocking whilst automatically selecting the right 83 // behaviour for in-thread and out-of-thread launches of cv windows. Qt strangely doesn't 84 // cater for this, but does for strictly queued connections. 85 Qt::ConnectionType autoBlockingConnection() { 86 return (QThread::currentThread() != QApplication::instance()->thread()) 87 ? Qt::BlockingQueuedConnection 88 : Qt::DirectConnection; 89 } 90 91 CV_IMPL CvFont cvFontQt(const char* nameFont, int pointSize,CvScalar color,int weight,int style, int spacing) 92 { 93 /* 94 //nameFont <- only Qt 95 //CvScalar color <- only Qt (blue_component, green_component, red\_component[, alpha_component]) 96 int font_face;//<- style in Qt 97 const int* ascii; 98 const int* greek; 99 const int* cyrillic; 100 float hscale, vscale; 101 float shear; 102 int thickness;//<- weight in Qt 103 float dx;//spacing letter in Qt (0 default) in pixel 104 int line_type;//<- pointSize in Qt 105 */ 106 CvFont f = {nameFont,color,style,NULL,NULL,NULL,0,0,0,weight,spacing,pointSize}; 107 return f; 108 } 109 110 111 CV_IMPL void cvAddText(const CvArr* img, const char* text, CvPoint org, CvFont* font) 112 { 113 if (!guiMainThread) 114 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 115 116 QMetaObject::invokeMethod(guiMainThread, 117 "putText", 118 autoBlockingConnection(), 119 Q_ARG(void*, (void*) img), 120 Q_ARG(QString,QString::fromUtf8(text)), 121 Q_ARG(QPoint, QPoint(org.x,org.y)), 122 Q_ARG(void*,(void*) font)); 123 } 124 125 126 double cvGetRatioWindow_QT(const char* name) 127 { 128 if (!guiMainThread) 129 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 130 131 double result = -1; 132 QMetaObject::invokeMethod(guiMainThread, 133 "getRatioWindow", 134 autoBlockingConnection(), 135 Q_RETURN_ARG(double, result), 136 Q_ARG(QString, QString(name))); 137 138 return result; 139 } 140 141 142 void cvSetRatioWindow_QT(const char* name,double prop_value) 143 { 144 145 if (!guiMainThread) 146 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 147 148 QMetaObject::invokeMethod(guiMainThread, 149 "setRatioWindow", 150 autoBlockingConnection(), 151 Q_ARG(QString, QString(name)), 152 Q_ARG(double, prop_value)); 153 } 154 155 156 double cvGetPropWindow_QT(const char* name) 157 { 158 if (!guiMainThread) 159 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 160 161 double result = -1; 162 QMetaObject::invokeMethod(guiMainThread, 163 "getPropWindow", 164 autoBlockingConnection(), 165 Q_RETURN_ARG(double, result), 166 Q_ARG(QString, QString(name))); 167 168 return result; 169 } 170 171 172 void cvSetPropWindow_QT(const char* name,double prop_value) 173 { 174 if (!guiMainThread) 175 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 176 177 QMetaObject::invokeMethod(guiMainThread, 178 "setPropWindow", 179 autoBlockingConnection(), 180 Q_ARG(QString, QString(name)), 181 Q_ARG(double, prop_value)); 182 } 183 184 void cv::setWindowTitle(const String& winname, const String& title) 185 { 186 if (!guiMainThread) 187 CV_Error(Error::StsNullPtr, "NULL guiReceiver (please create a window)"); 188 189 QMetaObject::invokeMethod(guiMainThread, 190 "setWindowTitle", 191 autoBlockingConnection(), 192 Q_ARG(QString, QString(winname.c_str())), 193 Q_ARG(QString, QString(title.c_str()))); 194 } 195 196 197 void cvSetModeWindow_QT(const char* name, double prop_value) 198 { 199 if (!guiMainThread) 200 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 201 202 QMetaObject::invokeMethod(guiMainThread, 203 "toggleFullScreen", 204 autoBlockingConnection(), 205 Q_ARG(QString, QString(name)), 206 Q_ARG(double, prop_value)); 207 } 208 209 210 double cvGetModeWindow_QT(const char* name) 211 { 212 if (!guiMainThread) 213 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 214 215 double result = -1; 216 217 QMetaObject::invokeMethod(guiMainThread, 218 "isFullScreen", 219 autoBlockingConnection(), 220 Q_RETURN_ARG(double, result), 221 Q_ARG(QString, QString(name))); 222 223 return result; 224 } 225 226 227 CV_IMPL void cvDisplayOverlay(const char* name, const char* text, int delayms) 228 { 229 if (!guiMainThread) 230 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 231 232 QMetaObject::invokeMethod(guiMainThread, 233 "displayInfo", 234 autoBlockingConnection(), 235 Q_ARG(QString, QString(name)), 236 Q_ARG(QString, QString(text)), 237 Q_ARG(int, delayms)); 238 } 239 240 241 CV_IMPL void cvSaveWindowParameters(const char* name) 242 { 243 if (!guiMainThread) 244 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 245 246 QMetaObject::invokeMethod(guiMainThread, 247 "saveWindowParameters", 248 autoBlockingConnection(), 249 Q_ARG(QString, QString(name))); 250 } 251 252 253 CV_IMPL void cvLoadWindowParameters(const char* name) 254 { 255 if (!guiMainThread) 256 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 257 258 QMetaObject::invokeMethod(guiMainThread, 259 "loadWindowParameters", 260 autoBlockingConnection(), 261 Q_ARG(QString, QString(name))); 262 } 263 264 265 CV_IMPL void cvDisplayStatusBar(const char* name, const char* text, int delayms) 266 { 267 if (!guiMainThread) 268 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 269 270 QMetaObject::invokeMethod(guiMainThread, 271 "displayStatusBar", 272 autoBlockingConnection(), 273 Q_ARG(QString, QString(name)), 274 Q_ARG(QString, QString(text)), 275 Q_ARG(int, delayms)); 276 } 277 278 279 CV_IMPL int cvWaitKey(int delay) 280 { 281 int result = -1; 282 283 if (!guiMainThread) 284 return result; 285 286 unsigned long delayms = delay <= 0 ? ULONG_MAX : delay; //in milliseconds 287 288 if (multiThreads) 289 { 290 mutexKey.lock(); 291 if (key_pressed.wait(&mutexKey, delayms)) //false if timeout 292 { 293 result = last_key; 294 } 295 last_key = -1; 296 mutexKey.unlock(); 297 } 298 else 299 { 300 //cannot use wait here because events will not be distributed before processEvents (the main eventLoop is broken) 301 //so I create a Thread for the QTimer 302 303 if (delay > 0) 304 guiMainThread->timer->start(delay); 305 306 //QMutex dummy; 307 308 while (!guiMainThread->bTimeOut) 309 { 310 qApp->processEvents(QEventLoop::AllEvents); 311 312 if (!guiMainThread)//when all the windows are deleted 313 return result; 314 315 mutexKey.lock(); 316 if (last_key != -1) 317 { 318 result = last_key; 319 last_key = -1; 320 guiMainThread->timer->stop(); 321 //printf("keypressed\n"); 322 } 323 mutexKey.unlock(); 324 325 if (result!=-1) 326 { 327 break; 328 } 329 else 330 { 331 /* 332 * //will not work, I broke the event loop !!!! 333 dummy.lock(); 334 QWaitCondition waitCondition; 335 waitCondition.wait(&dummy, 2); 336 */ 337 338 //to decrease CPU usage 339 //sleep 1 millisecond 340 #if defined WIN32 || defined _WIN32 || defined WIN64 || defined _WIN64 341 Sleep(1); 342 #else 343 usleep(1000); 344 #endif 345 } 346 } 347 348 guiMainThread->bTimeOut = false; 349 } 350 return result; 351 } 352 353 354 //Yannick Verdie 355 //This function is experimental and some functions (such as cvSet/getWindowProperty will not work) 356 //We recommend not using this function for now 357 CV_IMPL int cvStartLoop(int (*pt2Func)(int argc, char *argv[]), int argc, char* argv[]) 358 { 359 multiThreads = true; 360 QFuture<int> future = QtConcurrent::run(pt2Func, argc, argv); 361 return guiMainThread->start(); 362 } 363 364 365 CV_IMPL void cvStopLoop() 366 { 367 qApp->exit(); 368 } 369 370 371 static CvWindow* icvFindWindowByName(QString name) 372 { 373 CvWindow* window = 0; 374 375 //This is not a very clean way to do the stuff. Indeed, QAction automatically generate toolTil (QLabel) 376 //that can be grabbed here and crash the code at 'w->param_name==name'. 377 foreach (QWidget* widget, QApplication::topLevelWidgets()) 378 { 379 if (widget->isWindow() && !widget->parentWidget())//is a window without parent 380 { 381 CvWinModel* temp = (CvWinModel*) widget; 382 383 if (temp->type == type_CvWindow) 384 { 385 CvWindow* w = (CvWindow*) temp; 386 if (w->objectName() == name) 387 { 388 window = w; 389 break; 390 } 391 } 392 } 393 } 394 395 return window; 396 } 397 398 399 static CvBar* icvFindBarByName(QBoxLayout* layout, QString name_bar, typeBar type) 400 { 401 if (!layout) 402 return NULL; 403 404 int stop_index = layout->layout()->count(); 405 406 for (int i = 0; i < stop_index; ++i) 407 { 408 CvBar* t = (CvBar*) layout->layout()->itemAt(i); 409 410 if (t->type == type && t->name_bar == name_bar) 411 return t; 412 } 413 414 return NULL; 415 } 416 417 418 static CvTrackbar* icvFindTrackBarByName(const char* name_trackbar, const char* name_window, QBoxLayout* layout = NULL) 419 { 420 QString nameQt(name_trackbar); 421 QString nameWinQt(name_window); 422 423 if (nameWinQt.isEmpty() && global_control_panel) //window name is null and we have a control panel 424 layout = global_control_panel->myLayout; 425 426 if (!layout) 427 { 428 QPointer<CvWindow> w = icvFindWindowByName(nameWinQt); 429 430 if (!w) 431 CV_Error(CV_StsNullPtr, "NULL window handler"); 432 433 if (w->param_gui_mode == CV_GUI_NORMAL) 434 return (CvTrackbar*) icvFindBarByName(w->myBarLayout, nameQt, type_CvTrackbar); 435 436 if (w->param_gui_mode == CV_GUI_EXPANDED) 437 { 438 CvBar* result = icvFindBarByName(w->myBarLayout, nameQt, type_CvTrackbar); 439 440 if (result) 441 return (CvTrackbar*) result; 442 443 return (CvTrackbar*) icvFindBarByName(global_control_panel->myLayout, nameQt, type_CvTrackbar); 444 } 445 446 return NULL; 447 } 448 else 449 { 450 //layout was specified 451 return (CvTrackbar*) icvFindBarByName(layout, nameQt, type_CvTrackbar); 452 } 453 } 454 455 /* 456 static CvButtonbar* icvFindButtonBarByName(const char* button_name, QBoxLayout* layout) 457 { 458 QString nameQt(button_name); 459 return (CvButtonbar*) icvFindBarByName(layout, nameQt, type_CvButtonbar); 460 } 461 */ 462 463 static int icvInitSystem(int* c, char** v) 464 { 465 //"For any GUI application using Qt, there is precisely one QApplication object" 466 if (!QApplication::instance()) 467 { 468 new QApplication(*c, v); 469 setlocale(LC_NUMERIC,"C"); 470 471 qDebug() << "init done"; 472 473 #ifdef HAVE_QT_OPENGL 474 qDebug() << "opengl support available"; 475 #endif 476 } 477 478 return 0; 479 } 480 481 482 CV_IMPL int cvInitSystem(int, char**) 483 { 484 icvInitSystem(¶meterSystemC, parameterSystemV); 485 return 0; 486 } 487 488 489 CV_IMPL int cvNamedWindow(const char* name, int flags) 490 { 491 if (!guiMainThread) 492 guiMainThread = new GuiReceiver; 493 if (QThread::currentThread() != QApplication::instance()->thread()) { 494 multiThreads = true; 495 QMetaObject::invokeMethod(guiMainThread, 496 "createWindow", 497 Qt::BlockingQueuedConnection, // block so that we can do useful stuff once we confirm it is created 498 Q_ARG(QString, QString(name)), 499 Q_ARG(int, flags)); 500 } else { 501 guiMainThread->createWindow(QString(name), flags); 502 } 503 504 return 1; //Dummy value - probably should return the result of the invocation. 505 } 506 507 508 CV_IMPL void cvDestroyWindow(const char* name) 509 { 510 if (!guiMainThread) 511 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 512 513 QMetaObject::invokeMethod(guiMainThread, 514 "destroyWindow", 515 Qt::AutoConnection, // if another thread is controlling, let it handle it without blocking ourselves here 516 Q_ARG(QString, QString(name))); 517 } 518 519 520 CV_IMPL void cvDestroyAllWindows() 521 { 522 if (!guiMainThread) 523 return; 524 QMetaObject::invokeMethod(guiMainThread, 525 "destroyAllWindow", 526 Qt::AutoConnection // if another thread is controlling, let it handle it without blocking ourselves here 527 ); 528 } 529 530 531 CV_IMPL void* cvGetWindowHandle(const char* name) 532 { 533 if (!name) 534 CV_Error( CV_StsNullPtr, "NULL name string" ); 535 536 return (void*) icvFindWindowByName(QLatin1String(name)); 537 } 538 539 540 CV_IMPL const char* cvGetWindowName(void* window_handle) 541 { 542 if( !window_handle ) 543 CV_Error( CV_StsNullPtr, "NULL window handler" ); 544 545 return ((CvWindow*)window_handle)->objectName().toLatin1().data(); 546 } 547 548 549 CV_IMPL void cvMoveWindow(const char* name, int x, int y) 550 { 551 if (!guiMainThread) 552 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 553 QMetaObject::invokeMethod(guiMainThread, 554 "moveWindow", 555 autoBlockingConnection(), 556 Q_ARG(QString, QString(name)), 557 Q_ARG(int, x), 558 Q_ARG(int, y)); 559 } 560 561 CV_IMPL void cvResizeWindow(const char* name, int width, int height) 562 { 563 if (!guiMainThread) 564 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 565 QMetaObject::invokeMethod(guiMainThread, 566 "resizeWindow", 567 autoBlockingConnection(), 568 Q_ARG(QString, QString(name)), 569 Q_ARG(int, width), 570 Q_ARG(int, height)); 571 } 572 573 574 CV_IMPL int cvCreateTrackbar2(const char* name_bar, const char* window_name, int* val, int count, CvTrackbarCallback2 on_notify, void* userdata) 575 { 576 if (!guiMainThread) 577 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 578 579 QMetaObject::invokeMethod(guiMainThread, 580 "addSlider2", 581 autoBlockingConnection(), 582 Q_ARG(QString, QString(name_bar)), 583 Q_ARG(QString, QString(window_name)), 584 Q_ARG(void*, (void*)val), 585 Q_ARG(int, count), 586 Q_ARG(void*, (void*)on_notify), 587 Q_ARG(void*, (void*)userdata)); 588 589 return 1; //dummy value 590 } 591 592 593 CV_IMPL int cvStartWindowThread() 594 { 595 return 0; 596 } 597 598 599 CV_IMPL int cvCreateTrackbar(const char* name_bar, const char* window_name, int* value, int count, CvTrackbarCallback on_change) 600 { 601 if (!guiMainThread) 602 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 603 604 QMetaObject::invokeMethod(guiMainThread, 605 "addSlider", 606 autoBlockingConnection(), 607 Q_ARG(QString, QString(name_bar)), 608 Q_ARG(QString, QString(window_name)), 609 Q_ARG(void*, (void*)value), 610 Q_ARG(int, count), 611 Q_ARG(void*, (void*)on_change)); 612 613 return 1; //dummy value 614 } 615 616 617 CV_IMPL int cvCreateButton(const char* button_name, CvButtonCallback on_change, void* userdata, int button_type, int initial_button_state) 618 { 619 if (!guiMainThread) 620 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 621 622 if (initial_button_state < 0 || initial_button_state > 1) 623 return 0; 624 625 QMetaObject::invokeMethod(guiMainThread, 626 "addButton", 627 autoBlockingConnection(), 628 Q_ARG(QString, QString(button_name)), 629 Q_ARG(int, button_type), 630 Q_ARG(int, initial_button_state), 631 Q_ARG(void*, (void*)on_change), 632 Q_ARG(void*, userdata)); 633 634 return 1;//dummy value 635 } 636 637 638 CV_IMPL int cvGetTrackbarPos(const char* name_bar, const char* window_name) 639 { 640 int result = -1; 641 642 QPointer<CvTrackbar> t = icvFindTrackBarByName(name_bar, window_name); 643 644 if (t) 645 result = t->slider->value(); 646 647 return result; 648 } 649 650 651 CV_IMPL void cvSetTrackbarPos(const char* name_bar, const char* window_name, int pos) 652 { 653 QPointer<CvTrackbar> t = icvFindTrackBarByName(name_bar, window_name); 654 655 if (t) 656 t->slider->setValue(pos); 657 } 658 659 660 CV_IMPL void cvSetTrackbarMax(const char* name_bar, const char* window_name, int maxval) 661 { 662 if (maxval >= 0) 663 { 664 QPointer<CvTrackbar> t = icvFindTrackBarByName(name_bar, window_name); 665 if (t) 666 { 667 t->slider->setMaximum(maxval); 668 } 669 } 670 } 671 672 673 /* assign callback for mouse events */ 674 CV_IMPL void cvSetMouseCallback(const char* window_name, CvMouseCallback on_mouse, void* param) 675 { 676 QPointer<CvWindow> w = icvFindWindowByName(QLatin1String(window_name)); 677 678 if (!w) 679 CV_Error(CV_StsNullPtr, "NULL window handler"); 680 681 w->setMouseCallBack(on_mouse, param); 682 683 } 684 685 686 CV_IMPL void cvShowImage(const char* name, const CvArr* arr) 687 { 688 if (!guiMainThread) 689 guiMainThread = new GuiReceiver; 690 if (QThread::currentThread() != QApplication::instance()->thread()) { 691 multiThreads = true; 692 QMetaObject::invokeMethod(guiMainThread, 693 "showImage", 694 autoBlockingConnection(), 695 Q_ARG(QString, QString(name)), 696 Q_ARG(void*, (void*)arr) 697 ); 698 } else { 699 guiMainThread->showImage(QString(name), (void*)arr); 700 } 701 } 702 703 704 #ifdef HAVE_QT_OPENGL 705 706 CV_IMPL void cvSetOpenGlDrawCallback(const char* window_name, CvOpenGlDrawCallback callback, void* userdata) 707 { 708 if (!guiMainThread) 709 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 710 711 QMetaObject::invokeMethod(guiMainThread, 712 "setOpenGlDrawCallback", 713 autoBlockingConnection(), 714 Q_ARG(QString, QString(window_name)), 715 Q_ARG(void*, (void*)callback), 716 Q_ARG(void*, userdata)); 717 } 718 719 720 CV_IMPL void cvSetOpenGlContext(const char* window_name) 721 { 722 if (!guiMainThread) 723 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 724 725 QMetaObject::invokeMethod(guiMainThread, 726 "setOpenGlContext", 727 autoBlockingConnection(), 728 Q_ARG(QString, QString(window_name))); 729 } 730 731 732 CV_IMPL void cvUpdateWindow(const char* window_name) 733 { 734 if (!guiMainThread) 735 CV_Error( CV_StsNullPtr, "NULL guiReceiver (please create a window)" ); 736 737 QMetaObject::invokeMethod(guiMainThread, 738 "updateWindow", 739 autoBlockingConnection(), 740 Q_ARG(QString, QString(window_name))); 741 } 742 743 #endif 744 745 746 double cvGetOpenGlProp_QT(const char* name) 747 { 748 double result = -1; 749 750 if (guiMainThread) 751 { 752 QMetaObject::invokeMethod(guiMainThread, 753 "isOpenGl", 754 autoBlockingConnection(), 755 Q_RETURN_ARG(double, result), 756 Q_ARG(QString, QString(name))); 757 } 758 759 return result; 760 } 761 762 763 ////////////////////////////////////////////////////// 764 // GuiReceiver 765 766 767 GuiReceiver::GuiReceiver() : bTimeOut(false), nb_windows(0) 768 { 769 doesExternalQAppExist = (QApplication::instance() != 0); 770 icvInitSystem(¶meterSystemC, parameterSystemV); 771 772 timer = new QTimer(this); 773 QObject::connect(timer, SIGNAL(timeout()), this, SLOT(timeOut())); 774 timer->setSingleShot(true); 775 if ( doesExternalQAppExist ) { 776 moveToThread(QApplication::instance()->thread()); 777 } 778 } 779 780 781 void GuiReceiver::isLastWindow() 782 { 783 if (--nb_windows <= 0) 784 { 785 delete guiMainThread;//delete global_control_panel too 786 guiMainThread = NULL; 787 788 if (!doesExternalQAppExist) 789 { 790 qApp->quit(); 791 } 792 } 793 } 794 795 796 GuiReceiver::~GuiReceiver() 797 { 798 if (global_control_panel) 799 { 800 delete global_control_panel; 801 global_control_panel = NULL; 802 } 803 } 804 805 806 void GuiReceiver::putText(void* arr, QString text, QPoint org, void* arg2) 807 { 808 CV_Assert(arr); 809 810 CvMat* mat, stub; 811 mat = cvGetMat(arr, &stub); 812 813 int nbChannelOriginImage = cvGetElemType(mat); 814 if (nbChannelOriginImage != CV_8UC3) return; //for now, font works only with 8UC3 815 816 QImage qimg(mat->data.ptr, mat->cols, mat->rows, mat->step, QImage::Format_RGB888); 817 818 CvFont* font = (CvFont*)arg2; 819 820 QPainter qp(&qimg); 821 if (font) 822 { 823 QFont f(font->nameFont, font->line_type/*PointSize*/, font->thickness/*weight*/); 824 f.setStyle((QFont::Style) font->font_face/*style*/); 825 f.setLetterSpacing(QFont::AbsoluteSpacing, font->dx/*spacing*/); 826 //cvScalar(blue_component, green_component, red_component[, alpha_component]) 827 //Qt map non-transparent to 0xFF and transparent to 0 828 //OpenCV scalar is the reverse, so 255-font->color.val[3] 829 qp.setPen(QColor(font->color.val[2], font->color.val[1], font->color.val[0], 255 - font->color.val[3])); 830 qp.setFont(f); 831 } 832 qp.drawText(org, text); 833 qp.end(); 834 } 835 836 837 void GuiReceiver::saveWindowParameters(QString name) 838 { 839 QPointer<CvWindow> w = icvFindWindowByName(name); 840 841 if (w) 842 w->writeSettings(); 843 } 844 845 846 void GuiReceiver::loadWindowParameters(QString name) 847 { 848 QPointer<CvWindow> w = icvFindWindowByName(name); 849 850 if (w) 851 w->readSettings(); 852 } 853 854 855 double GuiReceiver::getRatioWindow(QString name) 856 { 857 QPointer<CvWindow> w = icvFindWindowByName(name); 858 859 if (!w) 860 return -1; 861 862 return w->getRatio(); 863 } 864 865 866 void GuiReceiver::setRatioWindow(QString name, double arg2) 867 { 868 QPointer<CvWindow> w = icvFindWindowByName( name.toLatin1().data() ); 869 870 if (!w) 871 return; 872 873 int flags = (int) arg2; 874 875 w->setRatio(flags); 876 } 877 878 879 double GuiReceiver::getPropWindow(QString name) 880 { 881 QPointer<CvWindow> w = icvFindWindowByName(name); 882 883 if (!w) 884 return -1; 885 886 return (double) w->getPropWindow(); 887 } 888 889 890 void GuiReceiver::setPropWindow(QString name, double arg2) 891 { 892 QPointer<CvWindow> w = icvFindWindowByName(name); 893 894 if (!w) 895 return; 896 897 int flags = (int) arg2; 898 899 w->setPropWindow(flags); 900 } 901 902 void GuiReceiver::setWindowTitle(QString name, QString title) 903 { 904 QPointer<CvWindow> w = icvFindWindowByName(name); 905 906 if (!w) 907 { 908 cvNamedWindow(name.toLatin1().data()); 909 w = icvFindWindowByName(name); 910 } 911 912 if (!w) 913 return; 914 915 w->setWindowTitle(title); 916 } 917 918 919 double GuiReceiver::isFullScreen(QString name) 920 { 921 QPointer<CvWindow> w = icvFindWindowByName(name); 922 923 if (!w) 924 return -1; 925 926 return w->isFullScreen() ? CV_WINDOW_FULLSCREEN : CV_WINDOW_NORMAL; 927 } 928 929 930 void GuiReceiver::toggleFullScreen(QString name, double arg2) 931 { 932 QPointer<CvWindow> w = icvFindWindowByName(name); 933 934 if (!w) 935 return; 936 937 int flags = (int) arg2; 938 939 w->toggleFullScreen(flags); 940 } 941 942 943 void GuiReceiver::createWindow(QString name, int flags) 944 { 945 if (!qApp) 946 CV_Error(CV_StsNullPtr, "NULL session handler" ); 947 948 // Check the name in the storage 949 if (icvFindWindowByName(name.toLatin1().data())) 950 { 951 return; 952 } 953 954 nb_windows++; 955 new CvWindow(name, flags); 956 } 957 958 959 void GuiReceiver::timeOut() 960 { 961 bTimeOut = true; 962 } 963 964 965 void GuiReceiver::displayInfo(QString name, QString text, int delayms) 966 { 967 QPointer<CvWindow> w = icvFindWindowByName(name); 968 969 if (w) 970 w->displayInfo(text, delayms); 971 } 972 973 974 void GuiReceiver::displayStatusBar(QString name, QString text, int delayms) 975 { 976 QPointer<CvWindow> w = icvFindWindowByName(name); 977 978 if (w) 979 w->displayStatusBar(text, delayms); 980 } 981 982 983 void GuiReceiver::showImage(QString name, void* arr) 984 { 985 QPointer<CvWindow> w = icvFindWindowByName(name); 986 987 if (!w) //as observed in the previous implementation (W32, GTK or Carbon), create a new window is the pointer returned is null 988 { 989 cvNamedWindow(name.toLatin1().data()); 990 w = icvFindWindowByName(name); 991 } 992 993 if (!w || !arr) 994 return; // keep silence here. 995 996 if (w->isOpenGl()) 997 { 998 CvMat* mat, stub; 999 1000 mat = cvGetMat(arr, &stub); 1001 1002 cv::Mat im = cv::cvarrToMat(mat); 1003 cv::imshow(name.toUtf8().data(), im); 1004 } 1005 else 1006 { 1007 w->updateImage(arr); 1008 } 1009 1010 if (w->isHidden()) 1011 w->show(); 1012 } 1013 1014 1015 void GuiReceiver::destroyWindow(QString name) 1016 { 1017 1018 QPointer<CvWindow> w = icvFindWindowByName(name); 1019 1020 if (w) 1021 { 1022 w->close(); 1023 1024 //in not-multiThreads mode, looks like the window is hidden but not deleted 1025 //so I do it manually 1026 //otherwise QApplication do it for me if the exec command was executed (in multiThread mode) 1027 if (!multiThreads) 1028 delete w; 1029 } 1030 } 1031 1032 1033 void GuiReceiver::destroyAllWindow() 1034 { 1035 if (!qApp) 1036 CV_Error(CV_StsNullPtr, "NULL session handler" ); 1037 1038 if (multiThreads) 1039 { 1040 // WARNING: this could even close windows from an external parent app 1041 //#TODO check externalQAppExists and in case it does, close windows carefully, 1042 // i.e. apply the className-check from below... 1043 qApp->closeAllWindows(); 1044 } 1045 else 1046 { 1047 bool isWidgetDeleted = true; 1048 while(isWidgetDeleted) 1049 { 1050 isWidgetDeleted = false; 1051 QWidgetList list = QApplication::topLevelWidgets(); 1052 for (int i = 0; i < list.count(); i++) 1053 { 1054 QObject *obj = list.at(i); 1055 if (obj->metaObject()->className() == QString("CvWindow")) 1056 { 1057 delete obj; 1058 isWidgetDeleted = true; 1059 break; 1060 } 1061 } 1062 } 1063 } 1064 } 1065 1066 1067 void GuiReceiver::moveWindow(QString name, int x, int y) 1068 { 1069 QPointer<CvWindow> w = icvFindWindowByName(name); 1070 1071 if (w) 1072 w->move(x, y); 1073 } 1074 1075 1076 void GuiReceiver::resizeWindow(QString name, int width, int height) 1077 { 1078 QPointer<CvWindow> w = icvFindWindowByName(name); 1079 1080 if (w) 1081 { 1082 w->showNormal(); 1083 w->setViewportSize(QSize(width, height)); 1084 } 1085 } 1086 1087 1088 void GuiReceiver::enablePropertiesButtonEachWindow() 1089 { 1090 //For each window, enable window property button 1091 foreach (QWidget* widget, QApplication::topLevelWidgets()) 1092 { 1093 if (widget->isWindow() && !widget->parentWidget()) //is a window without parent 1094 { 1095 CvWinModel* temp = (CvWinModel*) widget; 1096 if (temp->type == type_CvWindow) 1097 { 1098 CvWindow* w = (CvWindow*) widget; 1099 1100 //active window properties button 1101 w->enablePropertiesButton(); 1102 } 1103 } 1104 } 1105 } 1106 1107 1108 void GuiReceiver::addButton(QString button_name, int button_type, int initial_button_state, void* on_change, void* userdata) 1109 { 1110 if (!global_control_panel) 1111 return; 1112 1113 QPointer<CvButtonbar> b; 1114 1115 if (global_control_panel->myLayout->count() == 0) //if that is the first button attach to the control panel, create a new button bar 1116 { 1117 b = CvWindow::createButtonBar(button_name); //the bar has the name of the first button attached to it 1118 enablePropertiesButtonEachWindow(); 1119 1120 } 1121 else 1122 { 1123 CvBar* lastbar = (CvBar*) global_control_panel->myLayout->itemAt(global_control_panel->myLayout->count() - 1); 1124 1125 if (lastbar->type == type_CvTrackbar) //if last bar is a trackbar, create a new buttonbar, else, attach to the current bar 1126 b = CvWindow::createButtonBar(button_name); //the bar has the name of the first button attached to it 1127 else 1128 b = (CvButtonbar*) lastbar; 1129 1130 } 1131 1132 b->addButton(button_name, (CvButtonCallback) on_change, userdata, button_type, initial_button_state); 1133 } 1134 1135 1136 void GuiReceiver::addSlider2(QString bar_name, QString window_name, void* value, int count, void* on_change, void *userdata) 1137 { 1138 QBoxLayout *layout = NULL; 1139 QPointer<CvWindow> w; 1140 1141 if (!window_name.isEmpty()) 1142 { 1143 w = icvFindWindowByName(window_name); 1144 1145 if (!w) 1146 return; 1147 } 1148 else 1149 { 1150 if (global_control_panel) 1151 layout = global_control_panel->myLayout; 1152 } 1153 1154 QPointer<CvTrackbar> t = icvFindTrackBarByName(bar_name.toLatin1().data(), window_name.toLatin1().data(), layout); 1155 1156 if (t) //trackbar exists 1157 return; 1158 1159 if (!value) 1160 CV_Error(CV_StsNullPtr, "NULL value pointer" ); 1161 1162 if (count <= 0) //count is the max value of the slider, so must be bigger than 0 1163 CV_Error(CV_StsNullPtr, "Max value of the slider must be bigger than 0" ); 1164 1165 CvWindow::addSlider2(w, bar_name, (int*)value, count, (CvTrackbarCallback2) on_change, userdata); 1166 } 1167 1168 1169 void GuiReceiver::addSlider(QString bar_name, QString window_name, void* value, int count, void* on_change) 1170 { 1171 QBoxLayout *layout = NULL; 1172 QPointer<CvWindow> w; 1173 1174 if (!window_name.isEmpty()) 1175 { 1176 w = icvFindWindowByName(window_name); 1177 1178 if (!w) 1179 return; 1180 } 1181 else 1182 { 1183 if (global_control_panel) 1184 layout = global_control_panel->myLayout; 1185 } 1186 1187 QPointer<CvTrackbar> t = icvFindTrackBarByName(bar_name.toLatin1().data(), window_name.toLatin1().data(), layout); 1188 1189 if (t) //trackbar exists 1190 return; 1191 1192 if (!value) 1193 CV_Error(CV_StsNullPtr, "NULL value pointer" ); 1194 1195 if (count <= 0) //count is the max value of the slider, so must be bigger than 0 1196 CV_Error(CV_StsNullPtr, "Max value of the slider must be bigger than 0" ); 1197 1198 CvWindow::addSlider(w, bar_name, (int*)value, count, (CvTrackbarCallback) on_change); 1199 } 1200 1201 1202 int GuiReceiver::start() 1203 { 1204 return qApp->exec(); 1205 } 1206 1207 1208 void GuiReceiver::setOpenGlDrawCallback(QString name, void* callback, void* userdata) 1209 { 1210 QPointer<CvWindow> w = icvFindWindowByName(name); 1211 1212 if (w) 1213 w->setOpenGlDrawCallback((CvOpenGlDrawCallback) callback, userdata); 1214 } 1215 1216 void GuiReceiver::setOpenGlContext(QString name) 1217 { 1218 QPointer<CvWindow> w = icvFindWindowByName(name); 1219 1220 if (w) 1221 w->makeCurrentOpenGlContext(); 1222 } 1223 1224 void GuiReceiver::updateWindow(QString name) 1225 { 1226 QPointer<CvWindow> w = icvFindWindowByName(name); 1227 1228 if (w) 1229 w->updateGl(); 1230 } 1231 1232 double GuiReceiver::isOpenGl(QString name) 1233 { 1234 double result = -1; 1235 1236 QPointer<CvWindow> w = icvFindWindowByName(name); 1237 1238 if (w) 1239 result = (double) w->isOpenGl(); 1240 1241 return result; 1242 } 1243 1244 1245 ////////////////////////////////////////////////////// 1246 // CvTrackbar 1247 1248 1249 CvTrackbar::CvTrackbar(CvWindow* arg, QString name, int* value, int _count, CvTrackbarCallback2 on_change, void* data) 1250 { 1251 callback = NULL; 1252 callback2 = on_change; 1253 userdata = data; 1254 1255 create(arg, name, value, _count); 1256 } 1257 1258 1259 CvTrackbar::CvTrackbar(CvWindow* arg, QString name, int* value, int _count, CvTrackbarCallback on_change) 1260 { 1261 callback = on_change; 1262 callback2 = NULL; 1263 userdata = NULL; 1264 1265 create(arg, name, value, _count); 1266 } 1267 1268 1269 void CvTrackbar::create(CvWindow* arg, QString name, int* value, int _count) 1270 { 1271 type = type_CvTrackbar; 1272 myparent = arg; 1273 name_bar = name; 1274 setObjectName(name_bar); 1275 dataSlider = value; 1276 1277 slider = new QSlider(Qt::Horizontal); 1278 slider->setFocusPolicy(Qt::StrongFocus); 1279 slider->setMinimum(0); 1280 slider->setMaximum(_count); 1281 slider->setPageStep(5); 1282 slider->setValue(*value); 1283 slider->setTickPosition(QSlider::TicksBelow); 1284 1285 1286 //Change style of the Slider 1287 //slider->setStyleSheet(str_Trackbar_css); 1288 1289 QFile qss(":/stylesheet-trackbar"); 1290 if (qss.open(QFile::ReadOnly)) 1291 { 1292 slider->setStyleSheet(QLatin1String(qss.readAll())); 1293 qss.close(); 1294 } 1295 1296 1297 //this next line does not work if we change the style with a stylesheet, why ? (bug in QT ?) 1298 //slider->setTickPosition(QSlider::TicksBelow); 1299 label = new QPushButton; 1300 label->setFlat(true); 1301 setLabel(slider->value()); 1302 1303 1304 QObject::connect(slider, SIGNAL(valueChanged(int)), this, SLOT(update(int))); 1305 1306 QObject::connect(label, SIGNAL(clicked()), this, SLOT(createDialog())); 1307 1308 //label->setStyleSheet("QPushButton:disabled {color: black}"); 1309 1310 addWidget(label, Qt::AlignLeft);//name + value 1311 addWidget(slider, Qt::AlignCenter);//slider 1312 } 1313 1314 1315 void CvTrackbar::createDialog() 1316 { 1317 bool ok = false; 1318 1319 //crash if I access the values directly and give them to QInputDialog, so do a copy first. 1320 int value = slider->value(); 1321 int step = slider->singleStep(); 1322 int min = slider->minimum(); 1323 int max = slider->maximum(); 1324 1325 int i = 1326 #if QT_VERSION >= 0x040500 1327 QInputDialog::getInt 1328 #else 1329 QInputDialog::getInteger 1330 #endif 1331 (this->parentWidget(), 1332 tr("Slider %1").arg(name_bar), 1333 tr("New value:"), 1334 value, 1335 min, 1336 max, 1337 step, 1338 &ok); 1339 1340 if (ok) 1341 slider->setValue(i); 1342 } 1343 1344 1345 void CvTrackbar::update(int myvalue) 1346 { 1347 setLabel(myvalue); 1348 1349 *dataSlider = myvalue; 1350 if (callback) 1351 { 1352 callback(myvalue); 1353 return; 1354 } 1355 1356 if (callback2) 1357 { 1358 callback2(myvalue, userdata); 1359 return; 1360 } 1361 } 1362 1363 1364 void CvTrackbar::setLabel(int myvalue) 1365 { 1366 QString nameNormalized = name_bar.leftJustified( 10, ' ', true ); 1367 QString valueMaximum = QString("%1").arg(slider->maximum()); 1368 QString str = QString("%1 (%2/%3)").arg(nameNormalized).arg(myvalue,valueMaximum.length(),10,QChar('0')).arg(valueMaximum); 1369 label->setText(str); 1370 } 1371 1372 1373 ////////////////////////////////////////////////////// 1374 // CvButtonbar 1375 1376 1377 //here CvButtonbar class 1378 CvButtonbar::CvButtonbar(QWidget* arg, QString arg2) 1379 { 1380 type = type_CvButtonbar; 1381 myparent = arg; 1382 name_bar = arg2; 1383 setObjectName(name_bar); 1384 1385 group_button = new QButtonGroup(this); 1386 } 1387 1388 1389 void CvButtonbar::setLabel() 1390 { 1391 QString nameNormalized = name_bar.leftJustified(10, ' ', true); 1392 label->setText(nameNormalized); 1393 } 1394 1395 1396 void CvButtonbar::addButton(QString name, CvButtonCallback call, void* userdata, int button_type, int initial_button_state) 1397 { 1398 QString button_name = name; 1399 1400 if (button_name == "") 1401 button_name = tr("button %1").arg(this->count()); 1402 1403 QPointer<QAbstractButton> button; 1404 1405 if (button_type == CV_PUSH_BUTTON) 1406 button = (QAbstractButton*) new CvPushButton(this, button_name,call, userdata); 1407 1408 if (button_type == CV_CHECKBOX) 1409 button = (QAbstractButton*) new CvCheckBox(this, button_name,call, userdata, initial_button_state); 1410 1411 if (button_type == CV_RADIOBOX) 1412 { 1413 button = (QAbstractButton*) new CvRadioButton(this, button_name,call, userdata, initial_button_state); 1414 group_button->addButton(button); 1415 } 1416 1417 if (button) 1418 { 1419 if (button_type == CV_PUSH_BUTTON) 1420 QObject::connect(button, SIGNAL(clicked(bool)), button, SLOT(callCallBack(bool))); 1421 else 1422 QObject::connect(button, SIGNAL(toggled(bool)), button, SLOT(callCallBack(bool))); 1423 1424 addWidget(button, Qt::AlignCenter); 1425 } 1426 } 1427 1428 1429 ////////////////////////////////////////////////////// 1430 // Buttons 1431 1432 1433 //buttons here 1434 CvPushButton::CvPushButton(CvButtonbar* arg1, QString arg2, CvButtonCallback arg3, void* arg4) 1435 { 1436 myparent = arg1; 1437 button_name = arg2; 1438 callback = arg3; 1439 userdata = arg4; 1440 1441 setObjectName(button_name); 1442 setText(button_name); 1443 1444 if (isChecked()) 1445 callCallBack(true); 1446 } 1447 1448 1449 void CvPushButton::callCallBack(bool checked) 1450 { 1451 if (callback) 1452 callback(checked, userdata); 1453 } 1454 1455 1456 CvCheckBox::CvCheckBox(CvButtonbar* arg1, QString arg2, CvButtonCallback arg3, void* arg4, int initial_button_state) 1457 { 1458 myparent = arg1; 1459 button_name = arg2; 1460 callback = arg3; 1461 userdata = arg4; 1462 1463 setObjectName(button_name); 1464 setCheckState((initial_button_state == 1 ? Qt::Checked : Qt::Unchecked)); 1465 setText(button_name); 1466 1467 if (isChecked()) 1468 callCallBack(true); 1469 } 1470 1471 1472 void CvCheckBox::callCallBack(bool checked) 1473 { 1474 if (callback) 1475 callback(checked, userdata); 1476 } 1477 1478 1479 CvRadioButton::CvRadioButton(CvButtonbar* arg1, QString arg2, CvButtonCallback arg3, void* arg4, int initial_button_state) 1480 { 1481 myparent = arg1; 1482 button_name = arg2; 1483 callback = arg3; 1484 userdata = arg4; 1485 1486 setObjectName(button_name); 1487 setChecked(initial_button_state); 1488 setText(button_name); 1489 1490 if (isChecked()) 1491 callCallBack(true); 1492 } 1493 1494 void CvRadioButton::callCallBack(bool checked) 1495 { 1496 if (callback) 1497 callback(checked, userdata); 1498 } 1499 1500 1501 ////////////////////////////////////////////////////// 1502 // CvWinProperties 1503 1504 1505 //here CvWinProperties class 1506 CvWinProperties::CvWinProperties(QString name_paraWindow, QObject* /*parent*/) 1507 { 1508 //setParent(parent); 1509 type = type_CvWinProperties; 1510 setWindowFlags(Qt::Tool); 1511 setContentsMargins(0, 0, 0, 0); 1512 setWindowTitle(name_paraWindow); 1513 setObjectName(name_paraWindow); 1514 resize(100, 50); 1515 1516 myLayout = new QBoxLayout(QBoxLayout::TopToBottom); 1517 myLayout->setObjectName(QString::fromUtf8("boxLayout")); 1518 myLayout->setContentsMargins(0, 0, 0, 0); 1519 myLayout->setSpacing(0); 1520 myLayout->setMargin(0); 1521 myLayout->setSizeConstraint(QLayout::SetFixedSize); 1522 setLayout(myLayout); 1523 1524 hide(); 1525 } 1526 1527 1528 void CvWinProperties::closeEvent(QCloseEvent* e) 1529 { 1530 e->accept(); //intersept the close event (not sure I really need it) 1531 //an hide event is also sent. I will intercept it and do some processing 1532 } 1533 1534 1535 void CvWinProperties::showEvent(QShowEvent* evnt) 1536 { 1537 //why -1,-1 ?: do this trick because the first time the code is run, 1538 //no value pos was saved so we let Qt move the window in the middle of its parent (event ignored). 1539 //then hide will save the last position and thus, we want to retreive it (event accepted). 1540 QPoint mypos(-1, -1); 1541 QSettings settings("OpenCV2", objectName()); 1542 mypos = settings.value("pos", mypos).toPoint(); 1543 1544 if (mypos.x() >= 0) 1545 { 1546 move(mypos); 1547 evnt->accept(); 1548 } 1549 else 1550 { 1551 evnt->ignore(); 1552 } 1553 } 1554 1555 1556 void CvWinProperties::hideEvent(QHideEvent* evnt) 1557 { 1558 QSettings settings("OpenCV2", objectName()); 1559 settings.setValue("pos", pos()); //there is an offset of 6 pixels (so the window's position is wrong -- why ?) 1560 evnt->accept(); 1561 } 1562 1563 1564 CvWinProperties::~CvWinProperties() 1565 { 1566 //clear the setting pos 1567 QSettings settings("OpenCV2", objectName()); 1568 settings.remove("pos"); 1569 } 1570 1571 1572 ////////////////////////////////////////////////////// 1573 // CvWindow 1574 1575 1576 CvWindow::CvWindow(QString name, int arg2) 1577 { 1578 type = type_CvWindow; 1579 1580 param_flags = arg2 & 0x0000000F; 1581 param_gui_mode = arg2 & 0x000000F0; 1582 param_ratio_mode = arg2 & 0x00000F00; 1583 1584 //setAttribute(Qt::WA_DeleteOnClose); //in other case, does not release memory 1585 setContentsMargins(0, 0, 0, 0); 1586 setWindowTitle(name); 1587 setObjectName(name); 1588 1589 setFocus( Qt::PopupFocusReason ); //#1695 arrow keys are not received without the explicit focus 1590 1591 resize(400, 300); 1592 setMinimumSize(1, 1); 1593 1594 //1: create control panel 1595 if (!global_control_panel) 1596 global_control_panel = createParameterWindow(); 1597 1598 //2: Layouts 1599 createBarLayout(); 1600 createGlobalLayout(); 1601 1602 //3: my view 1603 #ifndef HAVE_QT_OPENGL 1604 if (arg2 & CV_WINDOW_OPENGL) 1605 CV_Error( CV_OpenGlNotSupported, "Library was built without OpenGL support" ); 1606 mode_display = CV_MODE_NORMAL; 1607 #else 1608 mode_display = arg2 & CV_WINDOW_OPENGL ? CV_MODE_OPENGL : CV_MODE_NORMAL; 1609 if (mode_display == CV_MODE_OPENGL) 1610 param_gui_mode = CV_GUI_NORMAL; 1611 #endif 1612 createView(); 1613 1614 //4: shortcuts and actions 1615 //5: toolBar and statusbar 1616 if (param_gui_mode == CV_GUI_EXPANDED) 1617 { 1618 createActions(); 1619 createShortcuts(); 1620 1621 createToolBar(); 1622 createStatusBar(); 1623 } 1624 1625 //Now attach everything 1626 if (myToolBar) 1627 myGlobalLayout->addWidget(myToolBar, Qt::AlignCenter); 1628 1629 myGlobalLayout->addWidget(myView->getWidget(), Qt::AlignCenter); 1630 1631 myGlobalLayout->addLayout(myBarLayout, Qt::AlignCenter); 1632 1633 if (myStatusBar) 1634 myGlobalLayout->addWidget(myStatusBar, Qt::AlignCenter); 1635 1636 setLayout(myGlobalLayout); 1637 show(); 1638 } 1639 1640 1641 CvWindow::~CvWindow() 1642 { 1643 if (guiMainThread) 1644 guiMainThread->isLastWindow(); 1645 } 1646 1647 1648 void CvWindow::setMouseCallBack(CvMouseCallback callback, void* param) 1649 { 1650 myView->setMouseCallBack(callback, param); 1651 } 1652 1653 1654 void CvWindow::writeSettings() 1655 { 1656 //organisation and application's name 1657 QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName()); 1658 1659 settings.setValue("pos", pos()); 1660 settings.setValue("size", size()); 1661 settings.setValue("mode_resize" ,param_flags); 1662 settings.setValue("mode_gui", param_gui_mode); 1663 1664 myView->writeSettings(settings); 1665 1666 icvSaveTrackbars(&settings); 1667 1668 if (global_control_panel) 1669 { 1670 icvSaveControlPanel(); 1671 settings.setValue("posPanel", global_control_panel->pos()); 1672 } 1673 } 1674 1675 1676 1677 //TODO: load CV_GUI flag (done) and act accordingly (create win property if needed and attach trackbars) 1678 void CvWindow::readSettings() 1679 { 1680 //organisation and application's name 1681 QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName()); 1682 1683 QPoint _pos = settings.value("pos", QPoint(200, 200)).toPoint(); 1684 QSize _size = settings.value("size", QSize(400, 400)).toSize(); 1685 1686 param_flags = settings.value("mode_resize", param_flags).toInt(); 1687 param_gui_mode = settings.value("mode_gui", param_gui_mode).toInt(); 1688 1689 param_flags = settings.value("mode_resize", param_flags).toInt(); 1690 1691 myView->readSettings(settings); 1692 1693 //trackbar here 1694 icvLoadTrackbars(&settings); 1695 1696 resize(_size); 1697 move(_pos); 1698 1699 if (global_control_panel) 1700 { 1701 icvLoadControlPanel(); 1702 global_control_panel->move(settings.value("posPanel", global_control_panel->pos()).toPoint()); 1703 } 1704 } 1705 1706 1707 double CvWindow::getRatio() 1708 { 1709 return myView->getRatio(); 1710 } 1711 1712 1713 void CvWindow::setRatio(int flags) 1714 { 1715 myView->setRatio(flags); 1716 } 1717 1718 1719 int CvWindow::getPropWindow() 1720 { 1721 return param_flags; 1722 } 1723 1724 1725 void CvWindow::setPropWindow(int flags) 1726 { 1727 if (param_flags == flags) //nothing to do 1728 return; 1729 1730 switch(flags) 1731 { 1732 case CV_WINDOW_NORMAL: 1733 myGlobalLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); 1734 param_flags = flags; 1735 1736 break; 1737 1738 case CV_WINDOW_AUTOSIZE: 1739 myGlobalLayout->setSizeConstraint(QLayout::SetFixedSize); 1740 param_flags = flags; 1741 1742 break; 1743 1744 default: 1745 ; 1746 } 1747 } 1748 1749 void CvWindow::toggleFullScreen(int flags) 1750 { 1751 if (isFullScreen() && flags == CV_WINDOW_NORMAL) 1752 { 1753 showTools(); 1754 showNormal(); 1755 return; 1756 } 1757 1758 if (!isFullScreen() && flags == CV_WINDOW_FULLSCREEN) 1759 { 1760 hideTools(); 1761 showFullScreen(); 1762 return; 1763 } 1764 } 1765 1766 1767 void CvWindow::updateImage(void* arr) 1768 { 1769 myView->updateImage(arr); 1770 } 1771 1772 1773 void CvWindow::displayInfo(QString text, int delayms) 1774 { 1775 myView->startDisplayInfo(text, delayms); 1776 } 1777 1778 1779 void CvWindow::displayStatusBar(QString text, int delayms) 1780 { 1781 if (myStatusBar) 1782 myStatusBar->showMessage(text, delayms); 1783 } 1784 1785 1786 void CvWindow::enablePropertiesButton() 1787 { 1788 if (!vect_QActions.empty()) 1789 vect_QActions[9]->setDisabled(false); 1790 } 1791 1792 1793 CvButtonbar* CvWindow::createButtonBar(QString name_bar) 1794 { 1795 QPointer<CvButtonbar> t = new CvButtonbar(global_control_panel, name_bar); 1796 t->setAlignment(Qt::AlignHCenter); 1797 1798 QPointer<QBoxLayout> myLayout = global_control_panel->myLayout; 1799 1800 myLayout->insertLayout(myLayout->count(), t); 1801 1802 return t; 1803 } 1804 1805 1806 void CvWindow::addSlider(CvWindow* w, QString name, int* value, int count, CvTrackbarCallback on_change) 1807 { 1808 QPointer<CvTrackbar> t = new CvTrackbar(w, name, value, count, on_change); 1809 t->setAlignment(Qt::AlignHCenter); 1810 1811 QPointer<QBoxLayout> myLayout; 1812 1813 if (w) 1814 { 1815 myLayout = w->myBarLayout; 1816 } 1817 else 1818 { 1819 myLayout = global_control_panel->myLayout; 1820 1821 //if first one, enable control panel 1822 if (myLayout->count() == 0) 1823 guiMainThread->enablePropertiesButtonEachWindow(); 1824 } 1825 1826 myLayout->insertLayout(myLayout->count(), t); 1827 } 1828 1829 1830 void CvWindow::addSlider2(CvWindow* w, QString name, int* value, int count, CvTrackbarCallback2 on_change, void* userdata) 1831 { 1832 QPointer<CvTrackbar> t = new CvTrackbar(w, name, value, count, on_change, userdata); 1833 t->setAlignment(Qt::AlignHCenter); 1834 1835 QPointer<QBoxLayout> myLayout; 1836 1837 if (w) 1838 { 1839 myLayout = w->myBarLayout; 1840 } 1841 else 1842 { 1843 myLayout = global_control_panel->myLayout; 1844 1845 //if first one, enable control panel 1846 if (myLayout->count() == 0) 1847 guiMainThread->enablePropertiesButtonEachWindow(); 1848 } 1849 1850 myLayout->insertLayout(myLayout->count(), t); 1851 } 1852 1853 1854 void CvWindow::setOpenGlDrawCallback(CvOpenGlDrawCallback callback, void* userdata) 1855 { 1856 myView->setOpenGlDrawCallback(callback, userdata); 1857 } 1858 1859 1860 void CvWindow::makeCurrentOpenGlContext() 1861 { 1862 myView->makeCurrentOpenGlContext(); 1863 } 1864 1865 1866 void CvWindow::updateGl() 1867 { 1868 myView->updateGl(); 1869 } 1870 1871 1872 bool CvWindow::isOpenGl() 1873 { 1874 return mode_display == CV_MODE_OPENGL; 1875 } 1876 1877 1878 void CvWindow::setViewportSize(QSize _size) 1879 { 1880 resize(_size); 1881 myView->setSize(_size); 1882 } 1883 1884 1885 void CvWindow::createBarLayout() 1886 { 1887 myBarLayout = new QBoxLayout(QBoxLayout::TopToBottom); 1888 myBarLayout->setObjectName(QString::fromUtf8("barLayout")); 1889 myBarLayout->setContentsMargins(0, 0, 0, 0); 1890 myBarLayout->setSpacing(0); 1891 myBarLayout->setMargin(0); 1892 } 1893 1894 1895 void CvWindow::createGlobalLayout() 1896 { 1897 myGlobalLayout = new QBoxLayout(QBoxLayout::TopToBottom); 1898 myGlobalLayout->setObjectName(QString::fromUtf8("boxLayout")); 1899 myGlobalLayout->setContentsMargins(0, 0, 0, 0); 1900 myGlobalLayout->setSpacing(0); 1901 myGlobalLayout->setMargin(0); 1902 setMinimumSize(1, 1); 1903 1904 if (param_flags == CV_WINDOW_AUTOSIZE) 1905 myGlobalLayout->setSizeConstraint(QLayout::SetFixedSize); 1906 else if (param_flags == CV_WINDOW_NORMAL) 1907 myGlobalLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); 1908 } 1909 1910 1911 void CvWindow::createView() 1912 { 1913 #ifdef HAVE_QT_OPENGL 1914 if (isOpenGl()) 1915 myView = new OpenGlViewPort(this); 1916 else 1917 #endif 1918 myView = new DefaultViewPort(this, param_ratio_mode); 1919 } 1920 1921 1922 void CvWindow::createActions() 1923 { 1924 vect_QActions.resize(10); 1925 1926 QWidget* view = myView->getWidget(); 1927 1928 //if the shortcuts are changed in window_QT.h, we need to update the tooltip manually 1929 vect_QActions[0] = new QAction(QIcon(":/left-icon"), "Panning left (CTRL+arrowLEFT)", this); 1930 vect_QActions[0]->setIconVisibleInMenu(true); 1931 QObject::connect(vect_QActions[0], SIGNAL(triggered()), view, SLOT(siftWindowOnLeft())); 1932 1933 vect_QActions[1] = new QAction(QIcon(":/right-icon"), "Panning right (CTRL+arrowRIGHT)", this); 1934 vect_QActions[1]->setIconVisibleInMenu(true); 1935 QObject::connect(vect_QActions[1], SIGNAL(triggered()), view, SLOT(siftWindowOnRight())); 1936 1937 vect_QActions[2] = new QAction(QIcon(":/up-icon"), "Panning up (CTRL+arrowUP)", this); 1938 vect_QActions[2]->setIconVisibleInMenu(true); 1939 QObject::connect(vect_QActions[2], SIGNAL(triggered()), view, SLOT(siftWindowOnUp())); 1940 1941 vect_QActions[3] = new QAction(QIcon(":/down-icon"), "Panning down (CTRL+arrowDOWN)", this); 1942 vect_QActions[3]->setIconVisibleInMenu(true); 1943 QObject::connect(vect_QActions[3], SIGNAL(triggered()), view, SLOT(siftWindowOnDown()) ); 1944 1945 vect_QActions[4] = new QAction(QIcon(":/zoom_x1-icon"), "Zoom x1 (CTRL+P)", this); 1946 vect_QActions[4]->setIconVisibleInMenu(true); 1947 QObject::connect(vect_QActions[4], SIGNAL(triggered()), view, SLOT(resetZoom())); 1948 1949 vect_QActions[5] = new QAction(QIcon(":/imgRegion-icon"), tr("Zoom x%1 (see label) (CTRL+X)").arg(threshold_zoom_img_region), this); 1950 vect_QActions[5]->setIconVisibleInMenu(true); 1951 QObject::connect(vect_QActions[5], SIGNAL(triggered()), view, SLOT(imgRegion())); 1952 1953 vect_QActions[6] = new QAction(QIcon(":/zoom_in-icon"), "Zoom in (CTRL++)", this); 1954 vect_QActions[6]->setIconVisibleInMenu(true); 1955 QObject::connect(vect_QActions[6], SIGNAL(triggered()), view, SLOT(ZoomIn())); 1956 1957 vect_QActions[7] = new QAction(QIcon(":/zoom_out-icon"), "Zoom out (CTRL+-)", this); 1958 vect_QActions[7]->setIconVisibleInMenu(true); 1959 QObject::connect(vect_QActions[7], SIGNAL(triggered()), view, SLOT(ZoomOut())); 1960 1961 vect_QActions[8] = new QAction(QIcon(":/save-icon"), "Save current image (CTRL+S)", this); 1962 vect_QActions[8]->setIconVisibleInMenu(true); 1963 QObject::connect(vect_QActions[8], SIGNAL(triggered()), view, SLOT(saveView())); 1964 1965 vect_QActions[9] = new QAction(QIcon(":/properties-icon"), "Display properties window (CTRL+P)", this); 1966 vect_QActions[9]->setIconVisibleInMenu(true); 1967 QObject::connect(vect_QActions[9], SIGNAL(triggered()), this, SLOT(displayPropertiesWin())); 1968 1969 if (global_control_panel->myLayout->count() == 0) 1970 vect_QActions[9]->setDisabled(true); 1971 } 1972 1973 1974 void CvWindow::createShortcuts() 1975 { 1976 vect_QShortcuts.resize(10); 1977 1978 QWidget* view = myView->getWidget(); 1979 1980 vect_QShortcuts[0] = new QShortcut(shortcut_panning_left, this); 1981 QObject::connect(vect_QShortcuts[0], SIGNAL(activated()), view, SLOT(siftWindowOnLeft())); 1982 1983 vect_QShortcuts[1] = new QShortcut(shortcut_panning_right, this); 1984 QObject::connect(vect_QShortcuts[1], SIGNAL(activated()), view, SLOT(siftWindowOnRight())); 1985 1986 vect_QShortcuts[2] = new QShortcut(shortcut_panning_up, this); 1987 QObject::connect(vect_QShortcuts[2], SIGNAL(activated()), view, SLOT(siftWindowOnUp())); 1988 1989 vect_QShortcuts[3] = new QShortcut(shortcut_panning_down, this); 1990 QObject::connect(vect_QShortcuts[3], SIGNAL(activated()), view, SLOT(siftWindowOnDown())); 1991 1992 vect_QShortcuts[4] = new QShortcut(shortcut_zoom_normal, this); 1993 QObject::connect(vect_QShortcuts[4], SIGNAL(activated()), view, SLOT(resetZoom())); 1994 1995 vect_QShortcuts[5] = new QShortcut(shortcut_zoom_imgRegion, this); 1996 QObject::connect(vect_QShortcuts[5], SIGNAL(activated()), view, SLOT(imgRegion())); 1997 1998 vect_QShortcuts[6] = new QShortcut(shortcut_zoom_in, this); 1999 QObject::connect(vect_QShortcuts[6], SIGNAL(activated()), view, SLOT(ZoomIn())); 2000 2001 vect_QShortcuts[7] = new QShortcut(shortcut_zoom_out, this); 2002 QObject::connect(vect_QShortcuts[7], SIGNAL(activated()), view, SLOT(ZoomOut())); 2003 2004 vect_QShortcuts[8] = new QShortcut(shortcut_save_img, this); 2005 QObject::connect(vect_QShortcuts[8], SIGNAL(activated()), view, SLOT(saveView())); 2006 2007 vect_QShortcuts[9] = new QShortcut(shortcut_properties_win, this); 2008 QObject::connect(vect_QShortcuts[9], SIGNAL(activated()), this, SLOT(displayPropertiesWin())); 2009 } 2010 2011 2012 void CvWindow::createToolBar() 2013 { 2014 myToolBar = new QToolBar(this); 2015 myToolBar->setFloatable(false); //is not a window 2016 myToolBar->setFixedHeight(28); 2017 myToolBar->setMinimumWidth(1); 2018 2019 foreach (QAction *a, vect_QActions) 2020 myToolBar->addAction(a); 2021 } 2022 2023 2024 void CvWindow::createStatusBar() 2025 { 2026 myStatusBar = new QStatusBar(this); 2027 myStatusBar->setSizeGripEnabled(false); 2028 myStatusBar->setFixedHeight(20); 2029 myStatusBar->setMinimumWidth(1); 2030 myStatusBar_msg = new QLabel; 2031 2032 //I comment this because if we change the style, myview (the picture) 2033 //will not be the correct size anymore (will lost 2 pixel because of the borders) 2034 2035 //myStatusBar_msg->setFrameStyle(QFrame::Raised); 2036 2037 myStatusBar_msg->setAlignment(Qt::AlignHCenter); 2038 myStatusBar->addWidget(myStatusBar_msg); 2039 } 2040 2041 2042 void CvWindow::hideTools() 2043 { 2044 if (myToolBar) 2045 myToolBar->hide(); 2046 2047 if (myStatusBar) 2048 myStatusBar->hide(); 2049 2050 if (global_control_panel) 2051 global_control_panel->hide(); 2052 } 2053 2054 2055 void CvWindow::showTools() 2056 { 2057 if (myToolBar) 2058 myToolBar->show(); 2059 2060 if (myStatusBar) 2061 myStatusBar->show(); 2062 } 2063 2064 2065 CvWinProperties* CvWindow::createParameterWindow() 2066 { 2067 QString name_paraWindow = QFileInfo(QApplication::applicationFilePath()).fileName() + " settings"; 2068 2069 CvWinProperties* result = new CvWinProperties(name_paraWindow, guiMainThread); 2070 2071 return result; 2072 } 2073 2074 2075 void CvWindow::displayPropertiesWin() 2076 { 2077 if (global_control_panel->isHidden()) 2078 global_control_panel->show(); 2079 else 2080 global_control_panel->hide(); 2081 } 2082 2083 2084 //Need more test here ! 2085 void CvWindow::keyPressEvent(QKeyEvent *evnt) 2086 { 2087 //see http://doc.trolltech.com/4.6/qt.html#Key-enum 2088 int key = evnt->key(); 2089 2090 Qt::Key qtkey = static_cast<Qt::Key>(key); 2091 char asciiCode = QTest::keyToAscii(qtkey); 2092 if (asciiCode != 0) 2093 key = static_cast<int>(asciiCode); 2094 else 2095 key = evnt->nativeVirtualKey(); //same codes as returned by GTK-based backend 2096 2097 //control plus (Z, +, -, up, down, left, right) are used for zoom/panning functions 2098 if (evnt->modifiers() != Qt::ControlModifier) 2099 { 2100 mutexKey.lock(); 2101 last_key = key; 2102 mutexKey.unlock(); 2103 key_pressed.wakeAll(); 2104 //evnt->accept(); 2105 } 2106 2107 QWidget::keyPressEvent(evnt); 2108 } 2109 2110 2111 void CvWindow::icvLoadControlPanel() 2112 { 2113 QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName() + " control panel"); 2114 2115 int bsize = settings.beginReadArray("bars"); 2116 2117 if (bsize == global_control_panel->myLayout->layout()->count()) 2118 { 2119 for (int i = 0; i < bsize; ++i) 2120 { 2121 CvBar* t = (CvBar*) global_control_panel->myLayout->layout()->itemAt(i); 2122 settings.setArrayIndex(i); 2123 if (t->type == type_CvTrackbar) 2124 { 2125 if (t->name_bar == settings.value("namebar").toString()) 2126 { 2127 ((CvTrackbar*)t)->slider->setValue(settings.value("valuebar").toInt()); 2128 } 2129 } 2130 if (t->type == type_CvButtonbar) 2131 { 2132 int subsize = settings.beginReadArray(QString("buttonbar")+i); 2133 2134 if ( subsize == ((CvButtonbar*)t)->layout()->count() ) 2135 icvLoadButtonbar((CvButtonbar*)t,&settings); 2136 2137 settings.endArray(); 2138 } 2139 } 2140 } 2141 2142 settings.endArray(); 2143 } 2144 2145 2146 void CvWindow::icvSaveControlPanel() 2147 { 2148 QSettings settings("OpenCV2", QFileInfo(QApplication::applicationFilePath()).fileName()+" control panel"); 2149 2150 settings.beginWriteArray("bars"); 2151 2152 for (int i = 0; i < global_control_panel->myLayout->layout()->count(); ++i) 2153 { 2154 CvBar* t = (CvBar*) global_control_panel->myLayout->layout()->itemAt(i); 2155 settings.setArrayIndex(i); 2156 if (t->type == type_CvTrackbar) 2157 { 2158 settings.setValue("namebar", QString(t->name_bar)); 2159 settings.setValue("valuebar",((CvTrackbar*)t)->slider->value()); 2160 } 2161 if (t->type == type_CvButtonbar) 2162 { 2163 settings.beginWriteArray(QString("buttonbar")+i); 2164 icvSaveButtonbar((CvButtonbar*)t,&settings); 2165 settings.endArray(); 2166 } 2167 } 2168 2169 settings.endArray(); 2170 } 2171 2172 2173 void CvWindow::icvSaveButtonbar(CvButtonbar* b, QSettings* settings) 2174 { 2175 for (int i = 0, count = b->layout()->count(); i < count; ++i) 2176 { 2177 settings->setArrayIndex(i); 2178 2179 QWidget* temp = (QWidget*) b->layout()->itemAt(i)->widget(); 2180 QString myclass(QLatin1String(temp->metaObject()->className())); 2181 2182 if (myclass == "CvPushButton") 2183 { 2184 CvPushButton* button = (CvPushButton*) temp; 2185 settings->setValue("namebutton", button->text()); 2186 settings->setValue("valuebutton", int(button->isChecked())); 2187 } 2188 else if (myclass == "CvCheckBox") 2189 { 2190 CvCheckBox* button = (CvCheckBox*) temp; 2191 settings->setValue("namebutton", button->text()); 2192 settings->setValue("valuebutton", int(button->isChecked())); 2193 } 2194 else if (myclass == "CvRadioButton") 2195 { 2196 CvRadioButton* button = (CvRadioButton*) temp; 2197 settings->setValue("namebutton", button->text()); 2198 settings->setValue("valuebutton", int(button->isChecked())); 2199 } 2200 } 2201 } 2202 2203 2204 void CvWindow::icvLoadButtonbar(CvButtonbar* b, QSettings* settings) 2205 { 2206 for (int i = 0, count = b->layout()->count(); i < count; ++i) 2207 { 2208 settings->setArrayIndex(i); 2209 2210 QWidget* temp = (QWidget*) b->layout()->itemAt(i)->widget(); 2211 QString myclass(QLatin1String(temp->metaObject()->className())); 2212 2213 if (myclass == "CvPushButton") 2214 { 2215 CvPushButton* button = (CvPushButton*) temp; 2216 2217 if (button->text() == settings->value("namebutton").toString()) 2218 button->setChecked(settings->value("valuebutton").toInt()); 2219 } 2220 else if (myclass == "CvCheckBox") 2221 { 2222 CvCheckBox* button = (CvCheckBox*) temp; 2223 2224 if (button->text() == settings->value("namebutton").toString()) 2225 button->setChecked(settings->value("valuebutton").toInt()); 2226 } 2227 else if (myclass == "CvRadioButton") 2228 { 2229 CvRadioButton* button = (CvRadioButton*) temp; 2230 2231 if (button->text() == settings->value("namebutton").toString()) 2232 button->setChecked(settings->value("valuebutton").toInt()); 2233 } 2234 2235 } 2236 } 2237 2238 2239 void CvWindow::icvLoadTrackbars(QSettings* settings) 2240 { 2241 int bsize = settings->beginReadArray("trackbars"); 2242 2243 //trackbar are saved in the same order, so no need to use icvFindTrackbarByName 2244 2245 if (myBarLayout->layout()->count() == bsize) //if not the same number, the window saved and loaded is not the same (nb trackbar not equal) 2246 { 2247 for (int i = 0; i < bsize; ++i) 2248 { 2249 settings->setArrayIndex(i); 2250 2251 CvTrackbar* t = (CvTrackbar*) myBarLayout->layout()->itemAt(i); 2252 2253 if (t->name_bar == settings->value("name").toString()) 2254 t->slider->setValue(settings->value("value").toInt()); 2255 2256 } 2257 } 2258 2259 settings->endArray(); 2260 } 2261 2262 2263 void CvWindow::icvSaveTrackbars(QSettings* settings) 2264 { 2265 settings->beginWriteArray("trackbars"); 2266 2267 for (int i = 0; i < myBarLayout->layout()->count(); ++i) 2268 { 2269 settings->setArrayIndex(i); 2270 2271 CvTrackbar* t = (CvTrackbar*) myBarLayout->layout()->itemAt(i); 2272 2273 settings->setValue("name", t->name_bar); 2274 settings->setValue("value", t->slider->value()); 2275 } 2276 2277 settings->endArray(); 2278 } 2279 2280 2281 ////////////////////////////////////////////////////// 2282 // DefaultViewPort 2283 2284 2285 DefaultViewPort::DefaultViewPort(CvWindow* arg, int arg2) : QGraphicsView(arg), image2Draw_mat(0) 2286 { 2287 centralWidget = arg; 2288 param_keepRatio = arg2; 2289 2290 setContentsMargins(0, 0, 0, 0); 2291 setMinimumSize(1, 1); 2292 setAlignment(Qt::AlignHCenter); 2293 2294 setObjectName(QString::fromUtf8("graphicsView")); 2295 2296 timerDisplay = new QTimer(this); 2297 timerDisplay->setSingleShot(true); 2298 connect(timerDisplay, SIGNAL(timeout()), this, SLOT(stopDisplayInfo())); 2299 2300 drawInfo = false; 2301 positionGrabbing = QPointF(0, 0); 2302 positionCorners = QRect(0, 0, size().width(), size().height()); 2303 2304 on_mouse = 0; 2305 on_mouse_param = 0; 2306 mouseCoordinate = QPoint(-1, -1); 2307 2308 //no border 2309 setStyleSheet( "QGraphicsView { border-style: none; }" ); 2310 2311 image2Draw_mat = cvCreateMat(viewport()->height(), viewport()->width(), CV_8UC3); 2312 cvZero(image2Draw_mat); 2313 2314 nbChannelOriginImage = 0; 2315 2316 setInteractive(false); 2317 setMouseTracking(true); //receive mouse event everytime 2318 } 2319 2320 2321 DefaultViewPort::~DefaultViewPort() 2322 { 2323 if (image2Draw_mat) 2324 cvReleaseMat(&image2Draw_mat); 2325 } 2326 2327 2328 QWidget* DefaultViewPort::getWidget() 2329 { 2330 return this; 2331 } 2332 2333 2334 void DefaultViewPort::setMouseCallBack(CvMouseCallback m, void* param) 2335 { 2336 on_mouse = m; 2337 2338 on_mouse_param = param; 2339 } 2340 2341 void DefaultViewPort::writeSettings(QSettings& settings) 2342 { 2343 settings.setValue("matrix_view.m11", param_matrixWorld.m11()); 2344 settings.setValue("matrix_view.m12", param_matrixWorld.m12()); 2345 settings.setValue("matrix_view.m13", param_matrixWorld.m13()); 2346 settings.setValue("matrix_view.m21", param_matrixWorld.m21()); 2347 settings.setValue("matrix_view.m22", param_matrixWorld.m22()); 2348 settings.setValue("matrix_view.m23", param_matrixWorld.m23()); 2349 settings.setValue("matrix_view.m31", param_matrixWorld.m31()); 2350 settings.setValue("matrix_view.m32", param_matrixWorld.m32()); 2351 settings.setValue("matrix_view.m33", param_matrixWorld.m33()); 2352 } 2353 2354 2355 void DefaultViewPort::readSettings(QSettings& settings) 2356 { 2357 qreal m11 = settings.value("matrix_view.m11", param_matrixWorld.m11()).toDouble(); 2358 qreal m12 = settings.value("matrix_view.m12", param_matrixWorld.m12()).toDouble(); 2359 qreal m13 = settings.value("matrix_view.m13", param_matrixWorld.m13()).toDouble(); 2360 qreal m21 = settings.value("matrix_view.m21", param_matrixWorld.m21()).toDouble(); 2361 qreal m22 = settings.value("matrix_view.m22", param_matrixWorld.m22()).toDouble(); 2362 qreal m23 = settings.value("matrix_view.m23", param_matrixWorld.m23()).toDouble(); 2363 qreal m31 = settings.value("matrix_view.m31", param_matrixWorld.m31()).toDouble(); 2364 qreal m32 = settings.value("matrix_view.m32", param_matrixWorld.m32()).toDouble(); 2365 qreal m33 = settings.value("matrix_view.m33", param_matrixWorld.m33()).toDouble(); 2366 2367 param_matrixWorld = QTransform(m11, m12, m13, m21, m22, m23, m31, m32, m33); 2368 } 2369 2370 2371 double DefaultViewPort::getRatio() 2372 { 2373 return param_keepRatio; 2374 } 2375 2376 2377 void DefaultViewPort::setRatio(int flags) 2378 { 2379 if (getRatio() == flags) //nothing to do 2380 return; 2381 2382 //if valid flags 2383 if (flags == CV_WINDOW_FREERATIO || flags == CV_WINDOW_KEEPRATIO) 2384 { 2385 centralWidget->param_ratio_mode = flags; 2386 param_keepRatio = flags; 2387 updateGeometry(); 2388 viewport()->update(); 2389 } 2390 } 2391 2392 2393 void DefaultViewPort::updateImage(const CvArr* arr) 2394 { 2395 CV_Assert(arr); 2396 2397 CvMat* mat, stub; 2398 int origin = 0; 2399 2400 if (CV_IS_IMAGE_HDR(arr)) 2401 origin = ((IplImage*)arr)->origin; 2402 2403 mat = cvGetMat(arr, &stub); 2404 2405 if (!image2Draw_mat || !CV_ARE_SIZES_EQ(image2Draw_mat, mat)) 2406 { 2407 if (image2Draw_mat) 2408 cvReleaseMat(&image2Draw_mat); 2409 2410 //the image in ipl (to do a deep copy with cvCvtColor) 2411 image2Draw_mat = cvCreateMat(mat->rows, mat->cols, CV_8UC3); 2412 image2Draw_qt = QImage(image2Draw_mat->data.ptr, image2Draw_mat->cols, image2Draw_mat->rows, image2Draw_mat->step, QImage::Format_RGB888); 2413 2414 //use to compute mouse coordinate, I need to update the ratio here and in resizeEvent 2415 ratioX = width() / float(image2Draw_mat->cols); 2416 ratioY = height() / float(image2Draw_mat->rows); 2417 updateGeometry(); 2418 } 2419 2420 nbChannelOriginImage = cvGetElemType(mat); 2421 2422 cvConvertImage(mat, image2Draw_mat, (origin != 0 ? CV_CVTIMG_FLIP : 0) + CV_CVTIMG_SWAP_RB); 2423 2424 viewport()->update(); 2425 } 2426 2427 2428 void DefaultViewPort::startDisplayInfo(QString text, int delayms) 2429 { 2430 if (timerDisplay->isActive()) 2431 stopDisplayInfo(); 2432 2433 infoText = text; 2434 if (delayms > 0) timerDisplay->start(delayms); 2435 drawInfo = true; 2436 } 2437 2438 2439 void DefaultViewPort::setOpenGlDrawCallback(CvOpenGlDrawCallback /*callback*/, void* /*userdata*/) 2440 { 2441 CV_Error(CV_OpenGlNotSupported, "Window doesn't support OpenGL"); 2442 } 2443 2444 2445 void DefaultViewPort::makeCurrentOpenGlContext() 2446 { 2447 CV_Error(CV_OpenGlNotSupported, "Window doesn't support OpenGL"); 2448 } 2449 2450 2451 void DefaultViewPort::updateGl() 2452 { 2453 CV_Error(CV_OpenGlNotSupported, "Window doesn't support OpenGL"); 2454 } 2455 2456 2457 //Note: move 2 percent of the window 2458 void DefaultViewPort::siftWindowOnLeft() 2459 { 2460 float delta = 2 * width() / (100.0 * param_matrixWorld.m11()); 2461 moveView(QPointF(delta, 0)); 2462 } 2463 2464 2465 //Note: move 2 percent of the window 2466 void DefaultViewPort::siftWindowOnRight() 2467 { 2468 float delta = -2 * width() / (100.0 * param_matrixWorld.m11()); 2469 moveView(QPointF(delta, 0)); 2470 } 2471 2472 2473 //Note: move 2 percent of the window 2474 void DefaultViewPort::siftWindowOnUp() 2475 { 2476 float delta = 2 * height() / (100.0 * param_matrixWorld.m11()); 2477 moveView(QPointF(0, delta)); 2478 } 2479 2480 2481 //Note: move 2 percent of the window 2482 void DefaultViewPort::siftWindowOnDown() 2483 { 2484 float delta = -2 * height() / (100.0 * param_matrixWorld.m11()); 2485 moveView(QPointF(0, delta)); 2486 } 2487 2488 2489 void DefaultViewPort::imgRegion() 2490 { 2491 scaleView((threshold_zoom_img_region / param_matrixWorld.m11() - 1) * 5, QPointF(size().width() / 2, size().height() / 2)); 2492 } 2493 2494 2495 void DefaultViewPort::resetZoom() 2496 { 2497 param_matrixWorld.reset(); 2498 controlImagePosition(); 2499 } 2500 2501 2502 void DefaultViewPort::ZoomIn() 2503 { 2504 scaleView(0.5, QPointF(size().width() / 2, size().height() / 2)); 2505 } 2506 2507 2508 void DefaultViewPort::ZoomOut() 2509 { 2510 scaleView(-0.5, QPointF(size().width() / 2, size().height() / 2)); 2511 } 2512 2513 2514 //can save as JPG, JPEG, BMP, PNG 2515 void DefaultViewPort::saveView() 2516 { 2517 QDate date_d = QDate::currentDate(); 2518 QString date_s = date_d.toString("dd.MM.yyyy"); 2519 QString name_s = centralWidget->windowTitle() + "_screenshot_" + date_s; 2520 2521 QString fileName = QFileDialog::getSaveFileName(this, tr("Save File %1").arg(name_s), name_s + ".png", tr("Images (*.png *.jpg *.bmp *.jpeg)")); 2522 2523 if (!fileName.isEmpty()) //save the picture 2524 { 2525 QString extension = fileName.right(3); 2526 2527 // Create a new pixmap to render the viewport into 2528 QPixmap viewportPixmap(viewport()->size()); 2529 viewport()->render(&viewportPixmap); 2530 2531 // Save it.. 2532 if (QString::compare(extension, "png", Qt::CaseInsensitive) == 0) 2533 { 2534 viewportPixmap.save(fileName, "PNG"); 2535 return; 2536 } 2537 2538 if (QString::compare(extension, "jpg", Qt::CaseInsensitive) == 0) 2539 { 2540 viewportPixmap.save(fileName, "JPG"); 2541 return; 2542 } 2543 2544 if (QString::compare(extension, "bmp", Qt::CaseInsensitive) == 0) 2545 { 2546 viewportPixmap.save(fileName, "BMP"); 2547 return; 2548 } 2549 2550 if (QString::compare(extension, "jpeg", Qt::CaseInsensitive) == 0) 2551 { 2552 viewportPixmap.save(fileName, "JPEG"); 2553 return; 2554 } 2555 2556 CV_Error(CV_StsNullPtr, "file extension not recognized, please choose between JPG, JPEG, BMP or PNG"); 2557 } 2558 } 2559 2560 2561 void DefaultViewPort::contextMenuEvent(QContextMenuEvent* evnt) 2562 { 2563 if (centralWidget->vect_QActions.size() > 0) 2564 { 2565 QMenu menu(this); 2566 2567 foreach (QAction *a, centralWidget->vect_QActions) 2568 menu.addAction(a); 2569 2570 menu.exec(evnt->globalPos()); 2571 } 2572 } 2573 2574 2575 void DefaultViewPort::resizeEvent(QResizeEvent* evnt) 2576 { 2577 controlImagePosition(); 2578 2579 //use to compute mouse coordinate, I need to update the ratio here and in resizeEvent 2580 ratioX = width() / float(image2Draw_mat->cols); 2581 ratioY = height() / float(image2Draw_mat->rows); 2582 2583 if (param_keepRatio == CV_WINDOW_KEEPRATIO)//to keep the same aspect ratio 2584 { 2585 QSize newSize = QSize(image2Draw_mat->cols, image2Draw_mat->rows); 2586 newSize.scale(evnt->size(), Qt::KeepAspectRatio); 2587 2588 //imageWidth/imageHeight = newWidth/newHeight +/- epsilon 2589 //ratioX = ratioY +/- epsilon 2590 //||ratioX - ratioY|| = epsilon 2591 if (fabs(ratioX - ratioY) * 100 > ratioX) //avoid infinity loop / epsilon = 1% of ratioX 2592 { 2593 resize(newSize); 2594 2595 //move to the middle 2596 //newSize get the delta offset to place the picture in the middle of its parent 2597 newSize = (evnt->size() - newSize) / 2; 2598 2599 //if the toolbar is displayed, avoid drawing myview on top of it 2600 if (centralWidget->myToolBar) 2601 if(!centralWidget->myToolBar->isHidden()) 2602 newSize += QSize(0, centralWidget->myToolBar->height()); 2603 2604 move(newSize.width(), newSize.height()); 2605 } 2606 } 2607 2608 return QGraphicsView::resizeEvent(evnt); 2609 } 2610 2611 2612 void DefaultViewPort::wheelEvent(QWheelEvent* evnt) 2613 { 2614 scaleView(evnt->delta() / 240.0, evnt->pos()); 2615 viewport()->update(); 2616 } 2617 2618 2619 void DefaultViewPort::mousePressEvent(QMouseEvent* evnt) 2620 { 2621 int cv_event = -1, flags = 0; 2622 QPoint pt = evnt->pos(); 2623 2624 //icvmouseHandler: pass parameters for cv_event, flags 2625 icvmouseHandler(evnt, mouse_down, cv_event, flags); 2626 icvmouseProcessing(QPointF(pt), cv_event, flags); 2627 2628 if (param_matrixWorld.m11()>1) 2629 { 2630 setCursor(Qt::ClosedHandCursor); 2631 positionGrabbing = evnt->pos(); 2632 } 2633 2634 QWidget::mousePressEvent(evnt); 2635 } 2636 2637 2638 void DefaultViewPort::mouseReleaseEvent(QMouseEvent* evnt) 2639 { 2640 int cv_event = -1, flags = 0; 2641 QPoint pt = evnt->pos(); 2642 2643 //icvmouseHandler: pass parameters for cv_event, flags 2644 icvmouseHandler(evnt, mouse_up, cv_event, flags); 2645 icvmouseProcessing(QPointF(pt), cv_event, flags); 2646 2647 if (param_matrixWorld.m11()>1) 2648 setCursor(Qt::OpenHandCursor); 2649 2650 QWidget::mouseReleaseEvent(evnt); 2651 } 2652 2653 2654 void DefaultViewPort::mouseDoubleClickEvent(QMouseEvent* evnt) 2655 { 2656 int cv_event = -1, flags = 0; 2657 QPoint pt = evnt->pos(); 2658 2659 //icvmouseHandler: pass parameters for cv_event, flags 2660 icvmouseHandler(evnt, mouse_dbclick, cv_event, flags); 2661 icvmouseProcessing(QPointF(pt), cv_event, flags); 2662 2663 QWidget::mouseDoubleClickEvent(evnt); 2664 } 2665 2666 2667 void DefaultViewPort::mouseMoveEvent(QMouseEvent* evnt) 2668 { 2669 int cv_event = CV_EVENT_MOUSEMOVE, flags = 0; 2670 QPoint pt = evnt->pos(); 2671 2672 //icvmouseHandler: pass parameters for cv_event, flags 2673 icvmouseHandler(evnt, mouse_move, cv_event, flags); 2674 icvmouseProcessing(QPointF(pt), cv_event, flags); 2675 2676 if (param_matrixWorld.m11() > 1 && evnt->buttons() == Qt::LeftButton) 2677 { 2678 QPointF dxy = (pt - positionGrabbing)/param_matrixWorld.m11(); 2679 positionGrabbing = evnt->pos(); 2680 moveView(dxy); 2681 } 2682 2683 //I update the statusbar here because if the user does a cvWaitkey(0) (like with inpaint.cpp) 2684 //the status bar will only be repaint when a click occurs. 2685 if (centralWidget->myStatusBar) 2686 viewport()->update(); 2687 2688 QWidget::mouseMoveEvent(evnt); 2689 } 2690 2691 2692 void DefaultViewPort::paintEvent(QPaintEvent* evnt) 2693 { 2694 QPainter myPainter(viewport()); 2695 myPainter.setWorldTransform(param_matrixWorld); 2696 2697 draw2D(&myPainter); 2698 2699 //Now disable matrixWorld for overlay display 2700 myPainter.setWorldMatrixEnabled(false); 2701 2702 //overlay pixel values if zoomed in far enough 2703 if (param_matrixWorld.m11()*ratioX >= threshold_zoom_img_region && 2704 param_matrixWorld.m11()*ratioY >= threshold_zoom_img_region) 2705 { 2706 drawImgRegion(&myPainter); 2707 } 2708 2709 //in mode zoom/panning 2710 if (param_matrixWorld.m11() > 1) 2711 { 2712 drawViewOverview(&myPainter); 2713 } 2714 2715 //for information overlay 2716 if (drawInfo) 2717 drawInstructions(&myPainter); 2718 2719 //for statusbar 2720 if (centralWidget->myStatusBar) 2721 drawStatusBar(); 2722 2723 QGraphicsView::paintEvent(evnt); 2724 } 2725 2726 2727 void DefaultViewPort::stopDisplayInfo() 2728 { 2729 timerDisplay->stop(); 2730 drawInfo = false; 2731 } 2732 2733 2734 inline bool DefaultViewPort::isSameSize(IplImage* img1, IplImage* img2) 2735 { 2736 return img1->width == img2->width && img1->height == img2->height; 2737 } 2738 2739 2740 void DefaultViewPort::controlImagePosition() 2741 { 2742 qreal left, top, right, bottom; 2743 2744 //after check top-left, bottom right corner to avoid getting "out" during zoom/panning 2745 param_matrixWorld.map(0,0,&left,&top); 2746 2747 if (left > 0) 2748 { 2749 param_matrixWorld.translate(-left,0); 2750 left = 0; 2751 } 2752 if (top > 0) 2753 { 2754 param_matrixWorld.translate(0,-top); 2755 top = 0; 2756 } 2757 //------- 2758 2759 QSize sizeImage = size(); 2760 param_matrixWorld.map(sizeImage.width(),sizeImage.height(),&right,&bottom); 2761 if (right < sizeImage.width()) 2762 { 2763 param_matrixWorld.translate(sizeImage.width()-right,0); 2764 right = sizeImage.width(); 2765 } 2766 if (bottom < sizeImage.height()) 2767 { 2768 param_matrixWorld.translate(0,sizeImage.height()-bottom); 2769 bottom = sizeImage.height(); 2770 } 2771 2772 //save corner position 2773 positionCorners.setTopLeft(QPoint(left,top)); 2774 positionCorners.setBottomRight(QPoint(right,bottom)); 2775 //save also the inv matrix 2776 matrixWorld_inv = param_matrixWorld.inverted(); 2777 2778 //viewport()->update(); 2779 } 2780 2781 void DefaultViewPort::moveView(QPointF delta) 2782 { 2783 param_matrixWorld.translate(delta.x(),delta.y()); 2784 controlImagePosition(); 2785 viewport()->update(); 2786 } 2787 2788 //factor is -0.5 (zoom out) or 0.5 (zoom in) 2789 void DefaultViewPort::scaleView(qreal factor,QPointF center) 2790 { 2791 factor/=5;//-0.1 <-> 0.1 2792 factor+=1;//0.9 <-> 1.1 2793 2794 //limit zoom out --- 2795 if (param_matrixWorld.m11()==1 && factor < 1) 2796 return; 2797 2798 if (param_matrixWorld.m11()*factor<1) 2799 factor = 1/param_matrixWorld.m11(); 2800 2801 2802 //limit zoom int --- 2803 if (param_matrixWorld.m11()>100 && factor > 1) 2804 return; 2805 2806 //inverse the transform 2807 int a, b; 2808 matrixWorld_inv.map(center.x(),center.y(),&a,&b); 2809 2810 param_matrixWorld.translate(a-factor*a,b-factor*b); 2811 param_matrixWorld.scale(factor,factor); 2812 2813 controlImagePosition(); 2814 2815 //display new zoom 2816 if (centralWidget->myStatusBar) 2817 centralWidget->displayStatusBar(tr("Zoom: %1%").arg(param_matrixWorld.m11()*100),1000); 2818 2819 if (param_matrixWorld.m11()>1) 2820 setCursor(Qt::OpenHandCursor); 2821 else 2822 unsetCursor(); 2823 } 2824 2825 2826 //up, down, dclick, move 2827 void DefaultViewPort::icvmouseHandler(QMouseEvent *evnt, type_mouse_event category, int &cv_event, int &flags) 2828 { 2829 Qt::KeyboardModifiers modifiers = evnt->modifiers(); 2830 Qt::MouseButtons buttons = evnt->buttons(); 2831 2832 flags = 0; 2833 if(modifiers & Qt::ShiftModifier) 2834 flags |= CV_EVENT_FLAG_SHIFTKEY; 2835 if(modifiers & Qt::ControlModifier) 2836 flags |= CV_EVENT_FLAG_CTRLKEY; 2837 if(modifiers & Qt::AltModifier) 2838 flags |= CV_EVENT_FLAG_ALTKEY; 2839 2840 if(buttons & Qt::LeftButton) 2841 flags |= CV_EVENT_FLAG_LBUTTON; 2842 if(buttons & Qt::RightButton) 2843 flags |= CV_EVENT_FLAG_RBUTTON; 2844 if(buttons & Qt::MidButton) 2845 flags |= CV_EVENT_FLAG_MBUTTON; 2846 2847 cv_event = CV_EVENT_MOUSEMOVE; 2848 switch(evnt->button()) 2849 { 2850 case Qt::LeftButton: 2851 cv_event = tableMouseButtons[category][0]; 2852 flags |= CV_EVENT_FLAG_LBUTTON; 2853 break; 2854 case Qt::RightButton: 2855 cv_event = tableMouseButtons[category][1]; 2856 flags |= CV_EVENT_FLAG_RBUTTON; 2857 break; 2858 case Qt::MidButton: 2859 cv_event = tableMouseButtons[category][2]; 2860 flags |= CV_EVENT_FLAG_MBUTTON; 2861 break; 2862 default:; 2863 } 2864 } 2865 2866 2867 void DefaultViewPort::icvmouseProcessing(QPointF pt, int cv_event, int flags) 2868 { 2869 //to convert mouse coordinate 2870 qreal pfx, pfy; 2871 matrixWorld_inv.map(pt.x(),pt.y(),&pfx,&pfy); 2872 2873 mouseCoordinate.rx()=floor(pfx/ratioX); 2874 mouseCoordinate.ry()=floor(pfy/ratioY); 2875 2876 if (on_mouse) 2877 on_mouse( cv_event, mouseCoordinate.x(), 2878 mouseCoordinate.y(), flags, on_mouse_param ); 2879 } 2880 2881 2882 QSize DefaultViewPort::sizeHint() const 2883 { 2884 if(image2Draw_mat) 2885 return QSize(image2Draw_mat->cols, image2Draw_mat->rows); 2886 else 2887 return QGraphicsView::sizeHint(); 2888 } 2889 2890 2891 void DefaultViewPort::draw2D(QPainter *painter) 2892 { 2893 image2Draw_qt = QImage(image2Draw_mat->data.ptr, image2Draw_mat->cols, image2Draw_mat->rows,image2Draw_mat->step,QImage::Format_RGB888); 2894 painter->drawImage(QRect(0,0,viewport()->width(),viewport()->height()), image2Draw_qt, QRect(0,0, image2Draw_qt.width(), image2Draw_qt.height()) ); 2895 } 2896 2897 //only if CV_8UC1 or CV_8UC3 2898 void DefaultViewPort::drawStatusBar() 2899 { 2900 if (nbChannelOriginImage!=CV_8UC1 && nbChannelOriginImage!=CV_8UC3) 2901 return; 2902 2903 if (mouseCoordinate.x()>=0 && 2904 mouseCoordinate.y()>=0 && 2905 mouseCoordinate.x()<image2Draw_qt.width() && 2906 mouseCoordinate.y()<image2Draw_qt.height()) 2907 // if (mouseCoordinate.x()>=0 && mouseCoordinate.y()>=0) 2908 { 2909 QRgb rgbValue = image2Draw_qt.pixel(mouseCoordinate); 2910 2911 if (nbChannelOriginImage==CV_8UC3 ) 2912 { 2913 centralWidget->myStatusBar_msg->setText(tr("<font color='black'>(x=%1, y=%2) ~ </font>") 2914 .arg(mouseCoordinate.x()) 2915 .arg(mouseCoordinate.y())+ 2916 tr("<font color='red'>R:%3 </font>").arg(qRed(rgbValue))+//.arg(value.val[0])+ 2917 tr("<font color='green'>G:%4 </font>").arg(qGreen(rgbValue))+//.arg(value.val[1])+ 2918 tr("<font color='blue'>B:%5</font>").arg(qBlue(rgbValue))//.arg(value.val[2]) 2919 ); 2920 } 2921 2922 if (nbChannelOriginImage==CV_8UC1) 2923 { 2924 //all the channel have the same value (because of cvconvertimage), so only the r channel is dsplayed 2925 centralWidget->myStatusBar_msg->setText(tr("<font color='black'>(x=%1, y=%2) ~ </font>") 2926 .arg(mouseCoordinate.x()) 2927 .arg(mouseCoordinate.y())+ 2928 tr("<font color='grey'>L:%3 </font>").arg(qRed(rgbValue)) 2929 ); 2930 } 2931 } 2932 } 2933 2934 //accept only CV_8UC1 and CV_8UC8 image for now 2935 void DefaultViewPort::drawImgRegion(QPainter *painter) 2936 { 2937 if (nbChannelOriginImage!=CV_8UC1 && nbChannelOriginImage!=CV_8UC3) 2938 return; 2939 2940 double pixel_width = param_matrixWorld.m11()*ratioX; 2941 double pixel_height = param_matrixWorld.m11()*ratioY; 2942 2943 qreal offsetX = param_matrixWorld.dx()/pixel_width; 2944 offsetX = offsetX - floor(offsetX); 2945 qreal offsetY = param_matrixWorld.dy()/pixel_height; 2946 offsetY = offsetY - floor(offsetY); 2947 2948 QSize view = size(); 2949 QVarLengthArray<QLineF, 30> linesX; 2950 for (qreal _x = offsetX*pixel_width; _x < view.width(); _x += pixel_width ) 2951 linesX.append(QLineF(_x, 0, _x, view.height())); 2952 2953 QVarLengthArray<QLineF, 30> linesY; 2954 for (qreal _y = offsetY*pixel_height; _y < view.height(); _y += pixel_height ) 2955 linesY.append(QLineF(0, _y, view.width(), _y)); 2956 2957 2958 QFont f = painter->font(); 2959 int original_font_size = f.pointSize(); 2960 //change font size 2961 //f.setPointSize(4+(param_matrixWorld.m11()-threshold_zoom_img_region)/5); 2962 f.setPixelSize(10+(pixel_height-threshold_zoom_img_region)/5); 2963 painter->setFont(f); 2964 2965 2966 for (int j=-1;j<height()/pixel_height;j++)//-1 because display the pixels top rows left columns 2967 for (int i=-1;i<width()/pixel_width;i++)//-1 2968 { 2969 // Calculate top left of the pixel's position in the viewport (screen space) 2970 QPointF pos_in_view((i+offsetX)*pixel_width, (j+offsetY)*pixel_height); 2971 2972 // Calculate top left of the pixel's position in the image (image space) 2973 QPointF pos_in_image = matrixWorld_inv.map(pos_in_view);// Top left of pixel in view 2974 pos_in_image.rx() = pos_in_image.x()/ratioX; 2975 pos_in_image.ry() = pos_in_image.y()/ratioY; 2976 QPoint point_in_image(pos_in_image.x() + 0.5f,pos_in_image.y() + 0.5f);// Add 0.5 for rounding 2977 2978 QRgb rgbValue; 2979 if (image2Draw_qt.valid(point_in_image)) 2980 rgbValue = image2Draw_qt.pixel(point_in_image); 2981 else 2982 rgbValue = qRgb(0,0,0); 2983 2984 if (nbChannelOriginImage==CV_8UC3) 2985 { 2986 //for debug 2987 /* 2988 val = tr("%1 %2").arg(point2.x()).arg(point2.y()); 2989 painter->setPen(QPen(Qt::black, 1)); 2990 painter->drawText(QRect(point1.x(),point1.y(),param_matrixWorld.m11(),param_matrixWorld.m11()/2), 2991 Qt::AlignCenter, val); 2992 */ 2993 QString val; 2994 2995 val = tr("%1").arg(qRed(rgbValue)); 2996 painter->setPen(QPen(Qt::red, 1)); 2997 painter->drawText(QRect(pos_in_view.x(),pos_in_view.y(),pixel_width,pixel_height/3), 2998 Qt::AlignCenter, val); 2999 3000 val = tr("%1").arg(qGreen(rgbValue)); 3001 painter->setPen(QPen(Qt::green, 1)); 3002 painter->drawText(QRect(pos_in_view.x(),pos_in_view.y()+pixel_height/3,pixel_width,pixel_height/3), 3003 Qt::AlignCenter, val); 3004 3005 val = tr("%1").arg(qBlue(rgbValue)); 3006 painter->setPen(QPen(Qt::blue, 1)); 3007 painter->drawText(QRect(pos_in_view.x(),pos_in_view.y()+2*pixel_height/3,pixel_width,pixel_height/3), 3008 Qt::AlignCenter, val); 3009 3010 } 3011 3012 if (nbChannelOriginImage==CV_8UC1) 3013 { 3014 QString val = tr("%1").arg(qRed(rgbValue)); 3015 painter->drawText(QRect(pos_in_view.x(),pos_in_view.y(),pixel_width,pixel_height), 3016 Qt::AlignCenter, val); 3017 } 3018 } 3019 3020 painter->setPen(QPen(Qt::black, 1)); 3021 painter->drawLines(linesX.data(), linesX.size()); 3022 painter->drawLines(linesY.data(), linesY.size()); 3023 3024 //restore font size 3025 f.setPointSize(original_font_size); 3026 painter->setFont(f); 3027 3028 } 3029 3030 void DefaultViewPort::drawViewOverview(QPainter *painter) 3031 { 3032 QSize viewSize = size(); 3033 viewSize.scale ( 100, 100,Qt::KeepAspectRatio ); 3034 3035 const int margin = 5; 3036 3037 //draw the image's location 3038 painter->setBrush(QColor(0, 0, 0, 127)); 3039 painter->setPen(Qt::darkGreen); 3040 painter->drawRect(QRect(width()-viewSize.width()-margin, 0,viewSize.width(),viewSize.height())); 3041 3042 //daw the view's location inside the image 3043 qreal ratioSize = 1/param_matrixWorld.m11(); 3044 qreal ratioWindow = (qreal)(viewSize.height())/(qreal)(size().height()); 3045 painter->setPen(Qt::darkBlue); 3046 painter->drawRect(QRectF(width()-viewSize.width()-positionCorners.left()*ratioSize*ratioWindow-margin, 3047 -positionCorners.top()*ratioSize*ratioWindow, 3048 (viewSize.width()-1)*ratioSize, 3049 (viewSize.height()-1)*ratioSize) 3050 ); 3051 } 3052 3053 void DefaultViewPort::drawInstructions(QPainter *painter) 3054 { 3055 QFontMetrics metrics = QFontMetrics(font()); 3056 int border = qMax(4, metrics.leading()); 3057 3058 QRect qrect = metrics.boundingRect(0, 0, width() - 2*border, int(height()*0.125), 3059 Qt::AlignCenter | Qt::TextWordWrap, infoText); 3060 painter->setRenderHint(QPainter::TextAntialiasing); 3061 painter->fillRect(QRect(0, 0, width(), qrect.height() + 2*border), 3062 QColor(0, 0, 0, 127)); 3063 painter->setPen(Qt::white); 3064 painter->fillRect(QRect(0, 0, width(), qrect.height() + 2*border), 3065 QColor(0, 0, 0, 127)); 3066 3067 painter->drawText((width() - qrect.width())/2, border, 3068 qrect.width(), qrect.height(), 3069 Qt::AlignCenter | Qt::TextWordWrap, infoText); 3070 } 3071 3072 3073 void DefaultViewPort::setSize(QSize /*size_*/) 3074 { 3075 } 3076 3077 3078 ////////////////////////////////////////////////////// 3079 // OpenGlViewPort 3080 3081 #ifdef HAVE_QT_OPENGL 3082 3083 OpenGlViewPort::OpenGlViewPort(QWidget* _parent) : QGLWidget(_parent), size(-1, -1) 3084 { 3085 mouseCallback = 0; 3086 mouseData = 0; 3087 3088 glDrawCallback = 0; 3089 glDrawData = 0; 3090 } 3091 3092 OpenGlViewPort::~OpenGlViewPort() 3093 { 3094 } 3095 3096 QWidget* OpenGlViewPort::getWidget() 3097 { 3098 return this; 3099 } 3100 3101 void OpenGlViewPort::setMouseCallBack(CvMouseCallback callback, void* param) 3102 { 3103 mouseCallback = callback; 3104 mouseData = param; 3105 } 3106 3107 void OpenGlViewPort::writeSettings(QSettings& /*settings*/) 3108 { 3109 } 3110 3111 void OpenGlViewPort::readSettings(QSettings& /*settings*/) 3112 { 3113 } 3114 3115 double OpenGlViewPort::getRatio() 3116 { 3117 return (double)width() / height(); 3118 } 3119 3120 void OpenGlViewPort::setRatio(int /*flags*/) 3121 { 3122 } 3123 3124 void OpenGlViewPort::updateImage(const CvArr* /*arr*/) 3125 { 3126 } 3127 3128 void OpenGlViewPort::startDisplayInfo(QString /*text*/, int /*delayms*/) 3129 { 3130 } 3131 3132 void OpenGlViewPort::setOpenGlDrawCallback(CvOpenGlDrawCallback callback, void* userdata) 3133 { 3134 glDrawCallback = callback; 3135 glDrawData = userdata; 3136 } 3137 3138 void OpenGlViewPort::makeCurrentOpenGlContext() 3139 { 3140 makeCurrent(); 3141 } 3142 3143 void OpenGlViewPort::updateGl() 3144 { 3145 QGLWidget::updateGL(); 3146 } 3147 3148 void OpenGlViewPort::initializeGL() 3149 { 3150 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); 3151 } 3152 3153 void OpenGlViewPort::resizeGL(int w, int h) 3154 { 3155 glViewport(0, 0, w, h); 3156 } 3157 3158 void OpenGlViewPort::paintGL() 3159 { 3160 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 3161 3162 if (glDrawCallback) 3163 glDrawCallback(glDrawData); 3164 } 3165 3166 void OpenGlViewPort::mousePressEvent(QMouseEvent* evnt) 3167 { 3168 int cv_event = -1, flags = 0; 3169 QPoint pt = evnt->pos(); 3170 3171 icvmouseHandler(evnt, mouse_down, cv_event, flags); 3172 icvmouseProcessing(QPointF(pt), cv_event, flags); 3173 3174 QGLWidget::mousePressEvent(evnt); 3175 } 3176 3177 3178 void OpenGlViewPort::mouseReleaseEvent(QMouseEvent* evnt) 3179 { 3180 int cv_event = -1, flags = 0; 3181 QPoint pt = evnt->pos(); 3182 3183 icvmouseHandler(evnt, mouse_up, cv_event, flags); 3184 icvmouseProcessing(QPointF(pt), cv_event, flags); 3185 3186 QGLWidget::mouseReleaseEvent(evnt); 3187 } 3188 3189 3190 void OpenGlViewPort::mouseDoubleClickEvent(QMouseEvent* evnt) 3191 { 3192 int cv_event = -1, flags = 0; 3193 QPoint pt = evnt->pos(); 3194 3195 icvmouseHandler(evnt, mouse_dbclick, cv_event, flags); 3196 icvmouseProcessing(QPointF(pt), cv_event, flags); 3197 3198 QGLWidget::mouseDoubleClickEvent(evnt); 3199 } 3200 3201 3202 void OpenGlViewPort::mouseMoveEvent(QMouseEvent* evnt) 3203 { 3204 int cv_event = CV_EVENT_MOUSEMOVE, flags = 0; 3205 QPoint pt = evnt->pos(); 3206 3207 //icvmouseHandler: pass parameters for cv_event, flags 3208 icvmouseHandler(evnt, mouse_move, cv_event, flags); 3209 icvmouseProcessing(QPointF(pt), cv_event, flags); 3210 3211 QGLWidget::mouseMoveEvent(evnt); 3212 } 3213 3214 void OpenGlViewPort::icvmouseHandler(QMouseEvent* evnt, type_mouse_event category, int& cv_event, int& flags) 3215 { 3216 Qt::KeyboardModifiers modifiers = evnt->modifiers(); 3217 Qt::MouseButtons buttons = evnt->buttons(); 3218 3219 flags = 0; 3220 if (modifiers & Qt::ShiftModifier) 3221 flags |= CV_EVENT_FLAG_SHIFTKEY; 3222 if (modifiers & Qt::ControlModifier) 3223 flags |= CV_EVENT_FLAG_CTRLKEY; 3224 if (modifiers & Qt::AltModifier) 3225 flags |= CV_EVENT_FLAG_ALTKEY; 3226 3227 if (buttons & Qt::LeftButton) 3228 flags |= CV_EVENT_FLAG_LBUTTON; 3229 if (buttons & Qt::RightButton) 3230 flags |= CV_EVENT_FLAG_RBUTTON; 3231 if (buttons & Qt::MidButton) 3232 flags |= CV_EVENT_FLAG_MBUTTON; 3233 3234 cv_event = CV_EVENT_MOUSEMOVE; 3235 switch (evnt->button()) 3236 { 3237 case Qt::LeftButton: 3238 cv_event = tableMouseButtons[category][0]; 3239 flags |= CV_EVENT_FLAG_LBUTTON; 3240 break; 3241 3242 case Qt::RightButton: 3243 cv_event = tableMouseButtons[category][1]; 3244 flags |= CV_EVENT_FLAG_RBUTTON; 3245 break; 3246 3247 case Qt::MidButton: 3248 cv_event = tableMouseButtons[category][2]; 3249 flags |= CV_EVENT_FLAG_MBUTTON; 3250 break; 3251 3252 default: 3253 ; 3254 } 3255 } 3256 3257 3258 void OpenGlViewPort::icvmouseProcessing(QPointF pt, int cv_event, int flags) 3259 { 3260 if (mouseCallback) 3261 mouseCallback(cv_event, pt.x(), pt.y(), flags, mouseData); 3262 } 3263 3264 3265 QSize OpenGlViewPort::sizeHint() const 3266 { 3267 if (size.width() > 0 && size.height() > 0) 3268 return size; 3269 3270 return QGLWidget::sizeHint(); 3271 } 3272 3273 void OpenGlViewPort::setSize(QSize size_) 3274 { 3275 size = size_; 3276 updateGeometry(); 3277 } 3278 3279 #endif 3280 3281 #endif // HAVE_QT 3282