ImageDisplay.cpp 18 KB

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