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