1 /*#****************************************************************************** 2 ** IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. 3 ** 4 ** By downloading, copying, installing or using the software you agree to this license. 5 ** If you do not agree to this license, do not download, install, 6 ** copy or use the software. 7 ** 8 ** 9 ** bioinspired : interfaces allowing OpenCV users to integrate Human Vision System models. Presented models originate from Jeanny Herault's original research and have been reused and adapted by the author&collaborators for computed vision applications since his thesis with Alice Caplier at Gipsa-Lab. 10 ** Use: extract still images & image sequences features, from contours details to motion spatio-temporal features, etc. for high level visual scene analysis. Also contribute to image enhancement/compression such as tone mapping. 11 ** 12 ** Maintainers : Listic lab (code author current affiliation & applications) and Gipsa Lab (original research origins & applications) 13 ** 14 ** Creation - enhancement process 2007-2011 15 ** Author: Alexandre Benoit (benoit.alexandre.vision@gmail.com), LISTIC lab, Annecy le vieux, France 16 ** 17 ** Theses algorithm have been developped by Alexandre BENOIT since his thesis with Alice Caplier at Gipsa-Lab (www.gipsa-lab.inpg.fr) and the research he pursues at LISTIC Lab (www.listic.univ-savoie.fr). 18 ** Refer to the following research paper for more information: 19 ** Benoit A., Caplier A., Durette B., Herault, J., "USING HUMAN VISUAL SYSTEM MODELING FOR BIO-INSPIRED LOW LEVEL IMAGE PROCESSING", Elsevier, Computer Vision and Image Understanding 114 (2010), pp. 758-773, DOI: http://dx.doi.org/10.1016/j.cviu.2010.01.011 20 ** This work have been carried out thanks to Jeanny Herault who's research and great discussions are the basis of all this work, please take a look at his book: 21 ** Vision: Images, Signals and Neural Networks: Models of Neural Processing in Visual Perception (Progress in Neural Processing),By: Jeanny Herault, ISBN: 9814273686. WAPI (Tower ID): 113266891. 22 ** 23 ** The retina filter includes the research contributions of phd/research collegues from which code has been redrawn by the author : 24 ** _take a look at the retinacolor.hpp module to discover Brice Chaix de Lavarene color mosaicing/demosaicing and the reference paper: 25 ** ====> B. Chaix de Lavarene, D. Alleysson, B. Durette, J. Herault (2007). "Efficient demosaicing through recursive filtering", IEEE International Conference on Image Processing ICIP 2007 26 ** _take a look at imagelogpolprojection.hpp to discover retina spatial log sampling which originates from Barthelemy Durette phd with Jeanny Herault. A Retina / V1 cortex projection is also proposed and originates from Jeanny's discussions. 27 ** ====> more informations in the above cited Jeanny Heraults's book. 28 ** 29 ** License Agreement 30 ** For Open Source Computer Vision Library 31 ** 32 ** Copyright (C) 2000-2008, Intel Corporation, all rights reserved. 33 ** Copyright (C) 2008-2011, Willow Garage Inc., all rights reserved. 34 ** 35 ** For Human Visual System tools (bioinspired) 36 ** Copyright (C) 2007-2011, LISTIC Lab, Annecy le Vieux and GIPSA Lab, Grenoble, France, all rights reserved. 37 ** 38 ** Third party copyrights are property of their respective owners. 39 ** 40 ** Redistribution and use in source and binary forms, with or without modification, 41 ** are permitted provided that the following conditions are met: 42 ** 43 ** * Redistributions of source code must retain the above copyright notice, 44 ** this list of conditions and the following disclaimer. 45 ** 46 ** * Redistributions in binary form must reproduce the above copyright notice, 47 ** this list of conditions and the following disclaimer in the documentation 48 ** and/or other materials provided with the distribution. 49 ** 50 ** * The name of the copyright holders may not be used to endorse or promote products 51 ** derived from this software without specific prior written permission. 52 ** 53 ** This software is provided by the copyright holders and contributors "as is" and 54 ** any express or implied warranties, including, but not limited to, the implied 55 ** warranties of merchantability and fitness for a particular purpose are disclaimed. 56 ** In no event shall the Intel Corporation or contributors be liable for any direct, 57 ** indirect, incidental, special, exemplary, or consequential damages 58 ** (including, but not limited to, procurement of substitute goods or services; 59 ** loss of use, data, or profits; or business interruption) however caused 60 ** and on any theory of liability, whether in contract, strict liability, 61 ** or tort (including negligence or otherwise) arising in any way out of 62 ** the use of this software, even if advised of the possibility of such damage. 63 *******************************************************************************/ 64 65 #include "precomp.hpp" 66 67 #include "retinafilter.hpp" 68 69 // @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr, Gipsa-Lab, France: www.gipsa-lab.inpg.fr/ 70 71 #include <iostream> 72 #include <cmath> 73 74 namespace cv 75 { 76 namespace bioinspired 77 { 78 // standard constructor without any log sampling of the input frame RetinaFilter(const unsigned int sizeRows,const unsigned int sizeColumns,const bool colorMode,const int samplingMethod,const bool useRetinaLogSampling,const double reductionFactor,const double samplingStrength)79 RetinaFilter::RetinaFilter(const unsigned int sizeRows, const unsigned int sizeColumns, const bool colorMode, const int samplingMethod, const bool useRetinaLogSampling, const double reductionFactor, const double samplingStrength) 80 : 81 _retinaParvoMagnoMappedFrame(0), 82 _retinaParvoMagnoMapCoefTable(0), 83 _photoreceptorsPrefilter((1-(int)useRetinaLogSampling)*sizeRows+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeRows, reductionFactor), (1-(int)useRetinaLogSampling)*sizeColumns+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeColumns, reductionFactor), 4), 84 _ParvoRetinaFilter((1-(int)useRetinaLogSampling)*sizeRows+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeRows, reductionFactor), (1-(int)useRetinaLogSampling)*sizeColumns+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeColumns, reductionFactor)), 85 _MagnoRetinaFilter((1-(int)useRetinaLogSampling)*sizeRows+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeRows, reductionFactor), (1-(int)useRetinaLogSampling)*sizeColumns+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeColumns, reductionFactor)), 86 _colorEngine((1-(int)useRetinaLogSampling)*sizeRows+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeRows, reductionFactor), (1-(int)useRetinaLogSampling)*sizeColumns+useRetinaLogSampling*ImageLogPolProjection::predictOutputSize(sizeColumns, reductionFactor), samplingMethod), 87 // configure retina photoreceptors log sampling... if necessary 88 _photoreceptorsLogSampling(NULL) 89 { 90 91 #ifdef RETINADEBUG 92 std::cout<<"RetinaFilter::size( "<<_photoreceptorsPrefilter.getNBrows()<<", "<<_photoreceptorsPrefilter.getNBcolumns()<<")"<<" =? "<<_photoreceptorsPrefilter.getNBpixels()<<std::endl; 93 #endif 94 if (useRetinaLogSampling) 95 { 96 _photoreceptorsLogSampling = new ImageLogPolProjection(sizeRows, sizeColumns, ImageLogPolProjection::RETINALOGPROJECTION, true); 97 if (!_photoreceptorsLogSampling->initProjection(reductionFactor, samplingStrength)) 98 { 99 std::cerr<<"RetinaFilter::Problem initializing photoreceptors log sampling, could not setup retina filter"<<std::endl; 100 delete _photoreceptorsLogSampling; 101 _photoreceptorsLogSampling=NULL; 102 } 103 else 104 { 105 #ifdef RETINADEBUG 106 std::cout<<"_photoreceptorsLogSampling::size( "<<_photoreceptorsLogSampling->getNBrows()<<", "<<_photoreceptorsLogSampling->getNBcolumns()<<")"<<" =? "<<_photoreceptorsLogSampling->getNBpixels()<<std::endl; 107 #endif 108 } 109 } 110 111 // set default processing activities 112 _useParvoOutput=true; 113 _useMagnoOutput=true; 114 115 _useColorMode=colorMode; 116 117 // create hybrid output and related coefficient table 118 _createHybridTable(); 119 120 // set default parameters 121 setGlobalParameters(); 122 123 // stability controls values init 124 _setInitPeriodCount(); 125 _globalTemporalConstant=25; 126 127 // reset all buffers 128 clearAllBuffers(); 129 130 131 // std::cout<<"RetinaFilter::size( "<<this->getNBrows()<<", "<<this->getNBcolumns()<<")"<<_filterOutput.size()<<" =? "<<_filterOutput.getNBpixels()<<std::endl; 132 133 } 134 135 // destructor ~RetinaFilter()136 RetinaFilter::~RetinaFilter() 137 { 138 if (_photoreceptorsLogSampling!=NULL) 139 delete _photoreceptorsLogSampling; 140 } 141 142 // function that clears all buffers of the object clearAllBuffers()143 void RetinaFilter::clearAllBuffers() 144 { 145 _photoreceptorsPrefilter.clearAllBuffers(); 146 _ParvoRetinaFilter.clearAllBuffers(); 147 _MagnoRetinaFilter.clearAllBuffers(); 148 _colorEngine.clearAllBuffers(); 149 if (_photoreceptorsLogSampling!=NULL) 150 _photoreceptorsLogSampling->clearAllBuffers(); 151 // stability controls value init 152 _setInitPeriodCount(); 153 } 154 155 /** 156 * resize retina filter object (resize all allocated buffers 157 * @param NBrows: the new height size 158 * @param NBcolumns: the new width size 159 */ resize(const unsigned int NBrows,const unsigned int NBcolumns)160 void RetinaFilter::resize(const unsigned int NBrows, const unsigned int NBcolumns) 161 { 162 unsigned int rows=NBrows, cols=NBcolumns; 163 164 // resize optionnal member and adjust other modules size if required 165 if (_photoreceptorsLogSampling) 166 { 167 _photoreceptorsLogSampling->resize(NBrows, NBcolumns); 168 rows=_photoreceptorsLogSampling->getOutputNBrows(); 169 cols=_photoreceptorsLogSampling->getOutputNBcolumns(); 170 } 171 172 _photoreceptorsPrefilter.resize(rows, cols); 173 _ParvoRetinaFilter.resize(rows, cols); 174 _MagnoRetinaFilter.resize(rows, cols); 175 _colorEngine.resize(rows, cols); 176 177 // reset parvo magno mapping 178 _createHybridTable(); 179 180 // clean buffers 181 clearAllBuffers(); 182 183 } 184 185 // stability controls value init _setInitPeriodCount()186 void RetinaFilter::_setInitPeriodCount() 187 { 188 189 // find out the maximum temporal constant value and apply a security factor 190 // false value (obviously too long) but appropriate for simple use 191 _globalTemporalConstant=(unsigned int)(_ParvoRetinaFilter.getPhotoreceptorsTemporalConstant()+_ParvoRetinaFilter.getHcellsTemporalConstant()+_MagnoRetinaFilter.getTemporalConstant()); 192 // reset frame counter 193 _ellapsedFramesSinceLastReset=0; 194 } 195 _createHybridTable()196 void RetinaFilter::_createHybridTable() 197 { 198 // create hybrid output and related coefficient table 199 _retinaParvoMagnoMappedFrame.resize(_photoreceptorsPrefilter.getNBpixels()); 200 201 _retinaParvoMagnoMapCoefTable.resize(_photoreceptorsPrefilter.getNBpixels()*2); 202 203 // fill _hybridParvoMagnoCoefTable 204 int i, j, halfRows=_photoreceptorsPrefilter.getNBrows()/2, halfColumns=_photoreceptorsPrefilter.getNBcolumns()/2; 205 float *hybridParvoMagnoCoefTablePTR= &_retinaParvoMagnoMapCoefTable[0]; 206 float minDistance=MIN(halfRows, halfColumns)*0.7f; 207 for (i=0;i<(int)_photoreceptorsPrefilter.getNBrows();++i) 208 { 209 for (j=0;j<(int)_photoreceptorsPrefilter.getNBcolumns();++j) 210 { 211 float distanceToCenter=std::sqrt(((float)(i-halfRows)*(i-halfRows)+(j-halfColumns)*(j-halfColumns))); 212 if (distanceToCenter<minDistance) 213 { 214 float a=*(hybridParvoMagnoCoefTablePTR++)=0.5f+0.5f*(float)cos(CV_PI*distanceToCenter/minDistance); 215 *(hybridParvoMagnoCoefTablePTR++)=1.f-a; 216 }else 217 { 218 *(hybridParvoMagnoCoefTablePTR++)=0.f; 219 *(hybridParvoMagnoCoefTablePTR++)=1.f; 220 } 221 } 222 } 223 } 224 225 // setup parameters function and global data filling setGlobalParameters(const float OPLspatialResponse1,const float OPLtemporalresponse1,const float OPLassymetryGain,const float OPLspatialResponse2,const float OPLtemporalresponse2,const float LPfilterSpatialResponse,const float LPfilterGain,const float LPfilterTemporalresponse,const float MovingContoursExtractorCoefficient,const bool normalizeParvoOutput_0_maxOutputValue,const bool normalizeMagnoOutput_0_maxOutputValue,const float maxOutputValue,const float maxInputValue,const float meanValue)226 void RetinaFilter::setGlobalParameters(const float OPLspatialResponse1, const float OPLtemporalresponse1, const float OPLassymetryGain, const float OPLspatialResponse2, const float OPLtemporalresponse2, const float LPfilterSpatialResponse, const float LPfilterGain, const float LPfilterTemporalresponse, const float MovingContoursExtractorCoefficient, const bool normalizeParvoOutput_0_maxOutputValue, const bool normalizeMagnoOutput_0_maxOutputValue, const float maxOutputValue, const float maxInputValue, const float meanValue) 227 { 228 _normalizeParvoOutput_0_maxOutputValue=normalizeParvoOutput_0_maxOutputValue; 229 _normalizeMagnoOutput_0_maxOutputValue=normalizeMagnoOutput_0_maxOutputValue; 230 _maxOutputValue=maxOutputValue; 231 _photoreceptorsPrefilter.setV0CompressionParameter(0.9f, maxInputValue, meanValue); 232 _photoreceptorsPrefilter.setLPfilterParameters(10, 0, 1.5, 1); // keeps low pass filter with high cut frequency in memory (usefull for the tone mapping function) 233 _photoreceptorsPrefilter.setLPfilterParameters(10, 0, 3.0, 2); // keeps low pass filter with low cut frequency in memory (usefull for the tone mapping function) 234 _photoreceptorsPrefilter.setLPfilterParameters(0, 0, 10, 3); // keeps low pass filter with low cut frequency in memory (usefull for the tone mapping function) 235 //this->setV0CompressionParameter(0.6, maxInputValue, meanValue); // keeps log compression sensitivity parameter (usefull for the tone mapping function) 236 _ParvoRetinaFilter.setOPLandParvoFiltersParameters(0,OPLtemporalresponse1, OPLspatialResponse1, OPLassymetryGain, OPLtemporalresponse2, OPLspatialResponse2); 237 _ParvoRetinaFilter.setV0CompressionParameter(0.9f, maxInputValue, meanValue); 238 _MagnoRetinaFilter.setCoefficientsTable(LPfilterGain, LPfilterTemporalresponse, LPfilterSpatialResponse, MovingContoursExtractorCoefficient, 0, 2.0f*LPfilterSpatialResponse); 239 _MagnoRetinaFilter.setV0CompressionParameter(0.7f, maxInputValue, meanValue); 240 241 // stability controls value init 242 _setInitPeriodCount(); 243 } 244 checkInput(const std::valarray<float> & input,const bool)245 bool RetinaFilter::checkInput(const std::valarray<float> &input, const bool) 246 { 247 248 BasicRetinaFilter *inputTarget=&_photoreceptorsPrefilter; 249 if (_photoreceptorsLogSampling) 250 inputTarget=_photoreceptorsLogSampling; 251 252 bool test=input.size()==inputTarget->getNBpixels() || input.size()==(inputTarget->getNBpixels()*3) ; 253 if (!test) 254 { 255 std::cerr<<"RetinaFilter::checkInput: input buffer does not match retina buffer size, conversion aborted"<<std::endl; 256 std::cout<<"RetinaFilter::checkInput: input size="<<input.size()<<" / "<<"retina size="<<inputTarget->getNBpixels()<<std::endl; 257 return false; 258 } 259 260 return true; 261 } 262 263 // main function that runs the filter for a given input frame runFilter(const std::valarray<float> & imageInput,const bool useAdaptiveFiltering,const bool processRetinaParvoMagnoMapping,const bool useColorMode,const bool inputIsColorMultiplexed)264 bool RetinaFilter::runFilter(const std::valarray<float> &imageInput, const bool useAdaptiveFiltering, const bool processRetinaParvoMagnoMapping, const bool useColorMode, const bool inputIsColorMultiplexed) 265 { 266 // preliminary check 267 bool processSuccess=true; 268 if (!checkInput(imageInput, useColorMode)) 269 return false; 270 271 // run the color multiplexing if needed and compute each suub filter of the retina: 272 // -> local adaptation 273 // -> contours OPL extraction 274 // -> moving contours extraction 275 276 // stability controls value update 277 ++_ellapsedFramesSinceLastReset; 278 279 _useColorMode=useColorMode; 280 281 /* pointer to the appropriate input data after, 282 * by default, if graylevel mode, the input is processed, 283 * if color or something else must be considered, specific preprocessing are applied 284 */ 285 286 const std::valarray<float> *selectedPhotoreceptorsLocalAdaptationInput= &imageInput; 287 const std::valarray<float> *selectedPhotoreceptorsColorInput=&imageInput; 288 289 //********** Following is input data specific photoreceptors processing 290 if (_photoreceptorsLogSampling) 291 { 292 _photoreceptorsLogSampling->runProjection(imageInput, useColorMode); 293 selectedPhotoreceptorsColorInput=selectedPhotoreceptorsLocalAdaptationInput=&(_photoreceptorsLogSampling->getSampledFrame()); 294 } 295 296 if (useColorMode&& (!inputIsColorMultiplexed)) // not multiplexed color input case 297 { 298 _colorEngine.runColorMultiplexing(*selectedPhotoreceptorsColorInput); 299 selectedPhotoreceptorsLocalAdaptationInput=&(_colorEngine.getMultiplexedFrame()); 300 } 301 302 //********** Following is generic Retina processing 303 304 // photoreceptors local adaptation 305 _photoreceptorsPrefilter.runFilter_LocalAdapdation(*selectedPhotoreceptorsLocalAdaptationInput, _ParvoRetinaFilter.getHorizontalCellsOutput()); 306 // safety pixel values checks 307 //_photoreceptorsPrefilter.normalizeGrayOutput_0_maxOutputValue(_maxOutputValue); 308 309 // run parvo filter 310 _ParvoRetinaFilter.runFilter(_photoreceptorsPrefilter.getOutput(), _useParvoOutput); 311 312 if (_useParvoOutput) 313 { 314 _ParvoRetinaFilter.normalizeGrayOutputCentredSigmoide(); // models the saturation of the cells, usefull for visualisation of the ON-OFF Parvo Output, Bipolar cells outputs do not change !!! 315 _ParvoRetinaFilter.centerReductImageLuminance(); // best for further spectrum analysis 316 317 if (_normalizeParvoOutput_0_maxOutputValue) 318 _ParvoRetinaFilter.normalizeGrayOutput_0_maxOutputValue(_maxOutputValue); 319 } 320 321 if (_useParvoOutput&&_useMagnoOutput) 322 { 323 _MagnoRetinaFilter.runFilter(_ParvoRetinaFilter.getBipolarCellsON(), _ParvoRetinaFilter.getBipolarCellsOFF()); 324 if (_normalizeMagnoOutput_0_maxOutputValue) 325 { 326 _MagnoRetinaFilter.normalizeGrayOutput_0_maxOutputValue(_maxOutputValue); 327 } 328 _MagnoRetinaFilter.normalizeGrayOutputNearZeroCentreredSigmoide(); 329 } 330 331 if (_useParvoOutput&&_useMagnoOutput&&processRetinaParvoMagnoMapping) 332 { 333 _processRetinaParvoMagnoMapping(); 334 if (_useColorMode) 335 _colorEngine.runColorDemultiplexing(_retinaParvoMagnoMappedFrame, useAdaptiveFiltering, _maxOutputValue);//_ColorEngine->getMultiplexedFrame());//_ParvoRetinaFilter->getPhotoreceptorsLPfilteringOutput()); 336 337 return processSuccess; 338 } 339 340 if (_useParvoOutput&&_useColorMode) 341 { 342 _colorEngine.runColorDemultiplexing(_ParvoRetinaFilter.getOutput(), useAdaptiveFiltering, _maxOutputValue);//_ColorEngine->getMultiplexedFrame());//_ParvoRetinaFilter->getPhotoreceptorsLPfilteringOutput()); 343 // compute A Cr1 Cr2 to LMS color space conversion 344 //if (true) 345 // _applyImageColorSpaceConversion(_ColorEngine->getChrominance(), lmsTempBuffer.Buffer(), _LMStoACr1Cr2); 346 } 347 348 return processSuccess; 349 } 350 getContours()351 const std::valarray<float> &RetinaFilter::getContours() 352 { 353 if (_useColorMode) 354 return _colorEngine.getLuminance(); 355 else 356 return _ParvoRetinaFilter.getOutput(); 357 } 358 359 // run the initilized retina filter in order to perform gray image tone mapping, after this call all retina outputs are updated runGrayToneMapping(const std::valarray<float> & grayImageInput,std::valarray<float> & grayImageOutput,const float PhotoreceptorsCompression,const float ganglionCellsCompression)360 void RetinaFilter::runGrayToneMapping(const std::valarray<float> &grayImageInput, std::valarray<float> &grayImageOutput, const float PhotoreceptorsCompression, const float ganglionCellsCompression) 361 { 362 // preliminary check 363 if (!checkInput(grayImageInput, false)) 364 return; 365 366 this->_runGrayToneMapping(grayImageInput, grayImageOutput, PhotoreceptorsCompression, ganglionCellsCompression); 367 } 368 369 // run the initilized retina filter in order to perform gray image tone mapping, after this call all retina outputs are updated _runGrayToneMapping(const std::valarray<float> & grayImageInput,std::valarray<float> & grayImageOutput,const float PhotoreceptorsCompression,const float ganglionCellsCompression)370 void RetinaFilter::_runGrayToneMapping(const std::valarray<float> &grayImageInput, std::valarray<float> &grayImageOutput, const float PhotoreceptorsCompression, const float ganglionCellsCompression) 371 { 372 // stability controls value update 373 ++_ellapsedFramesSinceLastReset; 374 375 std::valarray<float> temp2(grayImageInput.size()); 376 377 // apply tone mapping on the multiplexed image 378 // -> photoreceptors local adaptation (large area adaptation) 379 _photoreceptorsPrefilter.runFilter_LPfilter(grayImageInput, grayImageOutput, 2); // compute low pass filtering modeling the horizontal cells filtering to acess local luminance 380 _photoreceptorsPrefilter.setV0CompressionParameterToneMapping(1.f-PhotoreceptorsCompression, grayImageOutput.max(), 1.f*grayImageOutput.sum()/(float)_photoreceptorsPrefilter.getNBpixels()); 381 _photoreceptorsPrefilter.runFilter_LocalAdapdation(grayImageInput, grayImageOutput, temp2); // adapt contrast to local luminance 382 383 // -> ganglion cells local adaptation (short area adaptation) 384 _photoreceptorsPrefilter.runFilter_LPfilter(temp2, grayImageOutput, 1); // compute low pass filtering (high cut frequency (remove spatio-temporal noise) 385 _photoreceptorsPrefilter.setV0CompressionParameterToneMapping(1.f-ganglionCellsCompression, temp2.max(), 1.f*temp2.sum()/(float)_photoreceptorsPrefilter.getNBpixels()); 386 _photoreceptorsPrefilter.runFilter_LocalAdapdation(temp2, grayImageOutput, grayImageOutput); // adapt contrast to local luminance 387 } 388 389 // run the initilized retina filter in order to perform color tone mapping, after this call all retina outputs are updated runRGBToneMapping(const std::valarray<float> & RGBimageInput,std::valarray<float> & RGBimageOutput,const bool useAdaptiveFiltering,const float PhotoreceptorsCompression,const float ganglionCellsCompression)390 void RetinaFilter::runRGBToneMapping(const std::valarray<float> &RGBimageInput, std::valarray<float> &RGBimageOutput, const bool useAdaptiveFiltering, const float PhotoreceptorsCompression, const float ganglionCellsCompression) 391 { 392 // preliminary check 393 if (!checkInput(RGBimageInput, true)) 394 return; 395 396 // multiplex the image with the color sampling method specified in the constructor 397 _colorEngine.runColorMultiplexing(RGBimageInput); 398 399 // apply tone mapping on the multiplexed image 400 _runGrayToneMapping(_colorEngine.getMultiplexedFrame(), RGBimageOutput, PhotoreceptorsCompression, ganglionCellsCompression); 401 402 // demultiplex tone maped image 403 _colorEngine.runColorDemultiplexing(RGBimageOutput, useAdaptiveFiltering, _photoreceptorsPrefilter.getMaxInputValue());//_ColorEngine->getMultiplexedFrame());//_ParvoRetinaFilter->getPhotoreceptorsLPfilteringOutput()); 404 405 // rescaling result between 0 and 255 406 _colorEngine.normalizeRGBOutput_0_maxOutputValue(255.0); 407 408 // return the result 409 RGBimageOutput=_colorEngine.getDemultiplexedColorFrame(); 410 } 411 runLMSToneMapping(const std::valarray<float> &,std::valarray<float> &,const bool,const float,const float)412 void RetinaFilter::runLMSToneMapping(const std::valarray<float> &, std::valarray<float> &, const bool, const float, const float) 413 { 414 std::cerr<<"not working, sorry"<<std::endl; 415 416 /* // preliminary check 417 const std::valarray<float> &bufferInput=checkInput(LMSimageInput, true); 418 if (!bufferInput) 419 return NULL; 420 421 if (!_useColorMode) 422 std::cerr<<"RetinaFilter::Can not call tone mapping oeration if the retina filter was created for gray scale images"<<std::endl; 423 424 // create a temporary buffer of size nrows, Mcolumns, 3 layers 425 std::valarray<float> lmsTempBuffer(LMSimageInput); 426 std::cout<<"RetinaFilter::--->min LMS value="<<lmsTempBuffer.min()<<std::endl; 427 428 // setup local adaptation parameter at the photoreceptors level 429 setV0CompressionParameter(PhotoreceptorsCompression, _maxInputValue); 430 // get the local energy of each color channel 431 // ->L 432 _spatiotemporalLPfilter(LMSimageInput, _filterOutput, 1); 433 setV0CompressionParameterToneMapping(PhotoreceptorsCompression, _maxInputValue, this->sum()/_NBpixels); 434 _localLuminanceAdaptation(LMSimageInput, _filterOutput, lmsTempBuffer.Buffer()); 435 // ->M 436 _spatiotemporalLPfilter(LMSimageInput+_NBpixels, _filterOutput, 1); 437 setV0CompressionParameterToneMapping(PhotoreceptorsCompression, _maxInputValue, this->sum()/_NBpixels); 438 _localLuminanceAdaptation(LMSimageInput+_NBpixels, _filterOutput, lmsTempBuffer.Buffer()+_NBpixels); 439 // ->S 440 _spatiotemporalLPfilter(LMSimageInput+_NBpixels*2, _filterOutput, 1); 441 setV0CompressionParameterToneMapping(PhotoreceptorsCompression, _maxInputValue, this->sum()/_NBpixels); 442 _localLuminanceAdaptation(LMSimageInput+_NBpixels*2, _filterOutput, lmsTempBuffer.Buffer()+_NBpixels*2); 443 444 // eliminate negative values 445 for (unsigned int i=0;i<lmsTempBuffer.size();++i) 446 if (lmsTempBuffer.Buffer()[i]<0) 447 lmsTempBuffer.Buffer()[i]=0; 448 std::cout<<"RetinaFilter::->min LMS value="<<lmsTempBuffer.min()<<std::endl; 449 450 // compute LMS to A Cr1 Cr2 color space conversion 451 _applyImageColorSpaceConversion(lmsTempBuffer.Buffer(), lmsTempBuffer.Buffer(), _LMStoACr1Cr2); 452 453 TemplateBuffer <float> acr1cr2TempBuffer(_NBrows, _NBcolumns, 3); 454 memcpy(acr1cr2TempBuffer.Buffer(), lmsTempBuffer.Buffer(), sizeof(float)*_NBpixels*3); 455 456 // compute A Cr1 Cr2 to LMS color space conversion 457 _applyImageColorSpaceConversion(acr1cr2TempBuffer.Buffer(), lmsTempBuffer.Buffer(), _ACr1Cr2toLMS); 458 459 // eliminate negative values 460 for (unsigned int i=0;i<lmsTempBuffer.size();++i) 461 if (lmsTempBuffer.Buffer()[i]<0) 462 lmsTempBuffer.Buffer()[i]=0; 463 464 // rewrite output to the appropriate buffer 465 _colorEngine->setDemultiplexedColorFrame(lmsTempBuffer.Buffer()); 466 */ 467 } 468 469 // return image with center Parvo and peripheral Magno channels _processRetinaParvoMagnoMapping()470 void RetinaFilter::_processRetinaParvoMagnoMapping() 471 { 472 float *hybridParvoMagnoPTR= &_retinaParvoMagnoMappedFrame[0]; 473 const float *parvoOutputPTR= get_data(_ParvoRetinaFilter.getOutput()); 474 const float *magnoXOutputPTR= get_data(_MagnoRetinaFilter.getOutput()); 475 float *hybridParvoMagnoCoefTablePTR= &_retinaParvoMagnoMapCoefTable[0]; 476 477 for (unsigned int i=0 ; i<_photoreceptorsPrefilter.getNBpixels() ; ++i, hybridParvoMagnoCoefTablePTR+=2) 478 { 479 float hybridValue=*(parvoOutputPTR++)**(hybridParvoMagnoCoefTablePTR)+*(magnoXOutputPTR++)**(hybridParvoMagnoCoefTablePTR+1); 480 *(hybridParvoMagnoPTR++)=hybridValue; 481 } 482 483 TemplateBuffer<float>::normalizeGrayOutput_0_maxOutputValue(&_retinaParvoMagnoMappedFrame[0], _photoreceptorsPrefilter.getNBpixels()); 484 485 } 486 getParvoFoveaResponse(std::valarray<float> & parvoFovealResponse)487 bool RetinaFilter::getParvoFoveaResponse(std::valarray<float> &parvoFovealResponse) 488 { 489 if (!_useParvoOutput) 490 return false; 491 if (parvoFovealResponse.size() != _ParvoRetinaFilter.getNBpixels()) 492 return false; 493 494 const float *parvoOutputPTR= get_data(_ParvoRetinaFilter.getOutput()); 495 float *fovealParvoResponsePTR= &parvoFovealResponse[0]; 496 float *hybridParvoMagnoCoefTablePTR= &_retinaParvoMagnoMapCoefTable[0]; 497 498 for (unsigned int i=0 ; i<_photoreceptorsPrefilter.getNBpixels() ; ++i, hybridParvoMagnoCoefTablePTR+=2) 499 { 500 *(fovealParvoResponsePTR++)=*(parvoOutputPTR++)**(hybridParvoMagnoCoefTablePTR); 501 } 502 503 return true; 504 } 505 506 // method to retrieve the parafoveal magnocellular pathway response (no energy motion in fovea) getMagnoParaFoveaResponse(std::valarray<float> & magnoParafovealResponse)507 bool RetinaFilter::getMagnoParaFoveaResponse(std::valarray<float> &magnoParafovealResponse) 508 { 509 if (!_useMagnoOutput) 510 return false; 511 if (magnoParafovealResponse.size() != _MagnoRetinaFilter.getNBpixels()) 512 return false; 513 514 const float *magnoXOutputPTR= get_data(_MagnoRetinaFilter.getOutput()); 515 float *parafovealMagnoResponsePTR=&magnoParafovealResponse[0]; 516 float *hybridParvoMagnoCoefTablePTR=&_retinaParvoMagnoMapCoefTable[0]+1; 517 518 for (unsigned int i=0 ; i<_photoreceptorsPrefilter.getNBpixels() ; ++i, hybridParvoMagnoCoefTablePTR+=2) 519 { 520 *(parafovealMagnoResponsePTR++)=*(magnoXOutputPTR++)**(hybridParvoMagnoCoefTablePTR); 521 } 522 523 return true; 524 } 525 }// end of namespace bioinspired 526 }// end of namespace cv 527