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 <iostream>
68 #include <cstdlib>
69 #include "basicretinafilter.hpp"
70 #include <cmath>
71 
72 
73 namespace cv
74 {
75 namespace bioinspired
76 {
77 // @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr Gipsa-Lab, France: www.gipsa-lab.inpg.fr/
78 
79 //////////////////////////////////////////////////////////
80 //                 BASIC RETINA FILTER
81 //////////////////////////////////////////////////////////
82 
83 // Constructor and Desctructor of the basic retina filter
BasicRetinaFilter(const unsigned int NBrows,const unsigned int NBcolumns,const unsigned int parametersListSize,const bool useProgressiveFilter)84 BasicRetinaFilter::BasicRetinaFilter(const unsigned int NBrows, const unsigned int NBcolumns, const unsigned int parametersListSize, const bool useProgressiveFilter)
85 :_filterOutput(NBrows, NBcolumns),
86  _localBuffer(NBrows*NBcolumns),
87  _filteringCoeficientsTable(3*parametersListSize),
88  _progressiveSpatialConstant(0),// pointer to a local table containing local spatial constant (allocated with the object)
89  _progressiveGain(0)
90 {
91 #ifdef T_BASIC_RETINA_ELEMENT_DEBUG
92     std::cout<<"BasicRetinaFilter::BasicRetinaFilter: new filter, size="<<NBrows<<", "<<NBcolumns<<std::endl;
93 #endif
94     _halfNBrows=_filterOutput.getNBrows()/2;
95     _halfNBcolumns=_filterOutput.getNBcolumns()/2;
96 
97     if (useProgressiveFilter)
98     {
99 #ifdef T_BASIC_RETINA_ELEMENT_DEBUG
100         std::cout<<"BasicRetinaFilter::BasicRetinaFilter: _progressiveSpatialConstant_Tbuffer"<<std::endl;
101 #endif
102         _progressiveSpatialConstant.resize(_filterOutput.size());
103 #ifdef T_BASIC_RETINA_ELEMENT_DEBUG
104         std::cout<<"BasicRetinaFilter::BasicRetinaFilter: new _progressiveGain_Tbuffer"<<NBrows<<", "<<NBcolumns<<std::endl;
105 #endif
106         _progressiveGain.resize(_filterOutput.size());
107     }
108 #ifdef T_BASIC_RETINA_ELEMENT_DEBUG
109     std::cout<<"BasicRetinaFilter::BasicRetinaFilter: new filter, size="<<NBrows<<", "<<NBcolumns<<std::endl;
110 #endif
111 
112     // set default values
113     _maxInputValue=256.0;
114 
115     // reset all buffers
116     clearAllBuffers();
117 
118 #ifdef T_BASIC_RETINA_ELEMENT_DEBUG
119     std::cout<<"BasicRetinaFilter::Init BasicRetinaElement at specified frame size OK, size="<<this->size()<<std::endl;
120 #endif
121 
122 }
123 
~BasicRetinaFilter()124 BasicRetinaFilter::~BasicRetinaFilter()
125 {
126 
127 #ifdef BASIC_RETINA_ELEMENT_DEBUG
128     std::cout<<"BasicRetinaFilter::BasicRetinaElement Deleted OK"<<std::endl;
129 #endif
130 
131 }
132 
133 ////////////////////////////////////
134 // functions of the basic filter
135 ////////////////////////////////////
136 
137 
138 // resize all allocated buffers
resize(const unsigned int NBrows,const unsigned int NBcolumns)139 void BasicRetinaFilter::resize(const unsigned int NBrows, const unsigned int NBcolumns)
140 {
141 
142     std::cout<<"BasicRetinaFilter::resize( "<<NBrows<<", "<<NBcolumns<<")"<<std::endl;
143 
144     // resizing buffers
145     _filterOutput.resizeBuffer(NBrows, NBcolumns);
146 
147     // updating variables
148     _halfNBrows=_filterOutput.getNBrows()/2;
149     _halfNBcolumns=_filterOutput.getNBcolumns()/2;
150 
151     _localBuffer.resize(_filterOutput.size());
152     // in case of spatial adapted filter
153     if (_progressiveSpatialConstant.size()>0)
154     {
155         _progressiveSpatialConstant.resize(_filterOutput.size());
156         _progressiveGain.resize(_filterOutput.size());
157     }
158     // reset buffers
159     clearAllBuffers();
160 }
161 
162 // Change coefficients table
setLPfilterParameters(const float beta,const float tau,const float desired_k,const unsigned int filterIndex)163 void BasicRetinaFilter::setLPfilterParameters(const float beta, const float tau, const float desired_k, const unsigned int filterIndex)
164 {
165     float _beta = beta+tau;
166     float k=desired_k;
167     // check if the spatial constant is correct (avoid 0 value to avoid division by 0)
168     if (desired_k<=0)
169     {
170         k=0.001f;
171         std::cerr<<"BasicRetinaFilter::spatial constant of the low pass filter must be superior to zero !!! correcting parameter setting to 0,001"<<std::endl;
172     }
173 
174     float _alpha = k*k;
175     float _mu = 0.8f;
176     unsigned int tableOffset=filterIndex*3;
177     if (k<=0)
178     {
179         std::cerr<<"BasicRetinaFilter::spatial filtering coefficient must be superior to zero, correcting value to 0.01"<<std::endl;
180         _alpha=0.0001f;
181     }
182 
183     float _temp =  (1.0f+_beta)/(2.0f*_mu*_alpha);
184     float a = _filteringCoeficientsTable[tableOffset] = 1.0f + _temp - (float)std::sqrt( (1.0f+_temp)*(1.0f+_temp) - 1.0f);
185     _filteringCoeficientsTable[1+tableOffset]=(1.0f-a)*(1.0f-a)*(1.0f-a)*(1.0f-a)/(1.0f+_beta);
186     _filteringCoeficientsTable[2+tableOffset] =tau;
187 
188     //std::cout<<"BasicRetinaFilter::normal:"<<(1.0-a)*(1.0-a)*(1.0-a)*(1.0-a)/(1.0+_beta)<<" -> old:"<<(1-a)*(1-a)*(1-a)*(1-a)/(1+_beta)<<std::endl;
189 
190     //std::cout<<"BasicRetinaFilter::a="<<a<<", gain="<<_filteringCoeficientsTable[1+tableOffset]<<", tau="<<tau<<std::endl;
191 }
192 
setProgressiveFilterConstants_CentredAccuracy(const float beta,const float tau,const float alpha0,const unsigned int filterIndex)193 void BasicRetinaFilter::setProgressiveFilterConstants_CentredAccuracy(const float beta, const float tau, const float alpha0, const unsigned int filterIndex)
194 {
195     // check if dedicated buffers are already allocated, if not create them
196     if (_progressiveSpatialConstant.size()!=_filterOutput.size())
197     {
198         _progressiveSpatialConstant.resize(_filterOutput.size());
199         _progressiveGain.resize(_filterOutput.size());
200     }
201 
202     float _beta = beta+tau;
203     float _mu=0.8f;
204     if (alpha0<=0)
205     {
206         std::cerr<<"BasicRetinaFilter::spatial filtering coefficient must be superior to zero, correcting value to 0.01"<<std::endl;
207         //alpha0=0.0001;
208     }
209 
210     unsigned int tableOffset=filterIndex*3;
211 
212     float _alpha=0.8f;
213     float _temp =  (1.0f+_beta)/(2.0f*_mu*_alpha);
214     float a=_filteringCoeficientsTable[tableOffset] = 1.0f + _temp - (float)std::sqrt( (1.0f+_temp)*(1.0f+_temp) - 1.0f);
215     _filteringCoeficientsTable[tableOffset+1]=(1.0f-a)*(1.0f-a)*(1.0f-a)*(1.0f-a)/(1.0f+_beta);
216     _filteringCoeficientsTable[tableOffset+2] =tau;
217 
218     float commonFactor=alpha0/(float)std::sqrt(_halfNBcolumns*_halfNBcolumns+_halfNBrows*_halfNBrows+1.0f);
219     //memset(_progressiveSpatialConstant, 255, _filterOutput.getNBpixels());
220     for (unsigned int idColumn=0;idColumn<_halfNBcolumns; ++idColumn)
221         for (unsigned int idRow=0;idRow<_halfNBrows; ++idRow)
222         {
223             // computing local spatial constant
224             float localSpatialConstantValue=commonFactor*std::sqrt((float)(idColumn*idColumn)+(float)(idRow*idRow));
225             if (localSpatialConstantValue>1.0f)
226                 localSpatialConstantValue=1.0f;
227 
228             _progressiveSpatialConstant[_halfNBcolumns-1+idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1+idRow)]=localSpatialConstantValue;
229             _progressiveSpatialConstant[_halfNBcolumns-1-idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1+idRow)]=localSpatialConstantValue;
230             _progressiveSpatialConstant[_halfNBcolumns-1+idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1-idRow)]=localSpatialConstantValue;
231             _progressiveSpatialConstant[_halfNBcolumns-1-idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1-idRow)]=localSpatialConstantValue;
232 
233             // computing local gain
234             float localGain=(1-localSpatialConstantValue)*(1-localSpatialConstantValue)*(1-localSpatialConstantValue)*(1-localSpatialConstantValue)/(1+_beta);
235             _progressiveGain[_halfNBcolumns-1+idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1+idRow)]=localGain;
236             _progressiveGain[_halfNBcolumns-1-idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1+idRow)]=localGain;
237             _progressiveGain[_halfNBcolumns-1+idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1-idRow)]=localGain;
238             _progressiveGain[_halfNBcolumns-1-idColumn+_filterOutput.getNBcolumns()*(_halfNBrows-1-idRow)]=localGain;
239 
240             //std::cout<<commonFactor<<", "<<std::sqrt((_halfNBcolumns-1-idColumn)+(_halfNBrows-idRow-1))<<", "<<(_halfNBcolumns-1-idColumn)<<", "<<(_halfNBrows-idRow-1)<<", "<<localSpatialConstantValue<<std::endl;
241         }
242 }
243 
setProgressiveFilterConstants_CustomAccuracy(const float beta,const float tau,const float k,const std::valarray<float> & accuracyMap,const unsigned int filterIndex)244 void BasicRetinaFilter::setProgressiveFilterConstants_CustomAccuracy(const float beta, const float tau, const float k, const std::valarray<float> &accuracyMap, const unsigned int filterIndex)
245 {
246 
247     if (accuracyMap.size()!=_filterOutput.size())
248     {
249         std::cerr<<"BasicRetinaFilter::setProgressiveFilterConstants_CustomAccuracy: error: input accuracy map does not match filter size, init skept"<<std::endl;
250         return ;
251     }
252 
253     // check if dedicated buffers are already allocated, if not create them
254     if (_progressiveSpatialConstant.size()!=_filterOutput.size())
255     {
256         _progressiveSpatialConstant.resize(accuracyMap.size());
257         _progressiveGain.resize(accuracyMap.size());
258     }
259 
260     float _beta = beta+tau;
261     float _alpha=k*k;
262     float _mu=0.8f;
263     if (k<=0)
264     {
265         std::cerr<<"BasicRetinaFilter::spatial filtering coefficient must be superior to zero, correcting value to 0.01"<<std::endl;
266         //alpha0=0.0001;
267     }
268     unsigned int tableOffset=filterIndex*3;
269     float _temp =  (1.0f+_beta)/(2.0f*_mu*_alpha);
270     float a=_filteringCoeficientsTable[tableOffset] = 1.0f + _temp - (float)std::sqrt( (1.0f+_temp)*(1.0f+_temp) - 1.0f);
271     _filteringCoeficientsTable[tableOffset+1]=(1.0f-a)*(1.0f-a)*(1.0f-a)*(1.0f-a)/(1.0f+_beta);
272     _filteringCoeficientsTable[tableOffset+2] =tau;
273 
274     //memset(_progressiveSpatialConstant, 255, _filterOutput.getNBpixels());
275     for (unsigned int idColumn=0;idColumn<_filterOutput.getNBcolumns(); ++idColumn)
276         for (unsigned int idRow=0;idRow<_filterOutput.getNBrows(); ++idRow)
277         {
278             // computing local spatial constant
279             unsigned int index=idColumn+idRow*_filterOutput.getNBcolumns();
280             float localSpatialConstantValue=_a*accuracyMap[index];
281             if (localSpatialConstantValue>1)
282                 localSpatialConstantValue=1;
283 
284             _progressiveSpatialConstant[index]=localSpatialConstantValue;
285 
286             // computing local gain
287             float localGain=(1.0f-localSpatialConstantValue)*(1.0f-localSpatialConstantValue)*(1.0f-localSpatialConstantValue)*(1.0f-localSpatialConstantValue)/(1.0f+_beta);
288             _progressiveGain[index]=localGain;
289 
290             //std::cout<<commonFactor<<", "<<std::sqrt((_halfNBcolumns-1-idColumn)+(_halfNBrows-idRow-1))<<", "<<(_halfNBcolumns-1-idColumn)<<", "<<(_halfNBrows-idRow-1)<<", "<<localSpatialConstantValue<<std::endl;
291         }
292 }
293 
294 ///////////////////////////////////////////////////////////////////////
295 /// Local luminance adaptation functions
296 // run local adaptation filter and save result in _filterOutput
runFilter_LocalAdapdation(const std::valarray<float> & inputFrame,const std::valarray<float> & localLuminance)297 const std::valarray<float> &BasicRetinaFilter::runFilter_LocalAdapdation(const std::valarray<float> &inputFrame, const std::valarray<float> &localLuminance)
298 {
299     _localLuminanceAdaptation(get_data(inputFrame), get_data(localLuminance), &_filterOutput[0]);
300     return _filterOutput;
301 }
302 // run local adaptation filter at a specific output adress
runFilter_LocalAdapdation(const std::valarray<float> & inputFrame,const std::valarray<float> & localLuminance,std::valarray<float> & outputFrame)303 void BasicRetinaFilter::runFilter_LocalAdapdation(const std::valarray<float> &inputFrame, const std::valarray<float> &localLuminance, std::valarray<float> &outputFrame)
304 {
305     _localLuminanceAdaptation(get_data(inputFrame), get_data(localLuminance), &outputFrame[0]);
306 }
307 // run local adaptation filter and save result in _filterOutput with autonomous low pass filtering before adaptation
runFilter_LocalAdapdation_autonomous(const std::valarray<float> & inputFrame)308 const std::valarray<float> &BasicRetinaFilter::runFilter_LocalAdapdation_autonomous(const std::valarray<float> &inputFrame)
309 {
310     _spatiotemporalLPfilter(get_data(inputFrame), &_filterOutput[0]);
311     _localLuminanceAdaptation(get_data(inputFrame), &_filterOutput[0], &_filterOutput[0]);
312     return _filterOutput;
313 }
314 // run local adaptation filter at a specific output adress with autonomous low pass filtering before adaptation
runFilter_LocalAdapdation_autonomous(const std::valarray<float> & inputFrame,std::valarray<float> & outputFrame)315 void BasicRetinaFilter::runFilter_LocalAdapdation_autonomous(const std::valarray<float> &inputFrame, std::valarray<float> &outputFrame)
316 {
317     _spatiotemporalLPfilter(get_data(inputFrame), &_filterOutput[0]);
318     _localLuminanceAdaptation(get_data(inputFrame), &_filterOutput[0], &outputFrame[0]);
319 }
320 
321 // local luminance adaptation of the input in regard of localLuminance buffer, the input is rewrited and becomes the output
_localLuminanceAdaptation(float * inputOutputFrame,const float * localLuminance)322 void BasicRetinaFilter::_localLuminanceAdaptation(float *inputOutputFrame, const float *localLuminance)
323 {
324     _localLuminanceAdaptation(inputOutputFrame, localLuminance, inputOutputFrame, false);
325 
326     /*    const float *localLuminancePTR=localLuminance;
327     float *inputOutputFramePTR=inputOutputFrame;
328 
329     for (unsigned int IDpixel=0 ; IDpixel<_filterOutput.getNBpixels() ; ++IDpixel, ++inputOutputFramePTR)
330     {
331         float X0=*(localLuminancePTR++)*_localLuminanceFactor+_localLuminanceAddon;
332         *(inputOutputFramePTR) = (_maxInputValue+X0)**inputOutputFramePTR/(*inputOutputFramePTR +X0+0.00000000001);
333     }
334       */
335 }
336 
337 // local luminance adaptation of the input in regard of localLuminance buffer
_localLuminanceAdaptation(const float * inputFrame,const float * localLuminance,float * outputFrame,const bool updateLuminanceMean)338 void BasicRetinaFilter::_localLuminanceAdaptation(const float *inputFrame, const float *localLuminance, float *outputFrame, const bool updateLuminanceMean)
339 {
340     if (updateLuminanceMean)
341     {	float meanLuminance=0;
342         const float *luminancePTR=inputFrame;
343         for (unsigned int i=0;i<_filterOutput.getNBpixels();++i)
344             meanLuminance+=*(luminancePTR++);
345         meanLuminance/=_filterOutput.getNBpixels();
346         //float tempMeanValue=meanLuminance+_meanInputValue*_tau;
347         updateCompressionParameter(meanLuminance);
348     }
349 #ifdef MAKE_PARALLEL
350         cv::parallel_for_(cv::Range(0,_filterOutput.getNBpixels()), Parallel_localAdaptation(localLuminance, inputFrame, outputFrame, _localLuminanceFactor, _localLuminanceAddon, _maxInputValue));
351 #else
352     //std::cout<<meanLuminance<<std::endl;
353     const float *localLuminancePTR=localLuminance;
354     const float *inputFramePTR=inputFrame;
355     float *outputFramePTR=outputFrame;
356     for (unsigned int IDpixel=0 ; IDpixel<_filterOutput.getNBpixels() ; ++IDpixel, ++inputFramePTR, ++outputFramePTR)
357     {
358         float X0=*(localLuminancePTR++)*_localLuminanceFactor+_localLuminanceAddon;
359         // TODO : the following line can lead to a divide by zero ! A small offset is added, take care if the offset is too large in case of High Dynamic Range images which can use very small values...
360         *(outputFramePTR) = (_maxInputValue+X0)**inputFramePTR/(*inputFramePTR +X0+0.00000000001);
361         //std::cout<<"BasicRetinaFilter::inputFrame[IDpixel]=%f, X0=%f, outputFrame[IDpixel]=%f\n", inputFrame[IDpixel], X0, outputFrame[IDpixel]);
362     }
363 #endif
364 }
365 
366 // local adaptation applied on a range of values which can be positive and negative
_localLuminanceAdaptationPosNegValues(const float * inputFrame,const float * localLuminance,float * outputFrame)367 void BasicRetinaFilter::_localLuminanceAdaptationPosNegValues(const float *inputFrame, const float *localLuminance, float *outputFrame)
368 {
369     const float *localLuminancePTR=localLuminance;
370     const float *inputFramePTR=inputFrame;
371     float *outputFramePTR=outputFrame;
372     float factor=_maxInputValue*2.0f/(float)CV_PI;
373     for (unsigned int IDpixel=0 ; IDpixel<_filterOutput.getNBpixels() ; ++IDpixel, ++inputFramePTR)
374     {
375         float X0=*(localLuminancePTR++)*_localLuminanceFactor+_localLuminanceAddon;
376         *(outputFramePTR++) = factor*atan(*inputFramePTR/X0);//(_maxInputValue+X0)**inputFramePTR/(*inputFramePTR +X0);
377         //std::cout<<"BasicRetinaFilter::inputFrame[IDpixel]=%f, X0=%f, outputFrame[IDpixel]=%f\n", inputFrame[IDpixel], X0, outputFrame[IDpixel]);
378     }
379 }
380 
381 ///////////////////////////////////////////////////////////////////////
382 /// Spatio temporal Low Pass filter functions
383 // run LP filter and save result in the basic retina element buffer
runFilter_LPfilter(const std::valarray<float> & inputFrame,const unsigned int filterIndex)384 const std::valarray<float> &BasicRetinaFilter::runFilter_LPfilter(const std::valarray<float> &inputFrame, const unsigned int filterIndex)
385 {
386     _spatiotemporalLPfilter(get_data(inputFrame), &_filterOutput[0], filterIndex);
387     return _filterOutput;
388 }
389 
390 // run LP filter for a new frame input and save result at a specific output adress
runFilter_LPfilter(const std::valarray<float> & inputFrame,std::valarray<float> & outputFrame,const unsigned int filterIndex)391 void BasicRetinaFilter::runFilter_LPfilter(const std::valarray<float> &inputFrame, std::valarray<float> &outputFrame, const unsigned int filterIndex)
392 {
393     _spatiotemporalLPfilter(get_data(inputFrame), &outputFrame[0], filterIndex);
394 }
395 
396 // run LP filter on the input data and rewrite it
runFilter_LPfilter_Autonomous(std::valarray<float> & inputOutputFrame,const unsigned int filterIndex)397 void BasicRetinaFilter::runFilter_LPfilter_Autonomous(std::valarray<float> &inputOutputFrame, const unsigned int filterIndex)
398 {
399     unsigned int coefTableOffset=filterIndex*3;
400 
401     /**********/
402     _a=_filteringCoeficientsTable[coefTableOffset];
403     _gain=_filteringCoeficientsTable[1+coefTableOffset];
404     _tau=_filteringCoeficientsTable[2+coefTableOffset];
405 
406     // launch the serie of 1D directional filters in order to compute the 2D low pass filter
407     _horizontalCausalFilter(&inputOutputFrame[0], 0, _filterOutput.getNBrows());
408     _horizontalAnticausalFilter(&inputOutputFrame[0], 0, _filterOutput.getNBrows());
409     _verticalCausalFilter(&inputOutputFrame[0], 0, _filterOutput.getNBcolumns());
410     _verticalAnticausalFilter_multGain(&inputOutputFrame[0], 0, _filterOutput.getNBcolumns());
411 
412 }
413 // run LP filter for a new frame input and save result at a specific output adress
_spatiotemporalLPfilter(const float * inputFrame,float * outputFrame,const unsigned int filterIndex)414 void BasicRetinaFilter::_spatiotemporalLPfilter(const float *inputFrame, float *outputFrame, const unsigned int filterIndex)
415 {
416     unsigned int coefTableOffset=filterIndex*3;
417     /**********/
418     _a=_filteringCoeficientsTable[coefTableOffset];
419     _gain=_filteringCoeficientsTable[1+coefTableOffset];
420     _tau=_filteringCoeficientsTable[2+coefTableOffset];
421 
422     // launch the serie of 1D directional filters in order to compute the 2D low pass filter
423     _horizontalCausalFilter_addInput(inputFrame, outputFrame, 0,_filterOutput.getNBrows());
424     _horizontalAnticausalFilter(outputFrame, 0, _filterOutput.getNBrows());
425     _verticalCausalFilter(outputFrame, 0, _filterOutput.getNBcolumns());
426     _verticalAnticausalFilter_multGain(outputFrame, 0, _filterOutput.getNBcolumns());
427 
428 }
429 
430 // run SQUARING LP filter for a new frame input and save result at a specific output adress
_squaringSpatiotemporalLPfilter(const float * inputFrame,float * outputFrame,const unsigned int filterIndex)431 float BasicRetinaFilter::_squaringSpatiotemporalLPfilter(const float *inputFrame, float *outputFrame, const unsigned int filterIndex)
432 {
433     unsigned int coefTableOffset=filterIndex*3;
434     /**********/
435     _a=_filteringCoeficientsTable[coefTableOffset];
436     _gain=_filteringCoeficientsTable[1+coefTableOffset];
437     _tau=_filteringCoeficientsTable[2+coefTableOffset];
438 
439     // launch the serie of 1D directional filters in order to compute the 2D low pass filter
440 
441     _squaringHorizontalCausalFilter(inputFrame, outputFrame, 0, _filterOutput.getNBrows());
442     _horizontalAnticausalFilter(outputFrame, 0, _filterOutput.getNBrows());
443     _verticalCausalFilter(outputFrame, 0, _filterOutput.getNBcolumns());
444     return _verticalAnticausalFilter_returnMeanValue(outputFrame, 0, _filterOutput.getNBcolumns());
445 }
446 
447 /////////////////////////////////////////////////
448 // standard version of the 1D low pass filters
449 
450 //  horizontal causal filter which adds the input inside
_horizontalCausalFilter(float * outputFrame,unsigned int IDrowStart,unsigned int IDrowEnd)451 void BasicRetinaFilter::_horizontalCausalFilter(float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd)
452 {
453 
454 
455     //#pragma omp parallel for
456     for (unsigned int IDrow=IDrowStart; IDrow<IDrowEnd; ++IDrow)
457     {
458         float* outputPTR=outputFrame+(IDrowStart+IDrow)*_filterOutput.getNBcolumns();
459         float result=0;
460         for (unsigned int index=0; index<_filterOutput.getNBcolumns(); ++index)
461         {
462             result = *(outputPTR)+  _a* result;
463             *(outputPTR++) = result;
464         }
465     }
466 }
467 //  horizontal causal filter which adds the input inside
_horizontalCausalFilter_addInput(const float * inputFrame,float * outputFrame,unsigned int IDrowStart,unsigned int IDrowEnd)468 void BasicRetinaFilter::_horizontalCausalFilter_addInput(const float *inputFrame, float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd)
469 {
470 #ifdef MAKE_PARALLEL
471         cv::parallel_for_(cv::Range(IDrowStart,IDrowEnd), Parallel_horizontalCausalFilter_addInput(inputFrame, outputFrame, IDrowStart, _filterOutput.getNBcolumns(), _a, _tau));
472 #else
473     for (unsigned int IDrow=IDrowStart; IDrow<IDrowEnd; ++IDrow)
474     {
475         float* outputPTR=outputFrame+(IDrowStart+IDrow)*_filterOutput.getNBcolumns();
476         const float* inputPTR=inputFrame+(IDrowStart+IDrow)*_filterOutput.getNBcolumns();
477         float result=0;
478         for (unsigned int index=0; index<_filterOutput.getNBcolumns(); ++index)
479         {
480             result = *(inputPTR++) + _tau**(outputPTR)+  _a* result;
481             *(outputPTR++) = result;
482         }
483     }
484 #endif
485 }
486 
487 //  horizontal anticausal filter  (basic way, no add on)
_horizontalAnticausalFilter(float * outputFrame,unsigned int IDrowStart,unsigned int IDrowEnd)488 void BasicRetinaFilter::_horizontalAnticausalFilter(float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd)
489 {
490 
491 #ifdef MAKE_PARALLEL
492         cv::parallel_for_(cv::Range(IDrowStart,IDrowEnd), Parallel_horizontalAnticausalFilter(outputFrame, IDrowEnd, _filterOutput.getNBcolumns(), _a ));
493 #else
494     for (unsigned int IDrow=IDrowStart; IDrow<IDrowEnd; ++IDrow)
495     {
496         float* outputPTR=outputFrame+(IDrowEnd-IDrow)*(_filterOutput.getNBcolumns())-1;
497         float result=0;
498         for (unsigned int index=0; index<_filterOutput.getNBcolumns(); ++index)
499         {
500             result = *(outputPTR)+  _a* result;
501             *(outputPTR--) = result;
502         }
503     }
504 #endif
505 }
506 
507 //  horizontal anticausal filter which multiplies the output by _gain
_horizontalAnticausalFilter_multGain(float * outputFrame,unsigned int IDrowStart,unsigned int IDrowEnd)508 void BasicRetinaFilter::_horizontalAnticausalFilter_multGain(float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd)
509 {
510 
511     //#pragma omp parallel for
512     for (unsigned int IDrow=IDrowStart; IDrow<IDrowEnd; ++IDrow)
513     {
514         float* outputPTR=outputFrame+(IDrowEnd-IDrow)*(_filterOutput.getNBcolumns())-1;
515         float result=0;
516         for (unsigned int index=0; index<_filterOutput.getNBcolumns(); ++index)
517         {
518             result = *(outputPTR)+  _a* result;
519             *(outputPTR--) = _gain*result;
520         }
521     }
522 }
523 
524 //  vertical anticausal filter
_verticalCausalFilter(float * outputFrame,unsigned int IDcolumnStart,unsigned int IDcolumnEnd)525 void BasicRetinaFilter::_verticalCausalFilter(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd)
526 {
527 #ifdef MAKE_PARALLEL
528         cv::parallel_for_(cv::Range(IDcolumnStart,IDcolumnEnd), Parallel_verticalCausalFilter(outputFrame, _filterOutput.getNBrows(), _filterOutput.getNBcolumns(), _a ));
529 #else
530         for (unsigned int IDcolumn=IDcolumnStart; IDcolumn<IDcolumnEnd; ++IDcolumn)
531     {
532         float result=0;
533         float *outputPTR=outputFrame+IDcolumn;
534 
535         for (unsigned int index=0; index<_filterOutput.getNBrows(); ++index)
536         {
537             result = *(outputPTR) + _a * result;
538             *(outputPTR) = result;
539             outputPTR+=_filterOutput.getNBcolumns();
540 
541         }
542     }
543 #endif
544 }
545 
546 
547 //  vertical anticausal filter (basic way, no add on)
_verticalAnticausalFilter(float * outputFrame,unsigned int IDcolumnStart,unsigned int IDcolumnEnd)548 void BasicRetinaFilter::_verticalAnticausalFilter(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd)
549 {
550     float* offset=outputFrame+_filterOutput.getNBpixels()-_filterOutput.getNBcolumns();
551     //#pragma omp parallel for
552     for (unsigned int IDcolumn=IDcolumnStart; IDcolumn<IDcolumnEnd; ++IDcolumn)
553     {
554         float result=0;
555         float *outputPTR=offset+IDcolumn;
556 
557         for (unsigned int index=0; index<_filterOutput.getNBrows(); ++index)
558         {
559             result = *(outputPTR) + _a * result;
560             *(outputPTR) = result;
561             outputPTR-=_filterOutput.getNBcolumns();
562 
563         }
564     }
565 }
566 
567 //  vertical anticausal filter which multiplies the output by _gain
_verticalAnticausalFilter_multGain(float * outputFrame,unsigned int IDcolumnStart,unsigned int IDcolumnEnd)568 void BasicRetinaFilter::_verticalAnticausalFilter_multGain(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd)
569 {
570 #ifdef MAKE_PARALLEL
571         cv::parallel_for_(cv::Range(IDcolumnStart,IDcolumnEnd), Parallel_verticalAnticausalFilter_multGain(outputFrame, _filterOutput.getNBrows(), _filterOutput.getNBcolumns(), _a, _gain ));
572 #else
573         float* offset=outputFrame+_filterOutput.getNBpixels()-_filterOutput.getNBcolumns();
574     //#pragma omp parallel for
575     for (unsigned int IDcolumn=IDcolumnStart; IDcolumn<IDcolumnEnd; ++IDcolumn)
576     {
577         float result=0;
578         float *outputPTR=offset+IDcolumn;
579 
580         for (unsigned int index=0; index<_filterOutput.getNBrows(); ++index)
581         {
582             result = *(outputPTR) + _a * result;
583             *(outputPTR) = _gain*result;
584             outputPTR-=_filterOutput.getNBcolumns();
585 
586         }
587     }
588 #endif
589 }
590 
591 /////////////////////////////////////////
592 // specific modifications of 1D filters
593 
594 // -> squaring horizontal causal filter
_squaringHorizontalCausalFilter(const float * inputFrame,float * outputFrame,unsigned int IDrowStart,unsigned int IDrowEnd)595 void BasicRetinaFilter::_squaringHorizontalCausalFilter(const float *inputFrame, float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd)
596 {
597     float* outputPTR=outputFrame+IDrowStart*_filterOutput.getNBcolumns();
598     const float* inputPTR=inputFrame+IDrowStart*_filterOutput.getNBcolumns();
599     for (unsigned int IDrow=IDrowStart; IDrow<IDrowEnd; ++IDrow)
600     {
601         float result=0;
602         for (unsigned int index=0; index<_filterOutput.getNBcolumns(); ++index)
603         {
604             result = *(inputPTR)**(inputPTR) + _tau**(outputPTR)+  _a* result;
605             *(outputPTR++) = result;
606             ++inputPTR;
607         }
608     }
609 }
610 
611 //  vertical anticausal filter that returns the mean value of its result
_verticalAnticausalFilter_returnMeanValue(float * outputFrame,unsigned int IDcolumnStart,unsigned int IDcolumnEnd)612 float BasicRetinaFilter::_verticalAnticausalFilter_returnMeanValue(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd)
613 {
614     float meanValue=0;
615     float* offset=outputFrame+_filterOutput.getNBpixels()-_filterOutput.getNBcolumns();
616     for (unsigned int IDcolumn=IDcolumnStart; IDcolumn<IDcolumnEnd; ++IDcolumn)
617     {
618         float result=0;
619         float *outputPTR=offset+IDcolumn;
620 
621         for (unsigned int index=0; index<_filterOutput.getNBrows(); ++index)
622         {
623             result = *(outputPTR) + _a * result;
624             *(outputPTR) = _gain*result;
625             meanValue+=*(outputPTR);
626             outputPTR-=_filterOutput.getNBcolumns();
627 
628         }
629     }
630 
631     return meanValue/(float)_filterOutput.getNBpixels();
632 }
633 
634 // LP filter with integration in specific areas (regarding true values of a binary parameters image)
_localSquaringSpatioTemporalLPfilter(const float * inputFrame,float * LPfilterOutput,const unsigned int * integrationAreas,const unsigned int filterIndex)635 void BasicRetinaFilter::_localSquaringSpatioTemporalLPfilter(const float *inputFrame, float *LPfilterOutput, const unsigned int *integrationAreas, const unsigned int filterIndex)
636 {
637     unsigned int coefTableOffset=filterIndex*3;
638     _a=_filteringCoeficientsTable[coefTableOffset+0];
639     _gain=_filteringCoeficientsTable[coefTableOffset+1];
640     _tau=_filteringCoeficientsTable[coefTableOffset+2];
641     // launch the serie of 1D directional filters in order to compute the 2D low pass filter
642 
643     _local_squaringHorizontalCausalFilter(inputFrame, LPfilterOutput, 0, _filterOutput.getNBrows(), integrationAreas);
644     _local_horizontalAnticausalFilter(LPfilterOutput, 0, _filterOutput.getNBrows(), integrationAreas);
645     _local_verticalCausalFilter(LPfilterOutput, 0, _filterOutput.getNBcolumns(), integrationAreas);
646     _local_verticalAnticausalFilter_multGain(LPfilterOutput, 0, _filterOutput.getNBcolumns(), integrationAreas);
647 
648 }
649 
650 // LP filter on specific parts of the picture instead of all the image
651 // same functions (some of them) but take a binary flag to allow integration, false flag means, no data change at the output...
652 
653 // this function take an image in input and squares it befor computing
_local_squaringHorizontalCausalFilter(const float * inputFrame,float * outputFrame,unsigned int IDrowStart,unsigned int IDrowEnd,const unsigned int * integrationAreas)654 void BasicRetinaFilter::_local_squaringHorizontalCausalFilter(const float *inputFrame, float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd, const unsigned int *integrationAreas)
655 {
656     float* outputPTR=outputFrame+IDrowStart*_filterOutput.getNBcolumns();
657     const float* inputPTR=inputFrame+IDrowStart*_filterOutput.getNBcolumns();
658     const unsigned int *integrationAreasPTR=integrationAreas;
659     for (unsigned int IDrow=IDrowStart; IDrow<IDrowEnd; ++IDrow)
660     {
661         float result=0;
662         for (unsigned int index=0; index<_filterOutput.getNBcolumns(); ++index)
663         {
664             if (*(integrationAreasPTR++))
665                 result = *(inputPTR)**(inputPTR) + _tau**(outputPTR)+  _a* result;
666             else
667                 result=0;
668             *(outputPTR++) = result;
669             ++inputPTR;
670 
671         }
672     }
673 }
674 
_local_horizontalAnticausalFilter(float * outputFrame,unsigned int IDrowStart,unsigned int IDrowEnd,const unsigned int * integrationAreas)675 void BasicRetinaFilter::_local_horizontalAnticausalFilter(float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd, const unsigned int *integrationAreas)
676 {
677 
678     float* outputPTR=outputFrame+IDrowEnd*(_filterOutput.getNBcolumns())-1;
679     const unsigned int *integrationAreasPTR=integrationAreas;
680 
681     for (unsigned int IDrow=IDrowStart; IDrow<IDrowEnd; ++IDrow)
682     {
683         float result=0;
684         for (unsigned int index=0; index<_filterOutput.getNBcolumns(); ++index)
685         {
686             if (*(integrationAreasPTR++))
687                 result = *(outputPTR)+  _a* result;
688             else
689                 result=0;
690             *(outputPTR--) = result;
691         }
692     }
693 
694 }
695 
_local_verticalCausalFilter(float * outputFrame,unsigned int IDcolumnStart,unsigned int IDcolumnEnd,const unsigned int * integrationAreas)696 void BasicRetinaFilter::_local_verticalCausalFilter(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd, const unsigned int *integrationAreas)
697 {
698     const unsigned int *integrationAreasPTR=integrationAreas;
699 
700     for (unsigned int IDcolumn=IDcolumnStart; IDcolumn<IDcolumnEnd; ++IDcolumn)
701     {
702         float result=0;
703         float *outputPTR=outputFrame+IDcolumn;
704 
705         for (unsigned int index=0; index<_filterOutput.getNBrows(); ++index)
706         {
707             if (*(integrationAreasPTR++))
708                 result = *(outputPTR)+  _a* result;
709             else
710                 result=0;
711             *(outputPTR) = result;
712             outputPTR+=_filterOutput.getNBcolumns();
713 
714         }
715     }
716 }
717 // this functions affects _gain at the output
_local_verticalAnticausalFilter_multGain(float * outputFrame,unsigned int IDcolumnStart,unsigned int IDcolumnEnd,const unsigned int * integrationAreas)718 void BasicRetinaFilter::_local_verticalAnticausalFilter_multGain(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd, const unsigned int *integrationAreas)
719 {
720     const unsigned int *integrationAreasPTR=integrationAreas;
721     float* offset=outputFrame+_filterOutput.getNBpixels()-_filterOutput.getNBcolumns();
722 
723     for (unsigned int IDcolumn=IDcolumnStart; IDcolumn<IDcolumnEnd; ++IDcolumn)
724     {
725         float result=0;
726         float *outputPTR=offset+IDcolumn;
727 
728         for (unsigned int index=0; index<_filterOutput.getNBrows(); ++index)
729         {
730             if (*(integrationAreasPTR++))
731                 result = *(outputPTR)+  _a* result;
732             else
733                 result=0;
734             *(outputPTR) = _gain*result;
735             outputPTR-=_filterOutput.getNBcolumns();
736 
737         }
738     }
739 }
740 
741 ////////////////////////////////////////////////////
742 // run LP filter for a new frame input and save result at a specific output adress
743 // -> USE IRREGULAR SPATIAL CONSTANT
744 
745 // irregular filter computed from a buffer and rewrites it
_spatiotemporalLPfilter_Irregular(float * inputOutputFrame,const unsigned int filterIndex)746 void BasicRetinaFilter::_spatiotemporalLPfilter_Irregular(float *inputOutputFrame, const unsigned int filterIndex)
747 {
748     if (_progressiveGain.size()==0)
749     {
750         std::cerr<<"BasicRetinaFilter::runProgressiveFilter: cannot perform filtering, no progressive filter settled up"<<std::endl;
751         return;
752     }
753     unsigned int coefTableOffset=filterIndex*3;
754     /**********/
755     //_a=_filteringCoeficientsTable[coefTableOffset];
756     _tau=_filteringCoeficientsTable[2+coefTableOffset];
757 
758     // launch the serie of 1D directional filters in order to compute the 2D low pass filter
759     _horizontalCausalFilter_Irregular(inputOutputFrame, 0, (int)_filterOutput.getNBrows());
760     _horizontalAnticausalFilter_Irregular(inputOutputFrame, 0, (int)_filterOutput.getNBrows(), &_progressiveSpatialConstant[0]);
761     _verticalCausalFilter_Irregular(inputOutputFrame, 0, (int)_filterOutput.getNBcolumns(), &_progressiveSpatialConstant[0]);
762     _verticalAnticausalFilter_Irregular_multGain(inputOutputFrame, 0, (int)_filterOutput.getNBcolumns());
763 
764 }
765 // irregular filter computed from a buffer and puts result on another
_spatiotemporalLPfilter_Irregular(const float * inputFrame,float * outputFrame,const unsigned int filterIndex)766 void BasicRetinaFilter::_spatiotemporalLPfilter_Irregular(const float *inputFrame, float *outputFrame, const unsigned int filterIndex)
767 {
768     if (_progressiveGain.size()==0)
769     {
770         std::cerr<<"BasicRetinaFilter::runProgressiveFilter: cannot perform filtering, no progressive filter settled up"<<std::endl;
771         return;
772     }
773     unsigned int coefTableOffset=filterIndex*3;
774     /**********/
775     //_a=_filteringCoeficientsTable[coefTableOffset];
776     _tau=_filteringCoeficientsTable[2+coefTableOffset];
777 
778     // launch the serie of 1D directional filters in order to compute the 2D low pass filter
779     _horizontalCausalFilter_Irregular_addInput(inputFrame, outputFrame, 0, (int)_filterOutput.getNBrows());
780     _horizontalAnticausalFilter_Irregular(outputFrame, 0, (int)_filterOutput.getNBrows(), &_progressiveSpatialConstant[0]);
781     _verticalCausalFilter_Irregular(outputFrame, 0, (int)_filterOutput.getNBcolumns(), &_progressiveSpatialConstant[0]);
782     _verticalAnticausalFilter_Irregular_multGain(outputFrame, 0, (int)_filterOutput.getNBcolumns());
783 
784 }
785 // 1D filters with irregular spatial constant
786 //  horizontal causal filter wich runs on its input buffer
_horizontalCausalFilter_Irregular(float * outputFrame,unsigned int IDrowStart,unsigned int IDrowEnd)787 void BasicRetinaFilter::_horizontalCausalFilter_Irregular(float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd)
788 {
789     float* outputPTR=outputFrame+IDrowStart*_filterOutput.getNBcolumns();
790     const float* spatialConstantPTR=&_progressiveSpatialConstant[0]+IDrowStart*_filterOutput.getNBcolumns();
791     for (unsigned int IDrow=IDrowStart; IDrow<IDrowEnd; ++IDrow)
792     {
793         float result=0;
794         for (unsigned int index=0; index<_filterOutput.getNBcolumns(); ++index)
795         {
796             result = *(outputPTR)+  *(spatialConstantPTR++)* result;
797             *(outputPTR++) = result;
798         }
799     }
800 }
801 
802 // horizontal causal filter with add input
_horizontalCausalFilter_Irregular_addInput(const float * inputFrame,float * outputFrame,unsigned int IDrowStart,unsigned int IDrowEnd)803 void BasicRetinaFilter::_horizontalCausalFilter_Irregular_addInput(const float *inputFrame, float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd)
804 {
805     float* outputPTR=outputFrame+IDrowStart*_filterOutput.getNBcolumns();
806     const float* inputPTR=inputFrame+IDrowStart*_filterOutput.getNBcolumns();
807     const float* spatialConstantPTR=&_progressiveSpatialConstant[0]+IDrowStart*_filterOutput.getNBcolumns();
808     for (unsigned int IDrow=IDrowStart; IDrow<IDrowEnd; ++IDrow)
809     {
810         float result=0;
811         for (unsigned int index=0; index<_filterOutput.getNBcolumns(); ++index)
812         {
813             result = *(inputPTR++) + _tau**(outputPTR)+  *(spatialConstantPTR++)* result;
814             *(outputPTR++) = result;
815         }
816     }
817 
818 }
819 
820 //  horizontal anticausal filter  (basic way, no add on)
_horizontalAnticausalFilter_Irregular(float * outputFrame,unsigned int IDrowStart,unsigned int IDrowEnd,const float * spatialConstantBuffer)821 void BasicRetinaFilter::_horizontalAnticausalFilter_Irregular(float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd, const float *spatialConstantBuffer)
822 {
823 #ifdef MAKE_PARALLEL
824         cv::parallel_for_(cv::Range(IDrowStart,IDrowEnd), Parallel_horizontalAnticausalFilter_Irregular(outputFrame, spatialConstantBuffer, IDrowEnd, _filterOutput.getNBcolumns()));
825 #else
826     float* outputPTR=outputFrame+IDrowEnd*(_filterOutput.getNBcolumns())-1;
827     const float* spatialConstantPTR=spatialConstantBuffer+IDrowEnd*(_filterOutput.getNBcolumns())-1;
828 
829     for (unsigned int IDrow=IDrowStart; IDrow<IDrowEnd; ++IDrow)
830     {
831         float result=0;
832         for (unsigned int index=0; index<_filterOutput.getNBcolumns(); ++index)
833         {
834             result = *(outputPTR)+  *(spatialConstantPTR--)* result;
835             *(outputPTR--) = result;
836         }
837     }
838 #endif
839 
840 }
841 
842 //  vertical anticausal filter
_verticalCausalFilter_Irregular(float * outputFrame,unsigned int IDcolumnStart,unsigned int IDcolumnEnd,const float * spatialConstantBuffer)843 void BasicRetinaFilter::_verticalCausalFilter_Irregular(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd, const float *spatialConstantBuffer)
844 {
845 #ifdef MAKE_PARALLEL
846         cv::parallel_for_(cv::Range(IDcolumnStart,IDcolumnEnd), Parallel_verticalCausalFilter_Irregular(outputFrame, spatialConstantBuffer, _filterOutput.getNBrows(), _filterOutput.getNBcolumns()));
847 #else
848     for (unsigned int IDcolumn=IDcolumnStart; IDcolumn<IDcolumnEnd; ++IDcolumn)
849     {
850         float result=0;
851         float *outputPTR=outputFrame+IDcolumn;
852         const float *spatialConstantPTR=spatialConstantBuffer+IDcolumn;
853         for (unsigned int index=0; index<_filterOutput.getNBrows(); ++index)
854         {
855             result = *(outputPTR) + *(spatialConstantPTR) * result;
856             *(outputPTR) = result;
857             outputPTR+=_filterOutput.getNBcolumns();
858             spatialConstantPTR+=_filterOutput.getNBcolumns();
859         }
860     }
861 #endif
862 }
863 
864 //  vertical anticausal filter which multiplies the output by _gain
_verticalAnticausalFilter_Irregular_multGain(float * outputFrame,unsigned int IDcolumnStart,unsigned int IDcolumnEnd)865 void BasicRetinaFilter::_verticalAnticausalFilter_Irregular_multGain(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd)
866 {
867     float* outputOffset=outputFrame+_filterOutput.getNBpixels()-_filterOutput.getNBcolumns();
868     const float* constantOffset=&_progressiveSpatialConstant[0]+_filterOutput.getNBpixels()-_filterOutput.getNBcolumns();
869     const float* gainOffset=&_progressiveGain[0]+_filterOutput.getNBpixels()-_filterOutput.getNBcolumns();
870     for (unsigned int IDcolumn=IDcolumnStart; IDcolumn<IDcolumnEnd; ++IDcolumn)
871     {
872         float result=0;
873         float *outputPTR=outputOffset+IDcolumn;
874         const float *spatialConstantPTR=constantOffset+IDcolumn;
875         const float *progressiveGainPTR=gainOffset+IDcolumn;
876         for (unsigned int index=0; index<_filterOutput.getNBrows(); ++index)
877         {
878             result = *(outputPTR) + *(spatialConstantPTR) * result;
879             *(outputPTR) = *(progressiveGainPTR)*result;
880             outputPTR-=_filterOutput.getNBcolumns();
881             spatialConstantPTR-=_filterOutput.getNBcolumns();
882             progressiveGainPTR-=_filterOutput.getNBcolumns();
883         }
884     }
885 
886 }
887 }// end of namespace bioinspired
888 }// end of namespace cv
889