TuttleOFX  1
OverlayData.cpp
Go to the documentation of this file.
00001 #include "OverlayData.hpp"
00002 
00003 #include <tuttle/plugin/global.hpp>
00004 #include <tuttle/plugin/ImageGilProcessor.hpp>
00005 
00006 #include <terry/algorithm/transform_pixels.hpp>
00007 
00008 namespace tuttle {
00009 namespace plugin {
00010 namespace histogram {
00011 
00012 /**
00013  * Create a new empty data structure from scratch (data is null)
00014  * @param size : size of the current source clip (width*height) 
00015  */
00016 OverlayData::OverlayData( const OfxPointI& size, const int nbSteps, const int nbStepsCurvesFromSelection)
00017 : _currentTime( 0 )
00018 , _vNbStep( nbSteps )
00019 , _vNbStepCurveFromSelection( nbStepsCurvesFromSelection )
00020 , _isComputing( false )
00021 , _isDataInvalid( true )
00022 , _size( size )
00023 {
00024         clearAll( size );
00025 }
00026 
00027 /**
00028  * Update selection areas buffer to selection histograms overlay
00029  * @param args needed to have current time
00030  */
00031 void OverlayData::computeHistogramBufferData( HistogramBufferData& data, SView& srcView, const OfxTime time, const bool isSelection)
00032 {
00033         data._step = _vNbStep;                                  //prepare HistogramBuffer structure
00034         
00035         BOOST_ASSERT( _imgBool.shape()[0] == std::size_t(_size.y) );
00036         BOOST_ASSERT( _imgBool.shape()[1] == std::size_t(_size.x) );
00037         BOOST_ASSERT( srcView.width()  == std::size_t(_size.x) );
00038         BOOST_ASSERT( srcView.height() == std::size_t(_size.y) );
00039         
00040         Pixel_compute_histograms funct( _imgBool, data, isSelection );                  //functor declaration
00041         
00042         terry::algorithm::transform_pixels( srcView, funct );           //(USED functor reference)
00043         //boost::gil::for_each_pixel(srcView, funct);           (NOT USED)
00044         
00045         this->correctHistogramBufferData(data);                         //correct Histogram data to make up for discretization (average)
00046 }
00047 
00048 /**
00049  * @brief Set each values of the vector to null
00050  * @param v vector to reset
00051  * @param numberOfStep number of step (size of the vector)
00052  */
00053 void OverlayData::resetVectortoZero( HistogramVector& v, const std::size_t numberOfStep ) const
00054 {
00055         v.assign(numberOfStep,0);
00056 }
00057 
00058 /**
00059  * @brief Set each values of the vector to null
00060  * @param toReset HistogramBufferdata instance to reset
00061  */
00062 void OverlayData::resetHistogramBufferData( HistogramBufferData& toReset ) const
00063 {
00064         //Alpha
00065         this->resetVectortoZero(toReset._bufferAlpha,toReset._step);                            //alpha
00066         //RGB
00067         this->resetVectortoZero(toReset._bufferRed,toReset._step);                                      //R
00068         this->resetVectortoZero(toReset._bufferGreen,toReset._step);                            //G
00069         this->resetVectortoZero(toReset._bufferBlue,toReset._step);                                     //B
00070         //HLS
00071         this->resetVectortoZero(toReset._bufferHue,toReset._step);                                      //H
00072         this->resetVectortoZero(toReset._bufferLightness,toReset._step);                        //S
00073         this->resetVectortoZero(toReset._bufferSaturation,toReset._step);                       //L
00074 }
00075 
00076 /**
00077  * Correct the HistogramBufferData buffers wrong value with an average
00078  * @param toCorrect HistogramBufferData to correct
00079  */
00080 void OverlayData::correctHistogramBufferData(HistogramBufferData& toCorrect) const
00081 {
00082         //RGB
00083         this->correctVector(toCorrect._bufferRed);                                                                      //R
00084         this->correctVector(toCorrect._bufferGreen);                                                            //G
00085         this->correctVector(toCorrect._bufferBlue);                                                                     //B
00086         //HSL
00087         this->correctVector(toCorrect._bufferHue);                                                                      //H
00088         this->correctVector(toCorrect._bufferSaturation);                                                       //S
00089         this->correctVector(toCorrect._bufferLightness);                                                        //L
00090         
00091 }
00092 
00093 /**
00094  * Replace vector null values by average (better for histogram display) 
00095  * @param v vector to modify
00096  */
00097 void OverlayData::correctVector( HistogramVector& v ) const
00098 {
00099         for(unsigned int i=1; i<v.size()-1;++i)
00100         {
00101                 if(v.at(i) < 0.05)
00102                         v.at(i) = (Number)((v.at(i-1)+v.at(i+1))/2.0);//basic average
00103         }
00104 }
00105 
00106 /**
00107  * Compute average bars for display
00108  */
00109 void OverlayData::computeAverages()
00110 {
00111         //RGB
00112         this->_averageData._averageRed = computeAnAverage(this->_selectionData._bufferRed);                             //R
00113         this->_averageData._averageBlue = computeAnAverage(this->_selectionData._bufferBlue);                   //G
00114         this->_averageData._averageGreen = computeAnAverage(this->_selectionData._bufferGreen);                 //B
00115         //HSL
00116         this->_averageData._averageHue = computeAnAverage(this->_selectionData._bufferHue);                                     //H
00117         this->_averageData._averageSaturation = computeAnAverage(this->_selectionData._bufferSaturation);       //S
00118         this->_averageData._averageLightness = computeAnAverage(this->_selectionData._bufferLightness);         //L
00119 }
00120 
00121 /**
00122  * Compute a specific channel average
00123  * @param selection_v vector which contain the selection histogram
00124  * @return 
00125  */
00126 int OverlayData::computeAnAverage( const HistogramVector& selection_v ) const
00127 {
00128         int av = 0;
00129         int size = 0;
00130         for( std::size_t i=0; i < selection_v.size(); ++i)
00131         {
00132                 if(selection_v.at(i)!=0)
00133                 {
00134                         av+=selection_v.at(i)*i;
00135                         size+=selection_v.at(i);
00136                 }
00137         }
00138         if(size != 0) //avoid 0 division
00139                 av /=size;
00140         return av; //basic average
00141 }
00142 
00143 /**
00144  * Compute full data (averages,histograms buffer and selection buffer)
00145  * @param clipSrc       source of the plugin
00146  * @param time  current time
00147  * @param renderScale   current renderScale
00148  */
00149 void OverlayData::computeFullData( OFX::Clip* clipSrc, const OfxTime time, const OfxPointD& renderScale, const bool selectionOnly )
00150 {
00151         _isComputing = true;
00152         resetHistogramData();
00153         resetHistogramSelectionData();
00154         
00155         if( ! clipSrc->isConnected() )
00156         {       
00157                 _isComputing = false;
00158                 return;
00159         }
00160         
00161         //TUTTLE_TLOG_INFOS;
00162         //TUTTLE_TLOG_VAR( TUTTLE_INFO, "computeHistogramBufferData - fetchImage " << time );
00163         boost::scoped_ptr<OFX::Image> src( clipSrc->fetchImage(time, clipSrc->getCanonicalRod(time)) ); //scoped pointer of current source clip
00164         //TUTTLE_TLOG_INFOS;
00165         
00166         //TUTTLE_TLOG_VAR( TUTTLE_INFO, clipSrc->getPixelRod(time, renderScale) );
00167         //TUTTLE_TLOG_VAR( TUTTLE_INFO, clipSrc->getCanonicalRod(time, renderScale) );
00168         
00169         // Compatibility tests
00170         if( !src.get() ) // source isn't accessible
00171         {
00172                 _isComputing = false;
00173                 std::cout << "src is not accessible" << std::endl;
00174                 return;
00175         }
00176         
00177 //      TUTTLE_TLOG_VAR( TUTTLE_INFO, src->getBounds() );
00178 //      TUTTLE_TLOG_VAR( TUTTLE_INFO, src->getRegionOfDefinition() );
00179 
00180         if( src->getRowDistanceBytes() == 0 )//if source is wrong
00181         {
00182                 BOOST_THROW_EXCEPTION( exception::WrongRowBytes() );
00183         }
00184         OfxRectI srcPixelRod = clipSrc->getPixelRod( time, renderScale ); //get current RoD
00185         if( (clipSrc->getPixelDepth() != OFX::eBitDepthFloat) ||
00186                 (!clipSrc->getPixelComponents()) )
00187         {
00188                 BOOST_THROW_EXCEPTION( exception::Unsupported() << exception::user() + "Can't compute histogram data with the actual input clip format." );
00189                 return;
00190         }
00191         
00192 //      TUTTLE_TLOG_INFOS;
00193 //      BOOST_ASSERT( srcPixelRod == src->getBounds() );
00194         if( srcPixelRod != src->getBounds() )
00195         {
00196                 // the host does bad things !
00197                 // remove overlay... but do not crash.
00198                 TUTTLE_LOG_WARNING( "Image RoD and image bounds are not the same (rod=" << srcPixelRod << " , bounds:" << src->getBounds() << ")." );
00199                 return;
00200         }
00201 //      BOOST_ASSERT( srcPixelRod.x1 == src->getBounds().x1 );
00202 //      BOOST_ASSERT( srcPixelRod.y1 == src->getBounds().y1 );
00203 //      BOOST_ASSERT( srcPixelRod.x2 == src->getBounds().x2 );
00204 //      BOOST_ASSERT( srcPixelRod.y2 == src->getBounds().y2 );
00205         
00206         // Compute if source is OK
00207         SView srcView = tuttle::plugin::getGilView<SView>( src.get(), srcPixelRod, eImageOrientationIndependant );      // get current view from source clip
00208         
00209         OfxPointI imgSize;
00210         imgSize.x = srcView.width();
00211         imgSize.y = srcView.height();
00212         
00213 //      TUTTLE_LOG_INFOS;
00214         if( isImageSizeModified( imgSize ) )
00215         {
00216                 //TUTTLE_LOG_INFOS;
00217                 clearAll( imgSize );
00218         }
00219         
00220         //TUTTLE_LOG_INFOS;
00221         //Compute histogram buffer
00222         this->computeHistogramBufferData( _data, srcView, time);
00223         
00224         //TUTTLE_LOG_INFOS;
00225         //Compute selection histogram buffer
00226         this->computeHistogramBufferData( _selectionData, srcView, time, true );
00227         
00228         //TUTTLE_LOG_INFOS;
00229         //Compute averages
00230         this->computeAverages();
00231         _isComputing = false;
00232         
00233         _currentTime = time;
00234         //TUTTLE_LOG_INFOS;
00235 }
00236 
00237 /**
00238  * Reset the data (all values to 0)
00239  * @param size size of the current source clip
00240  */
00241 void OverlayData::resetHistogramData()
00242 {
00243         // Reset Histogram buffers
00244         this->_data._step = _vNbStep;
00245         this->resetHistogramBufferData(this->_data);
00246 }
00247 
00248 /**
00249  * Reset the data (all values to 0)
00250  * @param size size of the current source clip
00251  */
00252 void OverlayData::resetCurvesFromSelectionData()
00253 {
00254         // Reset Histogram buffers
00255         this->_curveFromSelection._step = _vNbStepCurveFromSelection;
00256         this->resetHistogramBufferData(this->_curveFromSelection);
00257 }
00258 
00259 /**
00260  * Reset the data (all values to 0)
00261  * @param size size of the current source clip
00262  */
00263 void OverlayData::resetHistogramSelectionData()
00264 {
00265         //Reset Histogram selection buffers
00266         this->_selectionData._step = _vNbStep;
00267         this->resetHistogramBufferData(this->_selectionData);
00268 }
00269 
00270 void OverlayData::removeSelection()
00271 {
00272         //allocate and initialize bool img tab 2D
00273         bool_2d::extent_gen extents;
00274         _imgBool.resize(extents[_size.y][_size.x]);
00275 
00276         for( unsigned int i=0; i < _imgBool.shape()[0]; ++i )
00277         {
00278                 for( unsigned int j=0; j < _imgBool.shape()[1]; ++j )
00279                 {
00280                         _imgBool[i][j] = 0;
00281                 }
00282         }
00283 }
00284 
00285 /**
00286  * Set all of averages to 0
00287  */
00288 void OverlayData::resetAverages()
00289 {
00290         //reset average
00291         this->_averageData._averageRed = 0;                     //R
00292         this->_averageData._averageGreen = 0;           //G
00293         this->_averageData._averageBlue = 0;            //B
00294         this->_averageData._averageHue = 0;                     //H
00295         this->_averageData._averageSaturation = 0;      //S
00296         this->_averageData._averageLightness = 0;       //L
00297 }
00298 
00299 /**
00300  * Check size (verify that imgBool always has the good size
00301  */
00302 bool OverlayData::isImageSizeModified( const OfxPointI& imgSize ) const
00303 {       
00304         return( _size.x != imgSize.x ||
00305                 _size.y != imgSize.y );
00306 }
00307 
00308 /**
00309  * Current time checker
00310  */
00311 bool OverlayData::isCurrentTimeModified(const OfxTime time) const
00312 {
00313                 return( _currentTime != time );
00314 }       
00315 
00316 /**
00317  * Compute only curve from selection data (averages,histograms buffer and selection buffer)
00318  * @param clipSrc       source of the plugin
00319  * @param time  current time
00320  * @param renderScale   current renderScale
00321  */
00322 void OverlayData::computeCurveFromSelectionData( OFX::Clip* clipSrc, const OfxTime time, const OfxPointD& renderScale)
00323 {
00324         _isComputing = true;
00325 
00326         resetCurvesFromSelectionData();
00327         
00328         if( ! clipSrc->isConnected() )
00329         {       
00330                 _isComputing = false;
00331                 return;
00332         }
00333         boost::scoped_ptr<OFX::Image> src( clipSrc->fetchImage(_currentTime, clipSrc->getCanonicalRod(_currentTime)) ); //scoped pointer of current source clip
00334 
00335         // Compatibility tests
00336         if( !src.get() ) // source isn't accessible
00337         {
00338                 _isComputing = false;
00339                 std::cout << "src is not accessible" << std::endl;
00340                 return;
00341         }
00342 
00343         if( src->getRowDistanceBytes() == 0 )//if source is wrong
00344         {
00345                 BOOST_THROW_EXCEPTION( exception::WrongRowBytes() );
00346         }
00347         OfxRectI srcPixelRod = clipSrc->getPixelRod( _currentTime, renderScale ); //get current RoD
00348         if( (clipSrc->getPixelDepth() != OFX::eBitDepthFloat) ||
00349                 (!clipSrc->getPixelComponents()) )
00350         {
00351                 BOOST_THROW_EXCEPTION( exception::Unsupported() << exception::user() + "Can't compute histogram data with the actual input clip format." );
00352         return;
00353         }
00354 
00355         if( srcPixelRod != src->getBounds() )
00356         {
00357                 // the host does bad things !
00358                 // remove overlay... but do not crash.
00359                 TUTTLE_LOG_WARNING( "Image RoD and image bounds are not the same (rod=" << srcPixelRod << " , bounds:" << src->getBounds() << ")." );
00360                 return;
00361         }
00362         
00363         // Compute if source is OK
00364         SView srcView = tuttle::plugin::getGilView<SView>( src.get(), srcPixelRod, eImageOrientationIndependant );      // get current view from source clip
00365         
00366         OfxPointI imgSize;
00367         imgSize.x = srcView.width();
00368         imgSize.y = srcView.height();
00369         
00370         if( isImageSizeModified( imgSize ) )
00371         {
00372                 clearAll( imgSize );
00373         }
00374         //Compute histogram buffer
00375         Pixel_compute_histograms funct( _imgBool,_curveFromSelection, true);                    //functor declaration
00376         terry::algorithm::transform_pixels( srcView, funct );           //(USED functor reference)
00377         
00378         this->correctHistogramBufferData(_curveFromSelection);                          //correct Histogram data to make up for discretization (average)
00379 }
00380 
00381 }
00382 }
00383 }