/* * NICE-Core - efficient algebra and computer vision methods * - libimagedisplay - A library for image and video display * See file License for license information. */ #include "core/imagedisplay/ImageDisplay.h" #include #ifdef NICE_USELIB_GLUT #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include // we need this function for overlays #include namespace NICE { ImageDisplay::ImageDisplay ( QWidget* parent, const char* name, Qt::WFlags flags ) : QGLWidget ( parent, NULL, flags ), image ( NULL ), colorImageBuffer ( NULL ), grayImageBuffer ( NULL ), copied ( false ), isDragging ( false ), buf_overlayImage ( NULL ) { if ( parent == NULL ) { ImageDisplayManager::instance().registerWidget ( this ); } updateGL(); } ImageDisplay::~ImageDisplay() { //ImageDisplayManager::instance().unregisterWidget(this); if ( copied && colorImageBuffer != NULL ) { delete colorImageBuffer; } if ( copied && grayImageBuffer != NULL ) { delete grayImageBuffer; } if ( buf_overlayImage != NULL ) delete [] buf_overlayImage; } void ImageDisplay::setImage ( const NICE::ColorImage* _image, const bool copy ) { frameRateCounter.newFrame(); if ( frameRateCounter.getCounter() == 0 ) { doSetCaption(); } if ( sequenceWriter.get() != NULL ) { sequenceWriter->writeColorImage ( *_image ); } int oldImageWidth = 0; int oldImageHeight = 0; if ( image != NULL ) { oldImageWidth = image->width(); oldImageHeight = image->height(); } if ( copied && grayImageBuffer != NULL ) { delete grayImageBuffer; grayImageBuffer = NULL; } isColor = true; if ( copy ) { if ( copied && colorImageBuffer != NULL ) { if ( _image->width() != colorImageBuffer->width() || _image->height() != colorImageBuffer->height() ) { delete colorImageBuffer; colorImageBuffer = new NICE::ColorImage ( *_image, NICE::GrayColorImageCommonImplementation::noAlignment ); } else { colorImageBuffer->copyFrom ( *_image, NICE::GrayColorImageCommonImplementation::noAlignment ); } } else { copied = true; colorImageBuffer = new NICE::ColorImage ( *_image, NICE::GrayColorImageCommonImplementation::noAlignment ); } image = colorImageBuffer; } else { if ( copied && colorImageBuffer != NULL ) { delete colorImageBuffer; colorImageBuffer = NULL; } image = _image; } if ( oldImageWidth != image->width() || oldImageHeight != image->height() ) { resize ( image->width(), image->height() ); } updateGL(); } void ImageDisplay::setImage ( const NICE::Image* _image, const bool copy ) { frameRateCounter.newFrame(); if ( frameRateCounter.getCounter() == 0 ) { doSetCaption(); } if ( sequenceWriter.get() != NULL ) { sequenceWriter->writeGrayImage ( *_image ); } int oldImageWidth = 0; int oldImageHeight = 0; if ( image != NULL ) { oldImageWidth = image->width(); oldImageHeight = image->height(); } if ( copied && colorImageBuffer != NULL ) { delete colorImageBuffer; colorImageBuffer = NULL; } isColor = false; if ( copy ) { if ( copied && grayImageBuffer != NULL ) { if ( _image->width() != grayImageBuffer->width() || _image->height() != grayImageBuffer->height() ) { delete grayImageBuffer; grayImageBuffer = new NICE::Image ( *_image, NICE::GrayColorImageCommonImplementation::noAlignment ); } else { grayImageBuffer->copyFrom ( *_image, NICE::GrayColorImageCommonImplementation::noAlignment ); } } else { copied = true; grayImageBuffer = new NICE::Image ( *_image, NICE::GrayColorImageCommonImplementation::noAlignment ); } image = grayImageBuffer; } else { if ( copied && grayImageBuffer != NULL ) { delete grayImageBuffer; grayImageBuffer = NULL; } image = _image; } if ( oldImageWidth != image->width() || oldImageHeight != image->height() ) { resize ( image->width(), image->height() ); } updateGL(); } void ImageDisplay::setOverlayImage ( const NICE::Image* overlayImage ) { bool alloc = false; if ( buf_overlayImage == NULL ) alloc = true; else if ( ( overlayImageWidth != overlayImage->width() ) || ( overlayImageHeight != overlayImage->height() ) ) alloc = true; if ( alloc ) { if ( buf_overlayImage != NULL ) delete [] buf_overlayImage; overlayImageWidth = overlayImage->width(); overlayImageHeight = overlayImage->height(); // RGBA image: 4 channels buf_overlayImage = new unsigned char[ overlayImageWidth * overlayImageHeight * 4 ]; } long int k = 0; for ( int y = 0; y < overlayImage->height(); y++ ) { const unsigned char* end = overlayImage->getPixelPointerYEnd ( y ); int colstep = overlayImage->columnStepsize(); for ( const unsigned char* p = overlayImage->getPixelPointerY ( y ); p != end; p = ( const unsigned char * ) ( ( ( Ipp8u * ) p ) + colstep ) ) { unsigned char overlayValue = *p; unsigned char r, g, b, alpha; if ( overlayValue <= 0 ) { r = 0; b = 0; g = 0; alpha = 0; } else { int colorValue = overlayValue % overlayColorTableNumEntries; r = overlayColorTable[colorValue][0]; g = overlayColorTable[colorValue][1]; b = overlayColorTable[colorValue][2]; alpha = 255; } buf_overlayImage[k++] = r; buf_overlayImage[k++] = g; buf_overlayImage[k++] = b; buf_overlayImage[k++] = alpha; } } updateGL(); } void ImageDisplay::repaint() { updateGL(); } void ImageDisplay::paintGL() { #ifdef NICE_USELIB_GLUT setGLProjection(); if ( image != NULL ) { glPixelStorei ( GL_PACK_ALIGNMENT, 1 ); glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 ); glPixelZoom ( ( GLfloat ) width() / ( ( GLfloat ) image->width() ), ( ( GLfloat ) - height() ) / ( ( GLfloat ) image->height() ) ); glRasterPos2f ( 0, height() - 0.5 ); if ( isColor ) { glDrawPixels ( image->width(), image->height(), GL_RGB, GL_UNSIGNED_BYTE, image->getPixelPointer() ); } else { glDrawPixels ( image->width(), image->height(), GL_LUMINANCE, GL_UNSIGNED_BYTE, image->getPixelPointer() ); } } else { glClearColor ( 0.0, 0.0, 0.0, 0.0 ); glClear ( GL_COLOR_BUFFER_BIT ); glFlush(); } if ( buf_overlayImage != NULL ) { if ( image == NULL ) { glPixelStorei ( GL_PACK_ALIGNMENT, 1 ); glPixelStorei ( GL_UNPACK_ALIGNMENT, 1 ); glPixelZoom ( ( GLfloat ) width() / ( ( GLfloat ) overlayImageWidth ), ( ( GLfloat ) - height() ) / ( ( GLfloat ) overlayImageHeight ) ); glRasterPos2f ( 0, height() - 0.5 ); } glEnable ( GL_BLEND ); glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glDrawPixels ( overlayImageWidth, overlayImageHeight, GL_RGBA, GL_UNSIGNED_BYTE, buf_overlayImage ); glDisable ( GL_BLEND ); glFlush(); } if ( isDragging && drawSelectionRect ) { glLineWidth ( 1 ); glEnable ( GL_LINE_STIPPLE ); glLineStipple ( 1, 0x00FF ); glColor4f ( 1, 1, 1, 1 ); // // Antialiased Points // glEnable(GL_POINT_SMOOTH); // glHint(GL_POINT_SMOOTH_HINT, GL_NICEST); // // Antialiased Lines // glEnable(GL_LINE_SMOOTH); // glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); glBegin ( GL_LINE_LOOP ); glVertex2f ( dragX, height() - dragY ); glVertex2f ( dragX, height() - dropY ); glVertex2f ( dropX, height() - dropY ); glVertex2f ( dropX, height() - dragY ); glEnd(); glDisable ( GL_LINE_STIPPLE ); glFlush(); } if ( texts.size() > 0 ) { glEnable ( GL_BLEND ); glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); for ( uint i = 0; i < texts.size(); ++i ) { Text& text = texts[i]; glColor4ub ( text.color[0], text.color[1], text.color[2], 255 ); float x = float ( text.x ) * float ( width() ) / float ( image->width() ); float y = float ( text.y ) * float ( height() ) / float ( image->height() ); glRasterPos2f ( x, height() - y - 0.5 ); void* font = GLUT_BITMAP_HELVETICA_10;//(*i)->font; for ( uint j = 0; j < text.text.size(); ++j ) glutBitmapCharacter ( font, text.text[j] ); } glDisable ( GL_BLEND ); glFlush(); } #else fthrow(Exception,"GLUT lib not availabe, recompile using GLUT!"); #endif paintGLObjects(); } void ImageDisplay::setGLProjection ( void ) { #ifdef NICE_USELIB_GLUT glViewport ( 0, 0, width(), height() ); glMatrixMode ( GL_PROJECTION ); glLoadIdentity(); gluOrtho2D ( 0.0, ( GLdouble ) width(), 0.0, ( GLdouble ) height() ); #else fthrow(Exception,"GLUT lib not availabe, recompile using GLUT!"); #endif } void ImageDisplay::paintGLObjects ( void ) { } void ImageDisplay::mousePressEvent ( QMouseEvent* event ) { QGLWidget::mousePressEvent ( event ); startDrag ( event->x(), event->y() ); } void ImageDisplay::mouseMoveEvent ( QMouseEvent* event ) { QGLWidget::mouseMoveEvent ( event ); dragging ( event->x(), event->y() ); } void ImageDisplay::mouseReleaseEvent ( QMouseEvent* event ) { QGLWidget::mouseReleaseEvent ( event ); makeDrop ( event->x(), event->y() ); float left = dragX * ( image->width() / ( float ) width() ); float right = dropX * ( image->width() / ( float ) width() ); float top = dragY * ( image->height() / ( float ) height() ); float bottom = dropY * ( image->height() / ( float ) height() ); if ( left > right ) { std::swap ( left, right ); } if ( top > bottom ) { std::swap ( top, bottom ); } emit rectSelect ( left, top, right, bottom ); } void ImageDisplay::startDrag ( int x, int y ) { isDragging = true; dragX = x; dragY = y; dropX = x; dropY = y; updateGL(); } void ImageDisplay::dragging ( int x, int y ) { if ( isDragging ) { dropX = x; dropY = y; updateGL(); } } void ImageDisplay::makeDrop ( int x, int y ) { if ( isDragging ) { isDragging = false; dropX = x; dropY = y; updateGL(); } } void ImageDisplay::contextMenuEvent ( QContextMenuEvent* event ) { QMenu* popupMenu = new QMenu ( this ); addExtraMenuItems ( popupMenu ); popupMenu->addAction("&Save Image", this, SLOT ( menuSave() ), Qt::CTRL + Qt::Key_S); popupMenu->addAction("&Restore aspect ratio", this, SLOT ( menuAspectRatio ), Qt::CTRL + Qt::Key_A); popupMenu->addSeparator(); popupMenu->addAction ( "Start &capturing image sequence", this, SLOT ( menuStartCapture() ) ); popupMenu->addAction ( "Sto&p capturing", this, SLOT ( menuStopCapture() ) ); popupMenu->exec ( QCursor::pos() ); delete popupMenu; } void ImageDisplay::addExtraMenuItems ( QMenu *popupMenu ) { } void ImageDisplay::menuAspectRatio() { if ( image != NULL ) { resize ( size().width(), size().width() * image->height() / image->width() ); } } void ImageDisplay::menuSave() { QString s = QFileDialog::getSaveFileName(this, "Save file dialog", "", "Images (*.ppm, *.pgm, *.png, *.jpg)"); if ( s.isNull() ) { return; } NICE::FileName filename ( s.toLocal8Bit() ); const std::string ext = filename.extractExtension().str(); const bool extensionOk = ( ext == std::string ( ".ppm" ) || ext == std::string ( ".pgm" ) || ext == std::string ( ".png" ) || ext == std::string ( ".jpg" ) ); if ( !extensionOk ) { if ( isColor ) { filename.setExtension ( ".ppm" ); } else { filename.setExtension ( ".pgm" ); } } image->write ( filename.str() ); } void ImageDisplay::menuStartCapture() { if ( dialog.get() == NULL ) { dialog.reset ( new CaptureDialog ( this, "Capture Dialog" ) ); dialog->setWindowTitle ( "Capture: " + captionBuffer ); connect ( ( QObject* ) dialog->capture(), SIGNAL ( started() ), this, SLOT ( dialogStartCapture() ) ); connect ( ( QObject* ) dialog->capture(), SIGNAL ( stopped() ), this, SLOT ( dialogStopCapture() ) ); } dialog->show(); } void ImageDisplay::menuStopCapture() { if ( dialog.get() != NULL ) { dialog->capture()->buttonStopClicked(); } } void ImageDisplay::dialogStartCapture() { sequenceWriter.reset ( new ImageFileListWriter ( dialog->capture()->directoryName(), dialog->capture()->extensionName(), dialog->capture()->isBuffered() ) ); } void ImageDisplay::dialogStopCapture() { sequenceWriter.reset ( NULL ); } void ImageDisplay::setCaption ( const QString& s ) { captionBuffer = s; doSetCaption(); } void ImageDisplay::doSetCaption() { std::stringstream s; s.precision ( 1 ); s << std::fixed << captionBuffer.toAscii().constData() << " (FPS: " << frameRateCounter.getFrameRate() << ")"; //std::cerr << "ImageDisplay::doSetCaption(): " << s.str() << std::endl; QWidget::setWindowTitle ( s.str().c_str() ); } ImageDisplay* displayImage ( const NICE::ColorImage* image, const std::string& title, const bool copy ) { // make sure Qt is initialized if ( qApp == NULL ) { QtFramework::instance(); } // QWidget* mainWindow = NULL; // if (QtFramework::isInstanceInitialized()) { // mainWindow = QtFramework::instance().getMainWindow(); // } // ImageDisplay* display // = new ImageDisplay(mainWindow, title.c_str(), // (unsigned int)Qt::WType_TopLevel); ImageDisplay* display = new ImageDisplay(); display->setCaption ( title.c_str() ); display->setImage ( image, copy ); display->show(); return display; } ImageDisplay* displayImage ( const NICE::Image* image, const std::string& title, const bool copy ) { // make sure Qt is initialized if ( qApp == NULL ) { QtFramework::instance(); } // QWidget* mainWindow = NULL; // if (QtFramework::isInstanceInitialized()) { // mainWindow = QtFramework::instance().getMainWindow(); // } // ImageDisplay* display // = new ImageDisplay(mainWindow, title.c_str(), // (unsigned int)Qt::WType_TopLevel); ImageDisplay* display = new ImageDisplay(); display->setCaption ( title.c_str() ); display->setImage ( image, copy ); display->show(); return display; } ImageDisplay* displayImageOverlay ( const NICE::Image* image, const NICE::Image *overlay, const std::string& title, const bool copy ) { if ( ( image->width() != overlay->width() ) || ( image->height() != overlay->height() ) ) { fthrow ( Exception, "Image and overlay image must have the same dimensions." ); } // make sure Qt is initialized if ( qApp == NULL ) { QtFramework::instance(); } ImageDisplay *display = new ImageDisplay(); display->setCaption ( title.c_str() ); display->setImage ( image, copy ); display->setOverlayImage ( overlay ); display->show(); return display; } ImageDisplay* displayImageOverlay ( const NICE::ColorImage* image, const NICE::Image *overlay, const std::string& title, const bool copy ) { if ( ( image->width() != overlay->width() ) || ( image->height() != overlay->height() ) ) { fthrow ( Exception, "Image and overlay image must have the same dimensions." ); } // make sure Qt is initialized if ( qApp == NULL ) { QtFramework::instance(); } ImageDisplay *display = new ImageDisplay(); display->setCaption ( title.c_str() ); display->setImage ( image, copy ); display->setOverlayImage ( overlay ); display->show(); return display; } void showImage ( const NICE::Image& image, const std::string& title, const bool copy ) { // display image and wait for the user to close // the window displayImage ( &image, title, copy ); QtFramework::exec ( false ); } void showImage ( const NICE::ColorImage& image, const std::string& title, const bool copy ) { // display image and wait for the user to close // the window displayImage ( &image, title, copy ); QtFramework::exec ( false ); } void showImageOverlay ( const NICE::Image & image, const NICE::Image & overlay, const std::string& title, const bool copy ) { displayImageOverlay ( &image, &overlay, title, copy ); QtFramework::exec ( false ); } void showImageOverlay ( const NICE::ColorImage & image, const NICE::Image & overlay, const std::string& title, const bool copy ) { displayImageOverlay ( &image, &overlay, title, copy ); QtFramework::exec ( false ); } int ImageDisplay::addText ( int x, int y, const std::string& text, const Color& color ) { Text t ( x, y, text, true, color ); texts.push_back ( t ); return texts.size() - 1; } } // namespace