ImageDisplay.cpp 17 KB

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