ImageDisplay.cpp 17 KB

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