ImageDisplay.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. /*
  2. * NICE-Core - efficient algebra and computer vision methods
  3. * - libimagedisplay - A library for image and video display
  4. * See file License for license information.
  5. */
  6. #include "core/imagedisplay/ImageDisplay.h"
  7. #include <iostream>
  8. #ifdef NICE_USELIB_GLUT
  9. #ifdef __APPLE__
  10. #include <OpenGL/gl.h>
  11. #include <OpenGL/glu.h>
  12. #else
  13. #include <GL/glut.h>
  14. #endif
  15. #endif
  16. #include <qcursor.h>
  17. #include <q3filedialog.h>
  18. #include <qapplication.h>
  19. #include <qpushbutton.h>
  20. #include <qlineedit.h>
  21. #include <q3buttongroup.h>
  22. #include <qcheckbox.h>
  23. //Added by qt3to4:
  24. #include <QContextMenuEvent>
  25. #include <QMouseEvent>
  26. #include <core/basics/Exception.h>
  27. #include <core/basics/FileName.h>
  28. #include <core/imagedisplay/QtFramework.h>
  29. #include <core/imagedisplay/ImageDisplayManager.h>
  30. #include <core/imagedisplay/OverlayColors.h>
  31. // we need this function for overlays
  32. #include <core/image/Convert.h>
  33. namespace NICE {
  34. ImageDisplay::ImageDisplay ( QWidget* parent, const char* name, Qt::WFlags flags )
  35. : QGLWidget ( parent, name, NULL, flags ),
  36. image ( NULL ),
  37. colorImageBuffer ( NULL ),
  38. grayImageBuffer ( NULL ),
  39. copied ( false ),
  40. isDragging ( false ),
  41. buf_overlayImage ( NULL )
  42. {
  43. if ( parent == NULL ) {
  44. ImageDisplayManager::instance().registerWidget ( this );
  45. }
  46. updateGL();
  47. }
  48. ImageDisplay::~ImageDisplay() {
  49. //ImageDisplayManager::instance().unregisterWidget(this);
  50. if ( copied && colorImageBuffer != NULL ) {
  51. delete colorImageBuffer;
  52. }
  53. if ( copied && grayImageBuffer != NULL ) {
  54. delete grayImageBuffer;
  55. }
  56. if ( buf_overlayImage != NULL )
  57. delete [] buf_overlayImage;
  58. }
  59. void ImageDisplay::setImage ( const NICE::ColorImage* _image,
  60. const bool copy ) {
  61. frameRateCounter.newFrame();
  62. if ( frameRateCounter.getCounter() == 0 ) {
  63. doSetCaption();
  64. }
  65. if ( sequenceWriter.get() != NULL ) {
  66. sequenceWriter->writeColorImage ( *_image );
  67. }
  68. int oldImageWidth = 0;
  69. int oldImageHeight = 0;
  70. if ( image != NULL ) {
  71. oldImageWidth = image->width();
  72. oldImageHeight = image->height();
  73. }
  74. if ( copied && grayImageBuffer != NULL ) {
  75. delete grayImageBuffer;
  76. grayImageBuffer = NULL;
  77. }
  78. isColor = true;
  79. if ( copy ) {
  80. if ( copied && colorImageBuffer != NULL ) {
  81. if ( _image->width() != colorImageBuffer->width()
  82. || _image->height() != colorImageBuffer->height() ) {
  83. delete colorImageBuffer;
  84. colorImageBuffer
  85. = new NICE::ColorImage ( *_image, NICE::GrayColorImageCommonImplementation::noAlignment );
  86. } else {
  87. colorImageBuffer->copyFrom ( *_image, NICE::GrayColorImageCommonImplementation::noAlignment );
  88. }
  89. } else {
  90. copied = true;
  91. colorImageBuffer
  92. = new NICE::ColorImage ( *_image, NICE::GrayColorImageCommonImplementation::noAlignment );
  93. }
  94. image = colorImageBuffer;
  95. } else {
  96. if ( copied && colorImageBuffer != NULL ) {
  97. delete colorImageBuffer;
  98. colorImageBuffer = NULL;
  99. }
  100. image = _image;
  101. }
  102. if ( oldImageWidth != image->width() || oldImageHeight != image->height() ) {
  103. resize ( image->width(), image->height() );
  104. }
  105. updateGL();
  106. }
  107. void ImageDisplay::setImage ( const NICE::Image* _image,
  108. const bool copy ) {
  109. frameRateCounter.newFrame();
  110. if ( frameRateCounter.getCounter() == 0 ) {
  111. doSetCaption();
  112. }
  113. if ( sequenceWriter.get() != NULL ) {
  114. sequenceWriter->writeGrayImage ( *_image );
  115. }
  116. int oldImageWidth = 0;
  117. int oldImageHeight = 0;
  118. if ( image != NULL ) {
  119. oldImageWidth = image->width();
  120. oldImageHeight = image->height();
  121. }
  122. if ( copied && colorImageBuffer != NULL ) {
  123. delete colorImageBuffer;
  124. colorImageBuffer = NULL;
  125. }
  126. isColor = false;
  127. if ( copy ) {
  128. if ( copied && grayImageBuffer != NULL ) {
  129. if ( _image->width() != grayImageBuffer->width()
  130. || _image->height() != grayImageBuffer->height() ) {
  131. delete grayImageBuffer;
  132. grayImageBuffer
  133. = new NICE::Image ( *_image, NICE::GrayColorImageCommonImplementation::noAlignment );
  134. } else {
  135. grayImageBuffer->copyFrom ( *_image, NICE::GrayColorImageCommonImplementation::noAlignment );
  136. }
  137. } else {
  138. copied = true;
  139. grayImageBuffer
  140. = new NICE::Image ( *_image, NICE::GrayColorImageCommonImplementation::noAlignment );
  141. }
  142. image = grayImageBuffer;
  143. } else {
  144. if ( copied && grayImageBuffer != NULL ) {
  145. delete grayImageBuffer;
  146. grayImageBuffer = NULL;
  147. }
  148. image = _image;
  149. }
  150. if ( oldImageWidth != image->width() || oldImageHeight != image->height() ) {
  151. resize ( image->width(), image->height() );
  152. }
  153. updateGL();
  154. }
  155. void ImageDisplay::setOverlayImage ( const NICE::Image* overlayImage ) {
  156. bool alloc = false;
  157. if ( buf_overlayImage == NULL )
  158. alloc = true;
  159. else if ( ( overlayImageWidth != overlayImage->width() ) ||
  160. ( overlayImageHeight != overlayImage->height() ) )
  161. alloc = true;
  162. if ( alloc ) {
  163. if ( buf_overlayImage != NULL )
  164. delete [] buf_overlayImage;
  165. overlayImageWidth = overlayImage->width();
  166. overlayImageHeight = overlayImage->height();
  167. // RGBA image: 4 channels
  168. buf_overlayImage = new unsigned char[ overlayImageWidth *
  169. overlayImageHeight * 4 ];
  170. }
  171. long int k = 0;
  172. for ( int y = 0; y < overlayImage->height(); y++ ) {
  173. const unsigned char* end = overlayImage->getPixelPointerYEnd ( y );
  174. int colstep = overlayImage->columnStepsize();
  175. for ( const unsigned char* p = overlayImage->getPixelPointerY ( y ); p != end;
  176. p = ( const unsigned char * ) ( ( ( Ipp8u * ) p ) + colstep ) )
  177. {
  178. unsigned char overlayValue = *p;
  179. unsigned char r, g, b, alpha;
  180. if ( overlayValue <= 0 ) {
  181. r = 0;
  182. b = 0;
  183. g = 0;
  184. alpha = 0;
  185. } else {
  186. int colorValue = overlayValue % overlayColorTableNumEntries;
  187. r = overlayColorTable[colorValue][0];
  188. g = overlayColorTable[colorValue][1];
  189. b = overlayColorTable[colorValue][2];
  190. alpha = 255;
  191. }
  192. buf_overlayImage[k++] = r;
  193. buf_overlayImage[k++] = g;
  194. buf_overlayImage[k++] = b;
  195. buf_overlayImage[k++] = alpha;
  196. }
  197. }
  198. updateGL();
  199. }
  200. void ImageDisplay::repaint() {
  201. updateGL();
  202. }
  203. void ImageDisplay::paintGL() {
  204. #ifdef NICE_USELIB_GLUT
  205. setGLProjection();
  206. if ( image != NULL ) {
  207. glPixelStorei ( GL_PACK_ALIGNMENT, 1 );
  208. glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 );
  209. glPixelZoom ( ( GLfloat ) width() / ( ( GLfloat ) image->width() ),
  210. ( ( GLfloat ) - height() ) / ( ( GLfloat ) image->height() ) );
  211. glRasterPos2f ( 0, height() - 0.5 );
  212. if ( isColor ) {
  213. glDrawPixels ( image->width(), image->height(),
  214. GL_RGB, GL_UNSIGNED_BYTE,
  215. image->getPixelPointer() );
  216. } else {
  217. glDrawPixels ( image->width(), image->height(),
  218. GL_LUMINANCE, GL_UNSIGNED_BYTE,
  219. image->getPixelPointer() );
  220. }
  221. } else {
  222. glClearColor ( 0.0, 0.0, 0.0, 0.0 );
  223. glClear ( GL_COLOR_BUFFER_BIT );
  224. glFlush();
  225. }
  226. if ( buf_overlayImage != NULL ) {
  227. if ( image == NULL ) {
  228. glPixelStorei ( GL_PACK_ALIGNMENT, 1 );
  229. glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 );
  230. glPixelZoom ( ( GLfloat ) width() / ( ( GLfloat ) overlayImageWidth ),
  231. ( ( GLfloat ) - height() ) / ( ( GLfloat ) overlayImageHeight ) );
  232. glRasterPos2f ( 0, height() - 0.5 );
  233. }
  234. glEnable ( GL_BLEND );
  235. glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
  236. glDrawPixels ( overlayImageWidth, overlayImageHeight,
  237. GL_RGBA, GL_UNSIGNED_BYTE, buf_overlayImage );
  238. glDisable ( GL_BLEND );
  239. glFlush();
  240. }
  241. if ( isDragging && drawSelectionRect ) {
  242. glLineWidth ( 1 );
  243. glEnable ( GL_LINE_STIPPLE );
  244. glLineStipple ( 1, 0x00FF );
  245. glColor4f ( 1, 1, 1, 1 );
  246. // // Antialiased Points
  247. // glEnable(GL_POINT_SMOOTH);
  248. // glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
  249. // // Antialiased Lines
  250. // glEnable(GL_LINE_SMOOTH);
  251. // glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
  252. glBegin ( GL_LINE_LOOP );
  253. glVertex2f ( dragX, height() - dragY );
  254. glVertex2f ( dragX, height() - dropY );
  255. glVertex2f ( dropX, height() - dropY );
  256. glVertex2f ( dropX, height() - dragY );
  257. glEnd();
  258. glDisable ( GL_LINE_STIPPLE );
  259. glFlush();
  260. }
  261. if ( texts.size() > 0 ) {
  262. glEnable ( GL_BLEND );
  263. glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
  264. for ( uint i = 0; i < texts.size(); ++i ) {
  265. Text& text = texts[i];
  266. glColor4ub ( text.color[0], text.color[1], text.color[2], 255 );
  267. float x = float ( text.x ) * float ( width() ) / float ( image->width() );
  268. float y = float ( text.y ) * float ( height() ) / float ( image->height() );
  269. glRasterPos2f ( x, height() - y - 0.5 );
  270. void* font = GLUT_BITMAP_HELVETICA_10;//(*i)->font;
  271. for ( uint j = 0; j < text.text.size(); ++j )
  272. glutBitmapCharacter ( font, text.text[j] );
  273. }
  274. glDisable ( GL_BLEND );
  275. glFlush();
  276. }
  277. #else
  278. fthrow(Exception,"GLUT lib not availabe, recompile using GLUT!");
  279. #endif
  280. paintGLObjects();
  281. }
  282. void ImageDisplay::setGLProjection ( void ) {
  283. #ifdef NICE_USELIB_GLUT
  284. glViewport ( 0, 0, width(), height() );
  285. glMatrixMode ( GL_PROJECTION );
  286. glLoadIdentity();
  287. gluOrtho2D ( 0.0, ( GLdouble ) width(), 0.0, ( GLdouble ) height() );
  288. #else
  289. fthrow(Exception,"GLUT lib not availabe, recompile using GLUT!");
  290. #endif
  291. }
  292. void ImageDisplay::paintGLObjects ( void ) {
  293. }
  294. void ImageDisplay::mousePressEvent ( QMouseEvent* event ) {
  295. QGLWidget::mousePressEvent ( event );
  296. startDrag ( event->x(), event->y() );
  297. }
  298. void ImageDisplay::mouseMoveEvent ( QMouseEvent* event ) {
  299. QGLWidget::mouseMoveEvent ( event );
  300. dragging ( event->x(), event->y() );
  301. }
  302. void ImageDisplay::mouseReleaseEvent ( QMouseEvent* event ) {
  303. QGLWidget::mouseReleaseEvent ( event );
  304. makeDrop ( event->x(), event->y() );
  305. float left = dragX * ( image->width() / ( float ) width() );
  306. float right = dropX * ( image->width() / ( float ) width() );
  307. float top = dragY * ( image->height() / ( float ) height() );
  308. float bottom = dropY * ( image->height() / ( float ) height() );
  309. if ( left > right ) {
  310. std::swap ( left, right );
  311. }
  312. if ( top > bottom ) {
  313. std::swap ( top, bottom );
  314. }
  315. emit rectSelect ( left, top, right, bottom );
  316. }
  317. void ImageDisplay::startDrag ( int x, int y ) {
  318. isDragging = true;
  319. dragX = x;
  320. dragY = y;
  321. dropX = x;
  322. dropY = y;
  323. updateGL();
  324. }
  325. void ImageDisplay::dragging ( int x, int y ) {
  326. if ( isDragging ) {
  327. dropX = x;
  328. dropY = y;
  329. updateGL();
  330. }
  331. }
  332. void ImageDisplay::makeDrop ( int x, int y ) {
  333. if ( isDragging ) {
  334. isDragging = false;
  335. dropX = x;
  336. dropY = y;
  337. updateGL();
  338. }
  339. }
  340. void ImageDisplay::contextMenuEvent ( QContextMenuEvent* event ) {
  341. Q3PopupMenu* popupMenu = new Q3PopupMenu ( this );
  342. // CHECK_PTR(popupMenu); // Qt4
  343. //popupMenu->insertTearOffHandle();
  344. addExtraMenuItems ( popupMenu );
  345. int saveID = popupMenu->insertItem ( "&Save image", this, SLOT ( menuSave() ) );
  346. popupMenu->setAccel ( Qt::CTRL + Qt::Key_S, saveID );
  347. int aspectID = popupMenu->insertItem ( "&Restore aspect ratio",
  348. this, SLOT ( menuAspectRatio() ) );
  349. popupMenu->setAccel ( Qt::CTRL + Qt::Key_A, aspectID );
  350. popupMenu->insertSeparator();
  351. popupMenu->insertItem ( "Start &capturing image sequence",
  352. this, SLOT ( menuStartCapture() ) );
  353. popupMenu->insertItem ( "Sto&p capturing", this, SLOT ( menuStopCapture() ) );
  354. popupMenu->exec ( QCursor::pos() );
  355. delete popupMenu;
  356. }
  357. void ImageDisplay::addExtraMenuItems ( Q3PopupMenu *popupMenu )
  358. {
  359. }
  360. void ImageDisplay::menuAspectRatio() {
  361. if ( image != NULL ) {
  362. resize ( size().width(), size().width() * image->height() / image->width() );
  363. }
  364. }
  365. void ImageDisplay::menuSave() {
  366. QString s = Q3FileDialog::getSaveFileName (
  367. "",
  368. "Images (*.ppm *.pgm *.png *.jpg)",
  369. this,
  370. "Save file dialog",
  371. "Choose a filename" );
  372. if ( s.local8Bit().size() == 0 ) {
  373. return;
  374. }
  375. NICE::FileName filename ( s.local8Bit() );
  376. const std::string ext = filename.extractExtension().str();
  377. const bool extensionOk
  378. = ( ext == std::string ( ".ppm" ) || ext == std::string ( ".pgm" )
  379. || ext == std::string ( ".png" ) || ext == std::string ( ".jpg" ) );
  380. if ( !extensionOk ) {
  381. if ( isColor ) {
  382. filename.setExtension ( ".ppm" );
  383. } else {
  384. filename.setExtension ( ".pgm" );
  385. }
  386. }
  387. image->write ( filename.str() );
  388. }
  389. void ImageDisplay::menuStartCapture() {
  390. if ( dialog.get() == NULL ) {
  391. dialog.reset ( new CaptureDialog ( this, "Capture Dialog" ) );
  392. dialog->setCaption ( "Capture: " + captionBuffer );
  393. connect ( ( QObject* ) dialog->capture(), SIGNAL ( started() ),
  394. this, SLOT ( dialogStartCapture() ) );
  395. connect ( ( QObject* ) dialog->capture(), SIGNAL ( stopped() ),
  396. this, SLOT ( dialogStopCapture() ) );
  397. }
  398. dialog->show();
  399. }
  400. void ImageDisplay::menuStopCapture() {
  401. if ( dialog.get() != NULL ) {
  402. dialog->capture()->buttonStopClicked();
  403. }
  404. }
  405. void ImageDisplay::dialogStartCapture() {
  406. sequenceWriter.reset (
  407. new ImageFileListWriter ( dialog->capture()->directoryName(),
  408. dialog->capture()->extensionName(),
  409. dialog->capture()->isBuffered() ) );
  410. }
  411. void ImageDisplay::dialogStopCapture() {
  412. sequenceWriter.reset ( NULL );
  413. }
  414. void ImageDisplay::setCaption ( const QString& s ) {
  415. captionBuffer = s;
  416. doSetCaption();
  417. }
  418. void ImageDisplay::doSetCaption() {
  419. std::stringstream s;
  420. s.precision ( 1 );
  421. s << std::fixed << captionBuffer.toAscii().constData()
  422. << " (FPS: " << frameRateCounter.getFrameRate() << ")";
  423. //std::cerr << "ImageDisplay::doSetCaption(): " << s.str() << std::endl;
  424. QWidget::setCaption ( s.str().c_str() );
  425. }
  426. ImageDisplay* displayImage ( const NICE::ColorImage* image,
  427. const std::string& title,
  428. const bool copy ) {
  429. // make sure Qt is initialized
  430. if ( qApp == NULL ) {
  431. QtFramework::instance();
  432. }
  433. // QWidget* mainWindow = NULL;
  434. // if (QtFramework::isInstanceInitialized()) {
  435. // mainWindow = QtFramework::instance().getMainWindow();
  436. // }
  437. // ImageDisplay* display
  438. // = new ImageDisplay(mainWindow, title.c_str(),
  439. // (unsigned int)Qt::WType_TopLevel);
  440. ImageDisplay* display = new ImageDisplay();
  441. display->setCaption ( title.c_str() );
  442. display->setImage ( image, copy );
  443. display->show();
  444. return display;
  445. }
  446. ImageDisplay* displayImage ( const NICE::Image* image,
  447. const std::string& title,
  448. const bool copy ) {
  449. // make sure Qt is initialized
  450. if ( qApp == NULL ) {
  451. QtFramework::instance();
  452. }
  453. // QWidget* mainWindow = NULL;
  454. // if (QtFramework::isInstanceInitialized()) {
  455. // mainWindow = QtFramework::instance().getMainWindow();
  456. // }
  457. // ImageDisplay* display
  458. // = new ImageDisplay(mainWindow, title.c_str(),
  459. // (unsigned int)Qt::WType_TopLevel);
  460. ImageDisplay* display = new ImageDisplay();
  461. display->setCaption ( title.c_str() );
  462. display->setImage ( image, copy );
  463. display->show();
  464. return display;
  465. }
  466. ImageDisplay* displayImageOverlay ( const NICE::Image* image,
  467. const NICE::Image *overlay,
  468. const std::string& title,
  469. const bool copy )
  470. {
  471. if ( ( image->width() != overlay->width() ) ||
  472. ( image->height() != overlay->height() ) )
  473. {
  474. fthrow ( Exception, "Image and overlay image must have the same dimensions." );
  475. }
  476. // make sure Qt is initialized
  477. if ( qApp == NULL ) {
  478. QtFramework::instance();
  479. }
  480. ImageDisplay *display = new ImageDisplay();
  481. display->setCaption ( title.c_str() );
  482. display->setImage ( image, copy );
  483. display->setOverlayImage ( overlay );
  484. display->show();
  485. return display;
  486. }
  487. ImageDisplay* displayImageOverlay ( const NICE::ColorImage* image,
  488. const NICE::Image *overlay,
  489. const std::string& title,
  490. const bool copy )
  491. {
  492. if ( ( image->width() != overlay->width() ) ||
  493. ( image->height() != overlay->height() ) )
  494. {
  495. fthrow ( Exception, "Image and overlay image must have the same dimensions." );
  496. }
  497. // make sure Qt is initialized
  498. if ( qApp == NULL ) {
  499. QtFramework::instance();
  500. }
  501. ImageDisplay *display = new ImageDisplay();
  502. display->setCaption ( title.c_str() );
  503. display->setImage ( image, copy );
  504. display->setOverlayImage ( overlay );
  505. display->show();
  506. return display;
  507. }
  508. void showImage ( const NICE::Image& image,
  509. const std::string& title,
  510. const bool copy ) {
  511. // display image and wait for the user to close
  512. // the window
  513. displayImage ( &image, title, copy );
  514. QtFramework::exec ( false );
  515. }
  516. void showImage ( const NICE::ColorImage& image,
  517. const std::string& title,
  518. const bool copy ) {
  519. // display image and wait for the user to close
  520. // the window
  521. displayImage ( &image, title, copy );
  522. QtFramework::exec ( false );
  523. }
  524. void showImageOverlay ( const NICE::Image & image,
  525. const NICE::Image & overlay,
  526. const std::string& title,
  527. const bool copy )
  528. {
  529. displayImageOverlay ( &image, &overlay, title, copy );
  530. QtFramework::exec ( false );
  531. }
  532. void showImageOverlay ( const NICE::ColorImage & image,
  533. const NICE::Image & overlay,
  534. const std::string& title,
  535. const bool copy )
  536. {
  537. displayImageOverlay ( &image, &overlay, title, copy );
  538. QtFramework::exec ( false );
  539. }
  540. int ImageDisplay::addText ( int x, int y, const std::string& text,
  541. const Color& color ) {
  542. Text t ( x, y, text, true, color );
  543. texts.push_back ( t );
  544. return texts.size() - 1;
  545. }
  546. } // namespace