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 #ifndef BASICRETINAELEMENT_HPP_
66 #define BASICRETINAELEMENT_HPP_
67 
68 #include <cstring>
69 
70 
71 /**
72 * @class BasicRetinaFilter
73 * @brief Brief overview, this class provides tools for low level image processing:
74 * --> this class is able to perform:
75 * -> first order Low pass optimized filtering
76 * -> local luminance adaptation (able to correct back light problems and contrast enhancement)
77 * -> progressive low pass filter filtering (higher filtering on the borders than on the center)
78 * -> image data between 0 and 255 resampling with different options, linear rescaling, sigmoide)
79 *
80 * NOTE : initially the retina model was based on double format scalar values but
81 * a good memory/precision compromise is float...
82 * also the double format precision does not make so much sense from a biological point of view (neurons value coding is not so precise)
83 *
84 * TYPICAL USE:
85 *
86 * // create object at a specified picture size
87 * BasicRetinaFilter *_photoreceptorsPrefilter;
88 * _photoreceptorsPrefilter =new BasicRetinaFilter(sizeRows, sizeWindows);
89 *
90 * // init gain, spatial and temporal parameters:
91 * _photoreceptorsPrefilter->setCoefficientsTable(gain,temporalConstant, spatialConstant);
92 *
93 * // during program execution, call the filter for local luminance correction or low pass filtering for an input picture called "FrameBuffer":
94 * _photoreceptorsPrefilter->runFilter_LocalAdapdation(FrameBuffer);
95 * // or (Low pass first order filter)
96 * _photoreceptorsPrefilter->runFilter_LPfilter(FrameBuffer);
97 * // get output frame and its size:
98 * const unsigned int output_nbRows=_photoreceptorsPrefilter->getNBrows();
99 * const unsigned int output_nbColumns=_photoreceptorsPrefilter->getNBcolumns();
100 * const double *outputFrame=_photoreceptorsPrefilter->getOutput();
101 *
102 * // at the end of the program, destroy object:
103 * delete _photoreceptorsPrefilter;
104 
105 * @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr, Gipsa-Lab, France: www.gipsa-lab.inpg.fr/
106 * Creation date 2007
107 * synthesis of the work described in Alexandre BENOIT thesis: "Le systeme visuel humain au secours de la vision par ordinateur"
108 */
109 
110 #include <iostream>
111 #include "templatebuffer.hpp"
112 
113 //#define __BASIC_RETINA_ELEMENT_DEBUG
114 
115 namespace cv
116 {
117 namespace bioinspired
118 {
119     class BasicRetinaFilter
120     {
121     public:
122 
123         /**
124         * constructor of the base bio-inspired toolbox, parameters are only linked to imae input size and number of filtering capabilities of the object
125         * @param NBrows: number of rows of the input image
126         * @param NBcolumns: number of columns of the input image
127         * @param parametersListSize: specifies the number of parameters set (each parameters set represents a specific low pass spatio-temporal filter)
128         * @param useProgressiveFilter: specifies if the filter has irreguar (progressive) filtering capabilities (this can be activated later using setProgressiveFilterConstants_xxx methods)
129         */
130         BasicRetinaFilter(const unsigned int NBrows, const unsigned int NBcolumns, const unsigned int parametersListSize=1, const bool useProgressiveFilter=false);
131 
132         /**
133         * standrad destructore
134         */
135         ~BasicRetinaFilter();
136 
137         /**
138         * function which clears the output buffer of the object
139         */
clearOutputBuffer()140         inline void clearOutputBuffer() { _filterOutput = 0; }
141 
142         /**
143         * function which clears the secondary buffer of the object
144         */
clearSecondaryBuffer()145         inline void clearSecondaryBuffer() { _localBuffer = 0; }
146 
147         /**
148         * function which clears the output and the secondary buffer of the object
149         */
clearAllBuffers()150         inline void clearAllBuffers() { clearOutputBuffer(); clearSecondaryBuffer(); }
151 
152         /**
153         * resize basic retina filter object (resize all allocated buffers
154         * @param NBrows: the new height size
155         * @param NBcolumns: the new width size
156         */
157         void resize(const unsigned int NBrows, const unsigned int NBcolumns);
158 
159         /**
160         * forbiden method inherited from parent std::valarray
161         * prefer not to use this method since the filter matrix become vectors
162         */
resize(const unsigned int)163         void resize(const unsigned int) { std::cerr<<"error, not accessible method"<<std::endl; }
164 
165         /**
166         *  low pass filter call and run (models the homogeneous cells network at the retina level, for example horizontal cells or photoreceptors)
167         * @param inputFrame: the input image to be processed
168         * @param filterIndex: the offset which specifies the parameter set that should be used for the filtering
169         * @return the processed image, the output is reachable later by using function getOutput()
170         */
171         const std::valarray<float> &runFilter_LPfilter(const std::valarray<float> &inputFrame, const unsigned int filterIndex=0); // run the LP filter for a new frame input and save result in _filterOutput
172 
173         /**
174         * low pass filter call and run (models the homogeneous cells network at the retina level, for example horizontal cells or photoreceptors)
175         * @param inputFrame: the input image to be processed
176         * @param outputFrame: the output buffer in which the result is writed
177         * @param filterIndex: the offset which specifies the parameter set that should be used for the filtering
178         */
179         void runFilter_LPfilter(const std::valarray<float> &inputFrame, std::valarray<float> &outputFrame, const unsigned int filterIndex=0); // run LP filter on a specific output adress
180 
181         /**
182         *  low pass filter call and run (models the homogeneous cells network at the retina level, for example horizontal cells or photoreceptors)
183         * @param inputOutputFrame: the input image to be processed on which the result is rewrited
184         * @param filterIndex: the offset which specifies the parameter set that should be used for the filtering
185         */
186         void runFilter_LPfilter_Autonomous(std::valarray<float> &inputOutputFrame, const unsigned int filterIndex=0);// run LP filter on the input data and rewrite it
187 
188         /**
189         *  local luminance adaptation call and run (contrast enhancement property of the photoreceptors)
190         * @param inputOutputFrame: the input image to be processed
191         * @param localLuminance: an image which represents the local luminance of the inputFrame parameter, in general, it is its low pass spatial filtering
192         * @return the processed image, the output is reachable later by using function getOutput()
193         */
194         const std::valarray<float> &runFilter_LocalAdapdation(const std::valarray<float> &inputOutputFrame, const std::valarray<float> &localLuminance);// run local adaptation filter and save result in _filterOutput
195 
196         /**
197         *  local luminance adaptation call and run (contrast enhancement property of the photoreceptors)
198         * @param inputFrame: the input image to be processed
199         * @param localLuminance: an image which represents the local luminance of the inputFrame parameter, in general, it is its low pass spatial filtering
200         * @param outputFrame: the output buffer in which the result is writed
201         */
202         void runFilter_LocalAdapdation(const std::valarray<float> &inputFrame, const std::valarray<float> &localLuminance, std::valarray<float> &outputFrame); // run local adaptation filter on a specific output adress
203 
204         /**
205         *  local luminance adaptation call and run (contrast enhancement property of the photoreceptors)
206         * @param inputFrame: the input image to be processed
207         * @return the processed image, the output is reachable later by using function getOutput()
208         */
209         const std::valarray<float> &runFilter_LocalAdapdation_autonomous(const std::valarray<float> &inputFrame);// run local adaptation filter and save result in _filterOutput
210 
211         /**
212         *  local luminance adaptation call and run (contrast enhancement property of the photoreceptors)
213         * @param inputFrame: the input image to be processed
214         * @param outputFrame: the output buffer in which the result is writen
215         */
216         void runFilter_LocalAdapdation_autonomous(const std::valarray<float> &inputFrame, std::valarray<float> &outputFrame); // run local adaptation filter on a specific output adress
217 
218         /**
219         * run low pass filtering with progressive parameters (models the retina log sampling of the photoreceptors and its low pass filtering effect consequence: more powerfull low pass filtering effect on the corners)
220         * @param inputFrame: the input image to be processed
221         * @param filterIndex: the index which specifies the parameter set that should be used for the filtering
222         * @return the processed image, the output is reachable later by using function getOutput() if outputFrame is NULL
223         */
runProgressiveFilter(std::valarray<float> & inputFrame,const unsigned int filterIndex=0)224         inline void runProgressiveFilter(std::valarray<float> &inputFrame, const unsigned int filterIndex=0) { _spatiotemporalLPfilter_Irregular(&inputFrame[0], filterIndex); }
225 
226         /**
227         * run low pass filtering with progressive parameters (models the retina log sampling of the photoreceptors and its low pass filtering effect consequence: more powerfull low pass filtering effect on the corners)
228         * @param inputFrame: the input image to be processed
229         * @param outputFrame: the output buffer in which the result is writen
230         * @param filterIndex: the index which specifies the parameter set that should be used for the filtering
231         */
runProgressiveFilter(const std::valarray<float> & inputFrame,std::valarray<float> & outputFrame,const unsigned int filterIndex=0)232         inline void runProgressiveFilter(const std::valarray<float> &inputFrame,
233             std::valarray<float> &outputFrame,
234             const unsigned int filterIndex=0)
235         {_spatiotemporalLPfilter_Irregular(get_data(inputFrame), &outputFrame[0], filterIndex); }
236 
237         /**
238         * first order spatio-temporal low pass filter setup function
239         * @param beta: gain of the filter (generally set to zero)
240         * @param tau: time constant of the filter (unit is frame for video processing)
241         * @param k: spatial constant of the filter (unit is pixels)
242         * @param filterIndex: the index which specifies the parameter set that should be used for the filtering
243         */
244         void setLPfilterParameters(const float beta, const float tau, const float k, const unsigned int filterIndex=0); // change the parameters of the filter
245 
246         /**
247         * first order spatio-temporal low pass filter setup function
248         * @param beta: gain of the filter (generally set to zero)
249         * @param tau: time constant of the filter (unit is frame for video processing)
250         * @param alpha0: spatial constant of the filter (unit is pixels) on the border of the image
251         * @param filterIndex: the index which specifies the parameter set that should be used for the filtering
252         */
253         void setProgressiveFilterConstants_CentredAccuracy(const float beta, const float tau, const float alpha0, const unsigned int filterIndex=0);
254 
255         /**
256         * first order spatio-temporal low pass filter setup function
257         * @param beta: gain of the filter (generally set to zero)
258         * @param tau: time constant of the filter (unit is frame for video processing)
259         * @param alpha0: spatial constant of the filter (unit is pixels) on the border of the image
260         * @param accuracyMap an image (float format) which values range is between 0 and 1, where 0 means, apply no filtering and 1 means apply the filtering as specified in the parameters set, intermediate values allow to smooth variations of the filtering strength
261         * @param filterIndex: the index which specifies the parameter set that should be used for the filtering
262         */
263         void setProgressiveFilterConstants_CustomAccuracy(const float beta, const float tau, const float alpha0, const std::valarray<float> &accuracyMap, const unsigned int filterIndex=0);
264 
265         /**
266         * local luminance adaptation setup, this function should be applied for normal local adaptation (not for tone mapping operation)
267         * @param v0: compression effect for the local luminance adaptation processing, set a value between 0.6 and 0.9 for best results, a high value yields to a high compression effect
268         * @param maxInputValue: the maximum amplitude value measured after local adaptation processing (c.f. function runFilter_LocalAdapdation & runFilter_LocalAdapdation_autonomous)
269         * @param meanLuminance: the a priori meann luminance of the input data (should be 128 for 8bits images but can vary greatly in case of High Dynamic Range Images (HDRI)
270         */
setV0CompressionParameter(const float v0,const float maxInputValue,const float)271         void setV0CompressionParameter(const float v0, const float maxInputValue, const float)
272         {
273             _v0=v0*maxInputValue;
274             _localLuminanceFactor=v0;
275             _localLuminanceAddon=maxInputValue*(1.0f-v0);
276             _maxInputValue=maxInputValue;
277         }
278 
279         /**
280         * update local luminance adaptation setup, initial maxInputValue is kept. This function should be applied for normal local adaptation (not for tone mapping operation)
281         * @param v0: compression effect for the local luminance adaptation processing, set a value between 0.6 and 0.9 for best results, a high value yields to a high compression effect
282         * @param meanLuminance: the a priori meann luminance of the input data (should be 128 for 8bits images but can vary greatly in case of High Dynamic Range Images (HDRI)
283         */
setV0CompressionParameter(const float v0,const float meanLuminance)284         void setV0CompressionParameter(const float v0, const float meanLuminance) { this->setV0CompressionParameter(v0, _maxInputValue, meanLuminance); }
285 
286         /**
287         * local luminance adaptation setup, this function should be applied for normal local adaptation (not for tone mapping operation)
288         * @param v0: compression effect for the local luminance adaptation processing, set a value between 0.6 and 0.9 for best results, a high value yields to a high compression effect
289         */
setV0CompressionParameter(const float v0)290         void setV0CompressionParameter(const float v0)
291         {
292             _v0=v0*_maxInputValue;
293             _localLuminanceFactor=v0;
294             _localLuminanceAddon=_maxInputValue*(1.0f-v0);
295         }
296 
297         /**
298         * local luminance adaptation setup, this function should be applied for local adaptation applied to tone mapping operation
299         * @param v0: compression effect for the local luminance adaptation processing, set a value between 0.6 and 0.9 for best results, a high value yields to a high compression effect
300         * @param maxInputValue: the maximum amplitude value measured after local adaptation processing (c.f. function runFilter_LocalAdapdation & runFilter_LocalAdapdation_autonomous)
301         * @param meanLuminance: the a priori meann luminance of the input data (should be 128 for 8bits images but can vary greatly in case of High Dynamic Range Images (HDRI)
302         */
setV0CompressionParameterToneMapping(const float v0,const float maxInputValue,const float meanLuminance=128.0f)303         void setV0CompressionParameterToneMapping(const float v0, const float maxInputValue, const float meanLuminance=128.0f)
304         {
305             _v0=v0*maxInputValue;
306             _localLuminanceFactor=1.0f;
307             _localLuminanceAddon=meanLuminance*v0;
308             _maxInputValue=maxInputValue;
309         }
310 
311         /**
312         * update compression parameters while keeping v0 parameter value
313         * @param meanLuminance the input frame mean luminance
314         */
updateCompressionParameter(const float meanLuminance)315         inline void updateCompressionParameter(const float meanLuminance)
316         {
317             _localLuminanceFactor=1;
318             _localLuminanceAddon=meanLuminance*_v0;
319         }
320 
321         /**
322         * @return the v0 compression parameter used to compute the local adaptation
323         */
getV0CompressionParameter()324         float getV0CompressionParameter() { return _v0/_maxInputValue; }
325 
326         /**
327         * @return the output result of the object
328         */
getOutput() const329         inline const std::valarray<float> &getOutput() const { return _filterOutput; }
330 
331         /**
332         * @return number of rows of the filter
333         */
getNBrows()334         inline unsigned int getNBrows() { return _filterOutput.getNBrows(); }
335 
336         /**
337         * @return number of columns of the filter
338         */
getNBcolumns()339         inline unsigned int getNBcolumns() { return _filterOutput.getNBcolumns(); }
340 
341         /**
342         * @return number of pixels of the filter
343         */
getNBpixels()344         inline unsigned int getNBpixels() { return _filterOutput.getNBpixels(); }
345 
346         /**
347         * force filter output to be normalized between 0 and maxValue
348         * @param maxValue: the maximum output value that is required
349         */
normalizeGrayOutput_0_maxOutputValue(const float maxValue)350         inline void normalizeGrayOutput_0_maxOutputValue(const float maxValue) { _filterOutput.normalizeGrayOutput_0_maxOutputValue(maxValue); }
351 
352         /**
353         * force filter output to be normalized around 0 and rescaled with a sigmoide effect (extrem values saturation)
354         * @param maxValue: the maximum output value that is required
355         */
normalizeGrayOutputCentredSigmoide()356         inline void normalizeGrayOutputCentredSigmoide() { _filterOutput.normalizeGrayOutputCentredSigmoide(); }
357 
358         /**
359         * force filter output to be normalized : data centering and std normalisation
360         * @param maxValue: the maximum output value that is required
361         */
centerReductImageLuminance()362         inline void centerReductImageLuminance() { _filterOutput.centerReductImageLuminance(); }
363 
364         /**
365         * @return the maximum input buffer value
366         */
getMaxInputValue()367         inline float getMaxInputValue() { return _maxInputValue; }
368 
369         /**
370         * @return the maximum input buffer value
371         */
setMaxInputValue(const float newMaxInputValue)372         inline void setMaxInputValue(const float newMaxInputValue) { this->_maxInputValue=newMaxInputValue; }
373 
374     protected:
375 
376         /////////////////////////
377         // data buffers
378         TemplateBuffer<float> _filterOutput; // primary buffer (contains processing outputs)
379         std::valarray<float> _localBuffer; // local secondary buffer
380         /////////////////////////
381         // PARAMETERS
382         unsigned int _halfNBrows;
383         unsigned int _halfNBcolumns;
384 
385         // parameters buffers
386         std::valarray <float>_filteringCoeficientsTable;
387         std::valarray <float>_progressiveSpatialConstant;// pointer to a local table containing local spatial constant (allocated with the object)
388         std::valarray <float>_progressiveGain;// pointer to a local table containing local spatial constant (allocated with the object)
389 
390         // local adaptation filtering parameters
391         float _v0; //value used for local luminance adaptation function
392         float _maxInputValue;
393         float _meanInputValue;
394         float _localLuminanceFactor;
395         float _localLuminanceAddon;
396 
397         // protected data related to standard low pass filters parameters
398         float _a;
399         float _tau;
400         float _gain;
401 
402         /////////////////////////
403         // FILTERS METHODS
404 
405         // Basic low pass spation temporal low pass filter used by each retina filters
406         void _spatiotemporalLPfilter(const float *inputFrame, float *LPfilterOutput, const unsigned int coefTableOffset=0);
407         float _squaringSpatiotemporalLPfilter(const float *inputFrame, float *outputFrame, const unsigned int filterIndex=0);
408 
409         // LP filter with an irregular spatial filtering
410 
411         // -> rewrites the input buffer
412         void _spatiotemporalLPfilter_Irregular(float *inputOutputFrame, const unsigned int filterIndex=0);
413         // writes the output on another buffer
414         void _spatiotemporalLPfilter_Irregular(const float *inputFrame, float *outputFrame, const unsigned int filterIndex=0);
415         // LP filter that squares the input and computes the output ONLY on the areas where the integrationAreas map are TRUE
416         void _localSquaringSpatioTemporalLPfilter(const float *inputFrame, float *LPfilterOutput, const unsigned int *integrationAreas, const unsigned int filterIndex=0);
417 
418         // local luminance adaptation of the input in regard of localLuminance buffer
419         void _localLuminanceAdaptation(const float *inputFrame, const float *localLuminance, float *outputFrame, const bool updateLuminanceMean=true);
420         // local luminance adaptation of the input in regard of localLuminance buffer, the input is rewrited and becomes the output
421         void _localLuminanceAdaptation(float *inputOutputFrame, const float *localLuminance);
422         // local adaptation applied on a range of values which can be positive and negative
423         void _localLuminanceAdaptationPosNegValues(const float *inputFrame, const float *localLuminance, float *outputFrame);
424 
425 
426         //////////////////////////////////////////////////////////////
427         // 1D directional filters used for the 2D low pass filtering
428 
429         // 1D filters with image input
430         void _horizontalCausalFilter_addInput(const float *inputFrame, float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd);
431         // 1D filters  with image input that is squared in the function // parallelized with TBB
432         void _squaringHorizontalCausalFilter(const float *inputFrame, float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd);
433         //  vertical anticausal filter that returns the mean value of its result
434         float _verticalAnticausalFilter_returnMeanValue(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd);
435 
436         // most simple functions: only perform 1D filtering with output=input (no add on)
437         void _horizontalCausalFilter(float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd);
438         void _horizontalAnticausalFilter(float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd);     // parallelized with TBB
439         void _verticalCausalFilter(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd);     // parallelized with TBB
440         void _verticalAnticausalFilter(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd);
441 
442         // perform 1D filtering with output with varrying spatial coefficient
443         void _horizontalCausalFilter_Irregular(float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd);
444         void _horizontalCausalFilter_Irregular_addInput(const float *inputFrame, float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd);
445         void _horizontalAnticausalFilter_Irregular(float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd, const float *spatialConstantBuffer);   // parallelized with TBB
446         void _verticalCausalFilter_Irregular(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd, const float *spatialConstantBuffer);   // parallelized with TBB
447         void _verticalAnticausalFilter_Irregular_multGain(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd);
448 
449 
450         // 1D filters in which the output is multiplied by _gain
451         void _verticalAnticausalFilter_multGain(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd); // this functions affects _gain at the output // parallelized with TBB
452         void _horizontalAnticausalFilter_multGain(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd); // this functions affects _gain at the output
453 
454         // LP filter on specific parts of the picture instead of all the image
455         // same functions (some of them) but take a binary flag to allow integration, false flag means, 0 at the output...
456         void _local_squaringHorizontalCausalFilter(const float *inputFrame, float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd, const unsigned int *integrationAreas);
457         void _local_horizontalAnticausalFilter(float *outputFrame, unsigned int IDrowStart, unsigned int IDrowEnd, const unsigned int *integrationAreas);
458         void _local_verticalCausalFilter(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd, const unsigned int *integrationAreas);
459         void _local_verticalAnticausalFilter_multGain(float *outputFrame, unsigned int IDcolumnStart, unsigned int IDcolumnEnd, const unsigned int *integrationAreas); // this functions affects _gain at the output
460 
461 #ifdef MAKE_PARALLEL
462         /******************************************************
463         ** IF some parallelizing thread methods are available, then, main loops are parallelized using these functors
464         ** ==> main idea paralellise main filters loops, then, only the most used methods are parallelized... TODO : increase the number of parallelised methods as necessary
465         ** ==> functors names = Parallel_$$$ where $$$= the name of the serial method that is parallelised
466         ** ==> functors constructors can differ from the parameters used with their related serial functions
467         */
468 
469 #define _DEBUG_TBB // define DEBUG_TBB in order to display additionnal data on stdout
470         class Parallel_horizontalAnticausalFilter: public cv::ParallelLoopBody
471         {
472         private:
473             float *outputFrame;
474             unsigned int IDrowEnd, nbColumns;
475             float filterParam_a;
476         public:
477             // constructor which takes the input image pointer reference reference and limits
Parallel_horizontalAnticausalFilter(float * bufferToProcess,const unsigned int idEnd,const unsigned int nbCols,const float a)478             Parallel_horizontalAnticausalFilter(float *bufferToProcess, const unsigned int idEnd, const unsigned int nbCols, const float a )
479                 :outputFrame(bufferToProcess), IDrowEnd(idEnd), nbColumns(nbCols), filterParam_a(a)
480             {
481 #ifdef DEBUG_TBB
482                 std::cout<<"Parallel_horizontalAnticausalFilter::Parallel_horizontalAnticausalFilter :"
483                     <<"\n\t idEnd="<<IDrowEnd
484                     <<"\n\t nbCols="<<nbColumns
485                     <<"\n\t filterParam="<<filterParam_a
486                     <<std::endl;
487 #endif
488             }
489 
operator ()(const Range & r) const490             virtual void operator()( const Range& r ) const CV_OVERRIDE {
491 
492 #ifdef DEBUG_TBB
493                 std::cout<<"Parallel_horizontalAnticausalFilter::operator() :"
494                     <<"\n\t range size="<<r.size()
495                     <<"\n\t first index="<<r.start
496                     //<<"\n\t last index="<<filterParam
497                     <<std::endl;
498 #endif
499                 for (int IDrow=r.start; IDrow!=r.end; ++IDrow)
500                 {
501                     float* outputPTR=outputFrame+(IDrowEnd-IDrow)*(nbColumns)-1;
502                     float result=0;
503                     for (unsigned int index=0; index<nbColumns; ++index)
504                     {
505                         result = *(outputPTR)+  filterParam_a* result;
506                         *(outputPTR--) = result;
507                     }
508                 }
509             }
510         };
511 
512         class Parallel_horizontalCausalFilter_addInput: public cv::ParallelLoopBody
513         {
514         private:
515             const float *inputFrame;
516             float *outputFrame;
517             unsigned int IDrowStart, nbColumns;
518             float filterParam_a, filterParam_tau;
519         public:
Parallel_horizontalCausalFilter_addInput(const float * bufferToAddAsInputProcess,float * bufferToProcess,const unsigned int idStart,const unsigned int nbCols,const float a,const float tau)520             Parallel_horizontalCausalFilter_addInput(const float *bufferToAddAsInputProcess, float *bufferToProcess, const unsigned int idStart, const unsigned int nbCols,  const float a,  const float tau)
521                 :inputFrame(bufferToAddAsInputProcess), outputFrame(bufferToProcess), IDrowStart(idStart), nbColumns(nbCols), filterParam_a(a), filterParam_tau(tau){}
522 
operator ()(const Range & r) const523             virtual void operator()( const Range& r ) const CV_OVERRIDE {
524                 for (int IDrow=r.start; IDrow!=r.end; ++IDrow)
525                 {
526                     float* outputPTR=outputFrame+(IDrowStart+IDrow)*nbColumns;
527                     const float* inputPTR=inputFrame+(IDrowStart+IDrow)*nbColumns;
528                     float result=0;
529                     for (unsigned int index=0; index<nbColumns; ++index)
530                     {
531                         result = *(inputPTR++) + filterParam_tau**(outputPTR)+  filterParam_a* result;
532                         *(outputPTR++) = result;
533                     }
534                 }
535             }
536         };
537 
538         class Parallel_verticalCausalFilter: public cv::ParallelLoopBody
539         {
540         private:
541             float *outputFrame;
542             unsigned int nbRows, nbColumns;
543             float filterParam_a;
544         public:
Parallel_verticalCausalFilter(float * bufferToProcess,const unsigned int nbRws,const unsigned int nbCols,const float a)545             Parallel_verticalCausalFilter(float *bufferToProcess, const unsigned int nbRws, const unsigned int nbCols, const float a )
546                 :outputFrame(bufferToProcess), nbRows(nbRws), nbColumns(nbCols), filterParam_a(a){}
547 
operator ()(const Range & r) const548             virtual void operator()( const Range& r ) const CV_OVERRIDE {
549                 for (int IDcolumn=r.start; IDcolumn!=r.end; ++IDcolumn)
550                 {
551                     float result=0;
552                     float *outputPTR=outputFrame+IDcolumn;
553 
554                     for (unsigned int index=0; index<nbRows; ++index)
555                     {
556                         result = *(outputPTR) + filterParam_a * result;
557                         *(outputPTR) = result;
558                         outputPTR+=nbColumns;
559 
560                     }
561                 }
562             }
563         };
564 
565         class Parallel_verticalAnticausalFilter_multGain: public cv::ParallelLoopBody
566         {
567         private:
568             float *outputFrame;
569             unsigned int nbRows, nbColumns;
570             float filterParam_a, filterParam_gain;
571         public:
Parallel_verticalAnticausalFilter_multGain(float * bufferToProcess,const unsigned int nbRws,const unsigned int nbCols,const float a,const float gain)572             Parallel_verticalAnticausalFilter_multGain(float *bufferToProcess, const unsigned int nbRws, const unsigned int nbCols, const float a, const float  gain)
573                 :outputFrame(bufferToProcess), nbRows(nbRws), nbColumns(nbCols), filterParam_a(a), filterParam_gain(gain){}
574 
operator ()(const Range & r) const575             virtual void operator()( const Range& r ) const CV_OVERRIDE {
576                 float* offset=outputFrame+nbColumns*nbRows-nbColumns;
577                 for (int IDcolumn=r.start; IDcolumn!=r.end; ++IDcolumn)
578                 {
579                     float result=0;
580                     float *outputPTR=offset+IDcolumn;
581 
582                     for (unsigned int index=0; index<nbRows; ++index)
583                     {
584                         result = *(outputPTR) + filterParam_a * result;
585                         *(outputPTR) = filterParam_gain*result;
586                         outputPTR-=nbColumns;
587 
588                     }
589                 }
590             }
591         };
592 
593         class Parallel_localAdaptation: public cv::ParallelLoopBody
594         {
595         private:
596             const float *localLuminance, *inputFrame;
597             float *outputFrame;
598             float localLuminanceFactor, localLuminanceAddon, maxInputValue;
599         public:
Parallel_localAdaptation(const float * localLum,const float * inputImg,float * bufferToProcess,const float localLuminanceFact,const float localLuminanceAdd,const float maxInputVal)600             Parallel_localAdaptation(const float *localLum, const float *inputImg, float *bufferToProcess, const float localLuminanceFact, const float localLuminanceAdd, const float maxInputVal)
601                 :localLuminance(localLum), inputFrame(inputImg),outputFrame(bufferToProcess), localLuminanceFactor(localLuminanceFact), localLuminanceAddon(localLuminanceAdd), maxInputValue(maxInputVal) {}
602 
operator ()(const Range & r) const603             virtual void operator()( const Range& r ) const CV_OVERRIDE {
604                 const float *localLuminancePTR=localLuminance+r.start;
605                 const float *inputFramePTR=inputFrame+r.start;
606                 float *outputFramePTR=outputFrame+r.start;
607                 for (int IDpixel=r.start ; IDpixel!=r.end ; ++IDpixel, ++inputFramePTR, ++outputFramePTR)
608                 {
609                     float X0=*(localLuminancePTR++)*localLuminanceFactor+localLuminanceAddon;
610                     // 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...
611                     *(outputFramePTR) = (maxInputValue+X0)**inputFramePTR/(*inputFramePTR +X0+0.00000000001f);
612                     //std::cout<<"BasicRetinaFilter::inputFrame[IDpixel]=%f, X0=%f, outputFrame[IDpixel]=%f\n", inputFrame[IDpixel], X0, outputFrame[IDpixel]);
613                 }
614             }
615         };
616 
617         //////////////////////////////////////////
618         /// Specific filtering methods which manage non const spatial filtering parameter (used By retinacolor and LogProjectors)
619         class Parallel_horizontalAnticausalFilter_Irregular: public cv::ParallelLoopBody
620         {
621         private:
622             float *outputFrame;
623             const float *spatialConstantBuffer;
624             unsigned int IDrowEnd, nbColumns;
625         public:
Parallel_horizontalAnticausalFilter_Irregular(float * bufferToProcess,const float * spatialConst,const unsigned int idEnd,const unsigned int nbCols)626             Parallel_horizontalAnticausalFilter_Irregular(float *bufferToProcess, const float *spatialConst, const unsigned int idEnd, const unsigned int nbCols)
627                 :outputFrame(bufferToProcess), spatialConstantBuffer(spatialConst), IDrowEnd(idEnd), nbColumns(nbCols){}
628 
operator ()(const Range & r) const629             virtual void operator()( const Range& r ) const CV_OVERRIDE {
630 
631                 for (int IDrow=r.start; IDrow!=r.end; ++IDrow)
632                 {
633                     float* outputPTR=outputFrame+(IDrowEnd-IDrow)*(nbColumns)-1;
634                     const float* spatialConstantPTR=spatialConstantBuffer+(IDrowEnd-IDrow)*(nbColumns)-1;
635                     float result=0;
636                     for (unsigned int index=0; index<nbColumns; ++index)
637                     {
638                         result = *(outputPTR)+  *(spatialConstantPTR--)* result;
639                         *(outputPTR--) = result;
640                     }
641                 }
642             }
643         };
644 
645         class Parallel_verticalCausalFilter_Irregular: public cv::ParallelLoopBody
646         {
647         private:
648             float *outputFrame;
649             const float *spatialConstantBuffer;
650             unsigned int nbRows, nbColumns;
651         public:
Parallel_verticalCausalFilter_Irregular(float * bufferToProcess,const float * spatialConst,const unsigned int nbRws,const unsigned int nbCols)652             Parallel_verticalCausalFilter_Irregular(float *bufferToProcess, const float *spatialConst, const unsigned int nbRws, const unsigned int nbCols)
653                 :outputFrame(bufferToProcess), spatialConstantBuffer(spatialConst), nbRows(nbRws), nbColumns(nbCols){}
654 
operator ()(const Range & r) const655             virtual void operator()( const Range& r ) const CV_OVERRIDE {
656                 for (int IDcolumn=r.start; IDcolumn!=r.end; ++IDcolumn)
657                 {
658                     float result=0;
659                     float *outputPTR=outputFrame+IDcolumn;
660                     const float* spatialConstantPTR=spatialConstantBuffer+IDcolumn;
661                     for (unsigned int index=0; index<nbRows; ++index)
662                     {
663                         result = *(outputPTR) +  *(spatialConstantPTR) * result;
664                         *(outputPTR) = result;
665                         outputPTR+=nbColumns;
666                         spatialConstantPTR+=nbColumns;
667                     }
668                 }
669             }
670         };
671 
672 #endif
673 
674     };
675 
676 }// end of namespace bioinspired
677 }// end of namespace cv
678 #endif
679