ImageDisplay.cpp 18 KB

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