/*************************************************************************** videoframe.cpp - description ------------------- begin : Fri Nov 22 2002 copyright : (C) 2002 by email : ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * ***************************************************************************/ #include "amcdefs.h" #include "amcframegrabber.h" #include "calibratepaneldialog.h" #include "linearregression.h" #include "threadevent.h" #include "videoframe.h" #include "videospot.h" #include "videospotthread.h" #include "videothread.h" #include #include #include #include #include #include #include #include #define HEADERSIZE 15 extern int g_iRefX, g_iRefY; VideoFrame::VideoFrame( QWidget *parent, const char *name, AMCFrameGrabber* p_pFG ) : QFrame( parent, name ) { qDebug("Thread for VideoFrame PID: %d - PPID: %d", getpid(), getppid() ); qDebug("Creating Image arrays"); m_pImage = new QImage( MY_WIDTH, MY_HEIGHT, MY_DEPTH*8 ); m_darkFrame = new QByteArray( BUFSIZE ); m_iFrame = 0; m_iGoodFrame = 0; m_iDarks = 0; m_iFrameNum = 0; m_ix = m_iy = -1; m_iRefX = m_iRefY = -1; m_iCenterX = m_iCenterY = 1; m_pCalibDlg = 0; // m_qlSpots.setAutoDelete( true ); qDebug("Creating VideoThread"); m_pVideoThread = new VideoThread( this, p_pFG ); m_pVideoThread->init( BUFSIZE ); qDebug("Creating SpotThread"); m_pSpotThread = new VideoSpotThread( this, m_pImage, (uchar*) m_darkFrame->data() ); qDebug("Starting VideoThread"); qDebug("Thread for VideoFrame when starting VideoThread PID: %d - PPID: %d", getpid(), getppid() ); m_pVideoThread->start(); } VideoFrame::~VideoFrame() { qDebug("Stoping video thread"); m_pVideoThread->stop(); m_pVideoThread->wait( ); qDebug("deleting video thread"); delete m_pVideoThread; qDebug("Stoping spot thread"); m_pSpotThread->wait(); qDebug("deleting spot thread"); delete m_pSpotThread; delete m_darkFrame; delete m_pImage; m_qlSpots.clear(); } /** overridden painter for the frame */ void VideoFrame::drawContents( QPainter* windowPainter ) { // qDebug("In drawContents"); // Draw image QRect rect = contentsRect(); windowPainter->drawImage( 0,0, *m_pImage ); // Overlay camera center if it was determined from the LEDs if( m_iCenterX != -1 ) windowPainter->setPen( Qt::white ); windowPainter->drawEllipse( m_iCenterX-2, m_iCenterY-2, 5, 5); windowPainter->drawEllipse( m_iCenterX-4, m_iCenterY-4, 9, 9); // Overlay Spots windowPainter->setPen( Qt::red ); for( VideoSpot* pActualSpot = m_qlSpots.first(); pActualSpot; pActualSpot = m_qlSpots.next() ) { if( pActualSpot->isValid() ) windowPainter->drawEllipse( pActualSpot->getX()-4, pActualSpot->getY()-4, 9, 9); } if( m_pCalibDlg != 0 ) { QList* pLineList = m_pCalibDlg->getLineList(); windowPainter->setPen( Qt::magenta ); for( VideoSpot* pActualSpot = pLineList->first(); pActualSpot; pActualSpot = pLineList->next() ) { if( pActualSpot->isValid() ) windowPainter->drawEllipse( pActualSpot->getX()-4, pActualSpot->getY()-4, 9, 9); } int iX1, iX2; windowPainter->setPen( Qt::yellow ); LinearRegression* pRegression = m_pCalibDlg->getXRegression(); if( pRegression->isValid() ) { iX1 = (int) (( 0. - pRegression->getAxis()) / pRegression->getSlope()); iX2 = (int) (( 479. - pRegression->getAxis()) / pRegression->getSlope()); windowPainter->drawLine( iX1, 0, iX2, 479 ); } pRegression = m_pCalibDlg->getYRegression(); if( pRegression->isValid() ) { iX1 = (int) (( 0. - pRegression->getAxis() ) / pRegression->getSlope()); iX2 = (int) (( 479. - pRegression->getAxis() ) / pRegression->getSlope()); windowPainter->drawLine( iX1, 0, iX2, 479 ); } } // Draw a blue cross for the global reference point windowPainter->setPen( Qt::blue ); windowPainter->drawLine( g_iRefX-4, g_iRefY, g_iRefX+4, g_iRefY); windowPainter->drawLine( g_iRefX, g_iRefY-4, g_iRefX, g_iRefY+4); // Draw a green rectangle showing the reference point for this panel if( m_iRefX > 0) { windowPainter->setPen( Qt::green ); windowPainter->drawRect( m_iRefX-4, m_iRefY-4, 9, 9 ); } // Draw a blue rectangle showing the Region Of Interest (ROI) // which is used to find the spot if( ! m_qrROI.isEmpty() ) { windowPainter->setPen( Qt::blue ); windowPainter->drawRect( m_qrROI ); } } /** No descriptions */ void VideoFrame::saveFrame() { QString fileName; fileName.sprintf("Frame%02d.png",m_iFrameNum); m_pImage->save( fileName, "PNG"); fileName.sprintf("Spots%02d.txt",m_iFrameNum++); QFile file( fileName ); if( file.open( IO_WriteOnly ) ) { QTextStream stream( &file ); QString str; str.sprintf("LEDs\n" ); stream << str; for( VideoSpot* pActualSpot = m_qlLEDs.first(); pActualSpot; pActualSpot = m_qlLEDs.next() ) { if( pActualSpot->isValid() ) { str.sprintf("%d %d\n", pActualSpot->getX(), pActualSpot->getY() ); stream << str; } } str.sprintf("\nSpots\n" ); stream << str; for( VideoSpot* pActualSpot = m_qlSpots.first(); pActualSpot; pActualSpot = m_qlSpots.next() ) { if( pActualSpot->isValid() ) { str.sprintf("%d %d\n", pActualSpot->getX(), pActualSpot->getY() ); stream << str; } } } } /** Save a dark frame */ void VideoFrame::takeDark() { qDebug("Taking dark frame"); uchar* pFrame = m_pImage->bits(); m_pVideoThread->getLastFrame( pFrame ); uchar* pDark = m_darkFrame->data(); for(int ind=0; ind< (MY_HEIGHT * MY_WIDTH * MY_DEPTH); ind++, pDark++, pFrame++ ) { int help = *pDark; help = (help * m_iDarks) + (int) *pFrame; *pDark = (uchar) (help / (m_iDarks+1)); } m_iDarks++; } /** Clear dark frames */ void VideoFrame::clearDarks() { m_darkFrame->fill(0); m_iDarks = 0; } /** No descriptions */ void VideoFrame::timerDone() { // qDebug("Frames per second %d %d", m_iFrame, m_iGoodFrame); emit framesGrabbed( m_iFrame ); emit framesProcessed( m_iGoodFrame ); m_iFrame = 0; m_iGoodFrame=0; } /** No descriptions */ void VideoFrame::mouseMoveEvent( QMouseEvent* event ) { if( (event->state() & LeftButton) == 0 ) return; int x = event->x(); int y = event->y(); if( x > m_qrROI.left() ) m_qrROI.setRight( x ); else { if( x == m_qrROI.left() ) m_qrROI.setRight( event->x() -1 ); else m_qrROI.setLeft( x ); } if( y > m_qrROI.top() ) m_qrROI.setBottom( y ); else { if( y == m_qrROI.bottom() ) m_qrROI.setBottom( event->y() -1 ); else m_qrROI.setTop( y ); } if ( m_qrROI.isValid() ); m_pSpotThread->setROI( m_qrROI ); } /** No descriptions */ void VideoFrame::mousePressEvent( QMouseEvent* event ) { if( event->button() == LeftButton ) { m_qrROI.setLeft( event->x() ); m_qrROI.setRight( event->x() -1 ); m_qrROI.setTop( event->y() ); m_qrROI.setBottom( event->y() -1 ); m_pSpotThread->setROI( m_qrROI ); } if( event->button() == MidButton ) { m_qrROI.setLeft( 0 ); m_qrROI.setRight( -1 ); m_qrROI.setTop( 0 ); m_qrROI.setBottom( -1 ); m_pSpotThread->setROI( m_qrROI ); } if( event->button() == RightButton ) { g_iRefX = event->x(); g_iRefY = event->y(); emit gref( g_iRefX, g_iRefY ); } } void VideoFrame::customEvent(QCustomEvent *e) { if ( e->type() == THREAD_END_EVENT ) { repaint( FALSE ); calcCenter(); if( m_qlSpots.count() == 1) { VideoSpot* pSpot = m_qlSpots.first(); emit spot( pSpot->getX(), pSpot->getY() ); } else emit spot( -1, -1 ); } if ( e->type() == THREAD_FRAME_EVENT ) { m_iFrame++; if( ! m_pSpotThread->running() ) { m_iGoodFrame++; m_pVideoThread->getLastFrame( m_pImage->bits() ); m_pSpotThread->start(); } // else // qDebug("Dropping Frame"); } } /** No descriptions */ void VideoFrame::threshold( int p_iValue ) { m_pSpotThread->setSigmas( p_iValue ); } /** No descriptions */ void VideoFrame::scaleValue( int p_iValue ) { m_pSpotThread->setScalingMax( p_iValue ); } void VideoFrame::halt( bool p_zStop ) { if ( p_zStop == true ) { m_pVideoThread->stop(); m_pVideoThread->wait(); // Wait for video thread to finish m_pSpotThread->wait(); // Wait for spot thread to finish } else m_pVideoThread->start(); } /** Calculate the location of the central pixel. We do this by identifiying the position of the camera LEDs and getting the relative offsets. */ void VideoFrame::calcCenter() { double dX = 0.0, dX1 = 0.0, dX2 = 0.0, dX3 = 0.0, dX4 = 0.0; double dY = 0.0, dY1 = 0.0, dY2 = 0.0, dY3 = 0.0, dY4 = 0.0; int iNumLEDs = 0; m_iCenterX = m_iCenterY = 1; m_qlLEDs.clear(); m_qlSpots.clear(); QList& qlSpotList = m_pSpotThread->getSpotList(); for( VideoSpot* pActualSpot = qlSpotList.first(); pActualSpot; pActualSpot = qlSpotList.next() ) { // Check if this spot is compatible with the spot of the // upper left LED if ( pActualSpot->contains( LED1_X, LED1_Y ) ) { dX1 = pActualSpot->getX() + (CAMERA_X - LED1_X); dY1 = pActualSpot->getY() + (CAMERA_Y - LED1_Y); dX += dX1; dY += dY1; m_qlLEDs.append( new VideoSpot( pActualSpot->getX(), pActualSpot->getY()) ); iNumLEDs++; } // Check if this spot is compatible with the spot of the // upper right LED else if ( pActualSpot->contains( LED2_X, LED2_Y ) ) { dX2 = pActualSpot->getX() + (CAMERA_X - LED2_X); dY2 = pActualSpot->getY() + (CAMERA_Y - LED2_Y); dX += dX2; dY += dY2; m_qlLEDs.append( new VideoSpot( pActualSpot->getX(), pActualSpot->getY()) ); iNumLEDs++; } // Check if this spot is compatible with the spot of the // lower left LED else if ( pActualSpot->contains( LED3_X, LED3_Y ) ) { dX3 = pActualSpot->getX() + (CAMERA_X - LED3_X); dY3 = pActualSpot->getY() + (CAMERA_Y - LED3_Y); dX += dX3; dY += dY3; m_qlLEDs.append( new VideoSpot( pActualSpot->getX(), pActualSpot->getY()) ); iNumLEDs++; } // Check if this spot is compatible with the spot of the // lower right LED else if ( pActualSpot->contains( LED4_X, LED4_Y ) ) { dX4 = pActualSpot->getX() + (CAMERA_X - LED4_X); dY4 = pActualSpot->getY() + (CAMERA_Y - LED4_Y); dX += dX4; dY += dY4; m_qlLEDs.append( new VideoSpot( pActualSpot->getX(), pActualSpot->getY()) ); iNumLEDs++; } else m_qlSpots.append( new VideoSpot( pActualSpot->getX(), pActualSpot->getY()) ); } if( iNumLEDs != 0) { m_iCenterX = (int) rint(dX / iNumLEDs); m_iCenterY = (int) rint(dY / iNumLEDs); // qDebug("Center %d %d", m_iCenterX, m_iCenterY); } qDebug("Center at: %d %d -- with %d LEDs",m_iCenterX, m_iCenterY, iNumLEDs ); }