OpenCV  3.1.0
Open Source Computer Vision
Bioinspired Module Retina Introduction

Retina class overview

Note
do not forget that the retina model is included in the following namespace : cv::bioinspired with C++ and in cv2.bioinspired with Python

Introduction

This class provides the main controls of the Gipsa/Listic labs human retina model. This is a non separable spatio-temporal filter modelling the two main retina information channels :

This model originates from Jeanny Herault work [71] . It has been involved in Alexandre Benoit phd and his current research [11], [131] . He currently maintains this module within OpenCV. It includes the work of other Jeanny's phd student such as [31] and the log polar transformations of Barthelemy Durette described in Jeanny's book.

More into details here is an overview of the retina properties that are implemented here :

The former behavior compresses luminance range and allows very bright areas and very dark ones to be visible on the same picture with lots of details. The latter reduces low frequency luminance energy (mean luminance) and enhances mid-frequencies (details). Applied all together, retina well prepares visual signals prior high level analysis. Those properties are really interesting with videos where light changes are dramatically reduced with an interesting temporal consistency.

Use

This model can be used as a preprocessing stage in the aim of :

Note
  • For ease of use in computer vision applications, the two retina channels are applied on all the input images. This does not follow the real retina topology but it is practical from an image processing point of view. If retina mapping (foveal and parafoveal vision) is required, use the log sampling capabilities proposed within the class.
  • Please do not hesitate to contribute by extending the retina description, code, use cases for complementary explanations and demonstrations.

Use case illustrations

Image preprocessing using the Parvocellular pathway (parvo retina output)

As a preliminary presentation, let's start with a visual example. We propose to apply the filter on a low quality color jpeg image with backlight problems. Here is the considered input... *"Well,i could see more with my eyes than what i captured with my camera..."*

retinaInput.jpg
a low quality color jpeg image with backlight problems.

Below, the retina foveal model applied on the entire image with default parameters. Details are enforced whatever the local luminance is. Here there contours are strongly enforced but the noise level is kept low. Halo effects are voluntary visible with this configuration. See parameters discussion below and increase horizontalCellsGain near 1 to remove them.

retinaOutput_default.jpg
the retina foveal model applied on the entire image with default parameters. Here contours are enforced, luminance is corrected and halo effects are voluntary visible with this configuration, increase horizontalCellsGain near 1 to remove them.

Below, a second retina foveal model output applied on the entire image with a parameters setup focused on naturalness perception. *"Hey, i now recognize my cat, looking at the mountains at the end of the day !"*. Here contours are enforced, luminance is corrected but halos are avoided with this configuration. The backlight effect is corrected and highlight details are still preserved. Then, even on a low quality jpeg image, if some luminance's information remains, the retina is able to reconstruct a proper visual signal. Such configuration is also useful for High Dynamic Range (HDR) images compression to 8bit images as discussed in [11] and in the demonstration codes discussed below. As shown at the end of the page, parameter changes from defaults are :

retinaOutput_realistic.jpg
the retina foveal model applied on the entire image with 'naturalness' parameters. Here contours are enforced but halo effects are avoided with this configuration, horizontalCellsGain is 0.3 and photoreceptorsLocalAdaptationSensitivity=ganglioncellsSensitivity=0.89.

As observed in this preliminary demo, the retina can be settled up with various parameters, by default, as shown on the figure above, the retina strongly reduces mean luminance energy and enforces all details of the visual scene. Luminance energy and halo effects can be modulated (exaggerated to cancelled as shown on the two examples). In order to use your own parameters, you can use at least one time the write(String fs) method which will write a proper XML file with all default parameters. Then, tweak it on your own and reload them at any time using method setup(String fs). These methods update a Retina::RetinaParameters member structure that is described hereafter. XML parameters file samples are shown at the end of the page.

Tone mapping processing capability using the Parvocellular pathway (parvo retina output)

This retina model naturally handles luminance range compression. Local adaptation stages and spectral whitening contribute to luminance range compression. In addition, high frequency noise that often corrupts tone mapped images is removed at early stages of the process thus leading to natural perception and noise free tone mapping.

Compared to the demos shown above, setup differences are the following ones: (see bioinspired/samples/OpenEXRimages_HDR_Retina_toneMapping.cpp for more details)

Have a look at the end of this page to see how to specify these parameters in a configuration file.

The following two illustrations show the effect of such configuration on 2 image samples.

HDRtoneMapping_candleSample.jpg
HDR image tone mapping example with generic parameters. Original image comes from http://openexr.com/ samples (openexr-images-1.7.0/ScanLines/CandleGlass.exr)
HDRtoneMapping_memorialSample.jpg
HDR image tone mapping example with the same generic parameters. Original image comes from http://www.pauldebevec.com/Research/HDR/memorial.exr)

Motion and event detection using the Magnocellular pathway (magno retina output)

Spatio-temporal events can be easily detected using magno output of the retina (use the getMagno() method). Its energy linearly increases with motion speed. An event blob detector is proposed with the TransientAreasSegmentationModule class also provided in the bioinspired module. The basic idea is to detect local energy drops with regard of the neighborhood and then to apply a threshold. Such process has been used in a bag of words description of videos on the TRECVid challenge [131] and only allows video frames description on transient areas.

We present here some illustrations of the retina outputs on some examples taken from http://changedetection.net/ with RGB and thermal videos.

Note
here, we use the default retina setup that generates halos around strong edges. Note that temporal constants allow a temporal effect to be visible on moting objects (useful for still image illustrations of a video). Halos can be removed by increasing retina Hcells gain while temporal effects can be reduced by decreasing temporal constant values. Also take into account that the two retina outputs are rescaled in range [0:255] such that magno output can show a lot of "noise" when nothing moves while drawing it. However, its energy remains low if you retrieve it using getMagnoRAW getter instead.
VideoDemo_RGB_PETS2006.jpg
Retina processing on RGB image sequence : example from http://changedetection.net/ (baseline/PETS2006). Parvo enforces static signals but smooths moving persons since they do not remain static from its point of view. Magno channel highligths moving persons, observe the energy mapping on the one on top, partly behind a dark glass.
VideoDemo_thermal_park.jpg
Retina processing on gray levels image sequence : example from http://changedetection.net/ (thermal/park). On such grayscale images, parvo channel enforces contrasts while magno strongly reacts on moving pedestrians

Literature

For more information, refer to the following papers :

This retina filter code includes the research contributions of phd/research collegues from which code has been redrawn by the author :

Retina programming interfaces

The proposed class allows the Gipsa (preliminary work) / Listic labs retina model to be used. It can be applied on still images, images sequences and video sequences.

Here is an overview of the Retina interface, allocate one instance with the createRetina functions (C++, Java, Python) :

namespace cv{namespace bioinspired{
class Retina : public Algorithm
{
public:
// parameters setup instance
struct RetinaParameters; // this class is detailed later
// main method for input frame processing (all use method, can also perform High Dynamic Range tone mapping)
void run (InputArray inputImage);
// specific method aiming at correcting luminance only (faster High Dynamic Range tone mapping)
void applyFastToneMapping(InputArray inputImage, OutputArray outputToneMappedImage)
// output buffers retrieval methods
// -> foveal color vision details channel with luminance and noise correction
void getParvo (OutputArray retinaOutput_parvo);
void getParvoRAW (OutputArray retinaOutput_parvo);// retrieve original output buffers without any normalisation
const Mat getParvoRAW () const;// retrieve original output buffers without any normalisation
// -> peripheral monochrome motion and events (transient information) channel
void getMagno (OutputArray retinaOutput_magno);
void getMagnoRAW (OutputArray retinaOutput_magno); // retrieve original output buffers without any normalisation
const Mat getMagnoRAW () const;// retrieve original output buffers without any normalisation
// reset retina buffers... equivalent to closing your eyes for some seconds
void clearBuffers ();
// retrieve input and output buffers sizes
// setup methods with specific parameters specification of global xml config file loading/write
void setup (String retinaParameterFile="", const bool applyDefaultSetupOnFailure=true);
void setup (FileStorage &fs, const bool applyDefaultSetupOnFailure=true);
void setup (RetinaParameters newParameters);
struct Retina::RetinaParameters getParameters ();
const String printSetup ();
virtual void write (String fs) const;
virtual void write (FileStorage &fs) const;
void setupOPLandIPLParvoChannel (const bool colorMode=true, const bool normaliseOutput=true, const float photoreceptorsLocalAdaptationSensitivity=0.7, const float photoreceptorsTemporalConstant=0.5, const float photoreceptorsSpatialConstant=0.53, const float horizontalCellsGain=0, const float HcellsTemporalConstant=1, const float HcellsSpatialConstant=7, const float ganglionCellsSensitivity=0.7);
void setupIPLMagnoChannel (const bool normaliseOutput=true, const float parasolCells_beta=0, const float parasolCells_tau=0, const float parasolCells_k=7, const float amacrinCellsTemporalCutFrequency=1.2, const float V0CompressionParameter=0.95, const float localAdaptintegration_tau=0, const float localAdaptintegration_k=7);
void setColorSaturation (const bool saturateColors=true, const float colorSaturationValue=4.0);
void activateMovingContoursProcessing (const bool activate);
void activateContoursProcessing (const bool activate);
};
// Allocators
cv::Ptr<Retina> createRetina (Size inputSize);
cv::Ptr<Retina> createRetina (Size inputSize, const bool colorMode, RETINA_COLORSAMPLINGMETHOD colorSamplingMethod=RETINA_COLOR_BAYER, const bool useRetinaLogSampling=false, const double reductionFactor=1.0, const double samplingStrenght=10.0);
}} // cv and bioinspired namespaces end

Setting up Retina

Managing the configuration file

When using the Retina::write and Retina::load methods, you create or load a XML file that stores Retina configuration.

The default configuration is presented below.

1 <?xml version="1.0"?>
2 <opencv_storage>
3 <OPLandIPLparvo>
4  <colorMode>1</colorMode>
5  <normaliseOutput>1</normaliseOutput>
6  <photoreceptorsLocalAdaptationSensitivity>7.5e-01</photoreceptorsLocalAdaptationSensitivity>
7  <photoreceptorsTemporalConstant>9.0e-01</photoreceptorsTemporalConstant>
8  <photoreceptorsSpatialConstant>5.7e-01</photoreceptorsSpatialConstant>
9  <horizontalCellsGain>0.01</horizontalCellsGain>
10  <hcellsTemporalConstant>0.5</hcellsTemporalConstant>
11  <hcellsSpatialConstant>7.</hcellsSpatialConstant>
12  <ganglionCellsSensitivity>7.5e-01</ganglionCellsSensitivity></OPLandIPLparvo>
13 <IPLmagno>
14  <normaliseOutput>1</normaliseOutput>
15  <parasolCells_beta>0.</parasolCells_beta>
16  <parasolCells_tau>0.</parasolCells_tau>
17  <parasolCells_k>7.</parasolCells_k>
18  <amacrinCellsTemporalCutFrequency>2.0e+00</amacrinCellsTemporalCutFrequency>
19  <V0CompressionParameter>9.5e-01</V0CompressionParameter>
20  <localAdaptintegration_tau>0.</localAdaptintegration_tau>
21  <localAdaptintegration_k>7.</localAdaptintegration_k></IPLmagno>
22 </opencv_storage>

Here are some words about all those parameters, tweak them as you wish to amplify or moderate retina effects (contours enforcement, halos effects, motion sensitivity, motion blurring, etc.)

Basic parameters

The simplest parameters are as follows :

Note : using color requires color channels multiplexing/demultipexing which also demands more processing. You can expect much faster processing using gray levels : it would require around 30 product per pixel for all of the retina processes and it has recently been parallelized for multicore architectures.

Photo-receptors parameters

The following parameters act on the entry point of the retina - photo-receptors - and has impact on all of the following processes. These sensors are low pass spatio-temporal filters that smooth temporal and spatial data and also adjust their sensitivity to local luminance,thus, leads to improving details extraction and high frequency noise canceling.

Horizontal cells parameters

This parameter set tunes the neural network connected to the photo-receptors, the horizontal cells. It modulates photo-receptors sensitivity and completes the processing for final spectral whitening (part of the spatial band pass effect thus favoring visual details enhancement).

NOTE Once the processing managed by the previous parameters is done, input data is cleaned from noise and luminance is already partly enhanced. The following parameters act on the last processing stages of the two outing retina signals.

Parvo (details channel) dedicated parameter

Note : this parameter can correct eventual burned images by favoring low energetic details of the visual scene, even in bright areas.

IPL Magno (motion/transient channel) parameters

Once image's information are cleaned, this channel acts as a high pass temporal filter that selects only the signals related to transient signals (events, motion, etc.). A low pass spatial filter smoothes extracted transient data while a final logarithmic compression enhances low transient events thus enhancing event sensitivity.

Demos and experiments !

First time experiments

Here are some code snippets to shortly show how to use Retina with default parameters (with halo effects). Next section redirects to more complete demos provided with the main retina class.

Here is presented how to process a webcam stream with the following steps :

C++ version (see bioinspired/samples/basicRetina.cpp) :

// include bioinspired module and OpenCV core utilities
#include <iostream>
// main function
int main(int argc, char* argv[]) {
// declare the retina input buffer.
cv::Mat inputFrame;
// setup webcam reader and grab a first frame to get its size
cv::VideoCapture videoCapture(0);
videoCapture>>inputFrame;
// allocate a retina instance with input size equal to the one of the loaded image
cv::Ptr<cv::bioinspired::Retina> myRetina = cv::bioinspired::createRetina(inputFrame.size());
/* retina parameters management methods use sample
-> save current (here default) retina parameters to a xml file (you may use it only one time to get the file and modify it)
*/
myRetina->write("RetinaDefaultParameters.xml");
// -> load parameters if file exists
myRetina->setup("RetinaSpecificParameters.xml");
// reset all retina buffers (open your eyes)
myRetina->clearBuffers();
// declare retina output buffers
cv::Mat retinaOutput_parvo;
cv::Mat retinaOutput_magno;
//main processing loop
while(true){
// if using video stream, then, grabbing a new frame, else, input remains the same
if (videoCapture.isOpened())
videoCapture>>inputFrame;
else
break;
imshow('input frame', inputImage)
// run retina on the input image
myRetina->run(inputFrame);
// grab retina outputs
myRetina->getParvo(retinaOutput_parvo);
myRetina->getMagno(retinaOutput_magno);
// draw retina outputs
cv::imshow("retina input", inputFrame);
cv::imshow("Retina Parvo", retinaOutput_parvo);
cv::imshow("Retina Magno", retinaOutput_magno);
cv::waitKey(5);
}
}

Compile this C++ code with the following command :

1 // compile
2 g++ basicRetina.cpp -o basicRetina -lopencv_core -lopencv_highgui -lopencv_bioinspired -lopencv_videoio -lopencv_imgcodecs

Python version

1 #import OpenCV module
2 import cv2
3 
4 #setup webcam reader
5 videoHandler = cv2.VideoCapture(0)
6 succeed, inputImage=videoHandler.read()
7 
8 #allocate a retina instance with input size equal to the one of the loaded image
9 retina = cv2.bioinspired.createRetina((inputImage.shape[1], inputImage.shape[0]))
10 
11 #retina parameters management methods use sample
12 #-> save current (here default) retina parameters to a xml file (you may use it only one time to get the file and modify it)
13 retina.write('retinaParams.xml')
14 #-> load retina parameters from a xml file : here we load the default parameters that we just wrote to file
15 retina.setup('retinaParams.xml')
16 
17 #main processing loop
18 stillProcess=True
19 while stillProcess is True:
20 
21  #grab a new frame and display it
22  stillProcess, inputImage=videoHandler.read()
23  cv2.imshow('input frame', inputImage)
24 
25  #run retina on the input image
26  retina.run(inputImage)
27 
28  #grab retina outputs
29  retinaOut_parvo=retina.getParvo()
30  retinaOut_magno=retina.getMagno()
31 
32  #draw retina outputs
33  cv2.imshow('retina parvo out', retinaOut_parvo)
34  cv2.imshow('retina magno out', retinaOut_magno)
35 
36  #wait a little to let the time for figures to be drawn
37  cv2.waitKey(2)

More complete demos

Note
Complementary to the following examples, have a look at the Retina tutorial in the tutorial/contrib section for complementary explanations.**

Take a look at the provided C++ examples provided with OpenCV :