TuttleOFX
1
|
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 }