2011-08-11 22:42:08 +02:00
/*#******************************************************************************
* * IMPORTANT : READ BEFORE DOWNLOADING , COPYING , INSTALLING OR USING .
* *
* * By downloading , copying , installing or using the software you agree to this license .
* * If you do not agree to this license , do not download , install ,
* * copy or use the software .
* *
* *
* * HVStools : 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 .
* * 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 .
* *
* * Maintainers : Listic lab ( code author current affiliation & applications ) and Gipsa Lab ( original research origins & applications )
* *
* * Creation - enhancement process 2007 - 2011
* * Author : Alexandre Benoit ( benoit . alexandre . vision @ gmail . com ) , LISTIC lab , Annecy le vieux , France
* *
* * 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 ) .
* * Refer to the following research paper for more information :
* * 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
* * 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 :
* * 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.
* *
* * The retina filter includes the research contributions of phd / research collegues from which code has been redrawn by the author :
* * _take a look at the retinacolor . hpp module to discover Brice Chaix de Lavarene color mosaicing / demosaicing and the reference paper :
* * = = = = > B . Chaix de Lavarene , D . Alleysson , B . Durette , J . Herault ( 2007 ) . " Efficient demosaicing through recursive filtering " , IEEE International Conference on Image Processing ICIP 2007
* * _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 .
* * = = = = > more informations in the above cited Jeanny Heraults ' s book .
* *
* * License Agreement
* * For Open Source Computer Vision Library
* *
* * Copyright ( C ) 2000 - 2008 , Intel Corporation , all rights reserved .
* * Copyright ( C ) 2008 - 2011 , Willow Garage Inc . , all rights reserved .
* *
* * For Human Visual System tools ( hvstools )
* * Copyright ( C ) 2007 - 2011 , LISTIC Lab , Annecy le Vieux and GIPSA Lab , Grenoble , France , all rights reserved .
* *
* * Third party copyrights are property of their respective owners .
* *
* * Redistribution and use in source and binary forms , with or without modification ,
* * are permitted provided that the following conditions are met :
* *
* * * Redistributions of source code must retain the above copyright notice ,
* * this list of conditions and the following disclaimer .
* *
* * * Redistributions in binary form must reproduce the above copyright notice ,
* * this list of conditions and the following disclaimer in the documentation
* * and / or other materials provided with the distribution .
* *
* * * The name of the copyright holders may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * This software is provided by the copyright holders and contributors " as is " and
* * any express or implied warranties , including , but not limited to , the implied
* * warranties of merchantability and fitness for a particular purpose are disclaimed .
* * In no event shall the Intel Corporation or contributors be liable for any direct ,
* * indirect , incidental , special , exemplary , or consequential damages
* * ( including , but not limited to , procurement of substitute goods or services ;
* * loss of use , data , or profits ; or business interruption ) however caused
* * and on any theory of liability , whether in contract , strict liability ,
* * or tort ( including negligence or otherwise ) arising in any way out of
* * the use of this software , even if advised of the possibility of such damage .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "precomp.hpp"
# include "retinacolor.hpp"
// @author Alexandre BENOIT, benoit.alexandre.vision@gmail.com, LISTIC : www.listic.univ-savoie.fr, Gipsa-Lab, France: www.gipsa-lab.inpg.fr/
# include <iostream>
# include <ctime>
namespace cv
{
// init static values
2011-08-21 13:01:53 +02:00
static float _LMStoACr1Cr2 [ ] = { 1.0 , 1.0 , 0.0 , 1.0 , - 1.0 , 0.0 , - 0.5 , - 0.5 , 1.0 } ;
2011-08-11 22:42:08 +02:00
//static double _ACr1Cr2toLMS[]={0.5, 0.5, 0.0, 0.5, -0.5, 0.0, 0.5, 0.0, 1.0};
2011-08-21 13:01:53 +02:00
static float _LMStoLab [ ] = { 0.5774 , 0.5774 , 0.5774 , 0.4082 , 0.4082 , - 0.8165 , 0.7071 , - 0.7071 , 0.0 } ;
2011-08-11 22:42:08 +02:00
// constructor/desctructor
RetinaColor : : RetinaColor ( const unsigned int NBrows , const unsigned int NBcolumns , const RETINA_COLORSAMPLINGMETHOD samplingMethod )
: BasicRetinaFilter ( NBrows , NBcolumns , 3 ) ,
_colorSampling ( NBrows * NBcolumns ) ,
_RGBmosaic ( NBrows * NBcolumns * 3 ) ,
_tempMultiplexedFrame ( NBrows * NBcolumns ) ,
_demultiplexedTempBuffer ( NBrows * NBcolumns * 3 ) ,
_demultiplexedColorFrame ( NBrows * NBcolumns * 3 ) ,
_chrominance ( NBrows * NBcolumns * 3 ) ,
_colorLocalDensity ( NBrows * NBcolumns * 3 ) ,
_imageGradient ( NBrows * NBcolumns * 3 )
{
// link to parent buffers (let's recycle !)
_luminance = & _filterOutput ;
_multiplexedFrame = & _localBuffer ;
_objectInit = false ;
_samplingMethod = samplingMethod ;
_saturateColors = false ;
_colorSaturationValue = 4.0 ;
// set default spatio-temporal filter parameters
setLPfilterParameters ( 0.0 , 0.0 , 1.5 ) ;
setLPfilterParameters ( 0.0 , 0.0 , 10.5 , 1 ) ; // for the low pass filter dedicated to contours energy extraction (demultiplexing process)
setLPfilterParameters ( 0.0 , 0.0 , 0.9 , 2 ) ;
// init default value on image Gradient
_imageGradient = 0.57 ;
// init color sampling map
_initColorSampling ( ) ;
// flush all buffers
clearAllBuffers ( ) ;
}
RetinaColor : : ~ RetinaColor ( )
{
}
/**
* function that clears all buffers of the object
*/
void RetinaColor : : clearAllBuffers ( )
{
BasicRetinaFilter : : clearAllBuffers ( ) ;
_tempMultiplexedFrame = 0 ;
_demultiplexedTempBuffer = 0 ;
_demultiplexedColorFrame = 0 ;
_chrominance = 0 ;
_imageGradient = 1 ;
}
/**
* resize retina color filter object ( resize all allocated buffers )
* @ param NBrows : the new height size
* @ param NBcolumns : the new width size
*/
void RetinaColor : : resize ( const unsigned int NBrows , const unsigned int NBcolumns )
{
BasicRetinaFilter : : clearAllBuffers ( ) ;
_colorSampling . resize ( NBrows * NBcolumns ) ;
_RGBmosaic . resize ( NBrows * NBcolumns * 3 ) ;
_tempMultiplexedFrame . resize ( NBrows * NBcolumns ) ;
_demultiplexedTempBuffer . resize ( NBrows * NBcolumns * 3 ) ;
_demultiplexedColorFrame . resize ( NBrows * NBcolumns * 3 ) ;
_chrominance . resize ( NBrows * NBcolumns * 3 ) ;
_colorLocalDensity . resize ( NBrows * NBcolumns * 3 ) ;
_imageGradient . resize ( NBrows * NBcolumns * 3 ) ;
// link to parent buffers (let's recycle !)
_luminance = & _filterOutput ;
_multiplexedFrame = & _localBuffer ;
// init color sampling map
_initColorSampling ( ) ;
// clean buffers
clearAllBuffers ( ) ;
}
void RetinaColor : : _initColorSampling ( )
{
// filling the conversion table for multiplexed <=> demultiplexed frame
srand ( time ( NULL ) ) ;
// preInit cones probabilities
_pR = _pB = _pG = 0 ;
switch ( _samplingMethod )
{
case RETINA_COLOR_RANDOM :
for ( unsigned int index = 0 ; index < this - > getNBpixels ( ) ; + + index )
{
// random RGB sampling
unsigned int colorIndex = rand ( ) % 24 ;
if ( colorIndex < 8 ) {
colorIndex = 0 ;
+ + _pR ;
} else
{
if ( colorIndex < 21 ) {
colorIndex = 1 ;
+ + _pG ;
} else {
colorIndex = 2 ;
+ + _pB ;
}
}
_colorSampling [ index ] = colorIndex * this - > getNBpixels ( ) + index ;
}
2011-08-21 13:01:53 +02:00
_pR / = ( float ) this - > getNBpixels ( ) ;
_pG / = ( float ) this - > getNBpixels ( ) ;
_pB / = ( float ) this - > getNBpixels ( ) ;
2011-08-11 22:42:08 +02:00
std : : cout < < " Color channels proportions: pR, pG, pB= " < < _pR < < " , " < < _pG < < " , " < < _pB < < " , " < < std : : endl ;
break ;
case RETINA_COLOR_DIAGONAL :
for ( unsigned int index = 0 ; index < this - > getNBpixels ( ) ; + + index )
{
_colorSampling [ index ] = index + ( ( index % 3 + ( index % _filterOutput . getNBcolumns ( ) ) ) % 3 ) * _filterOutput . getNBpixels ( ) ;
}
_pR = _pB = _pG = 1.0 / 3.0 ;
break ;
case RETINA_COLOR_BAYER : // default sets bayer sampling
for ( unsigned int index = 0 ; index < _filterOutput . getNBpixels ( ) ; + + index )
{
//First line: R G R G
_colorSampling [ index ] = index + ( ( index / _filterOutput . getNBcolumns ( ) ) % 2 ) * _filterOutput . getNBpixels ( ) + ( ( index % _filterOutput . getNBcolumns ( ) ) % 2 ) * _filterOutput . getNBpixels ( ) ;
//First line: G R G R
//_colorSampling[index] = 3*index+((index/_filterOutput.getNBcolumns())%2)+((index%_filterOutput.getNBcolumns()+1)%2);
}
_pR = _pB = 0.25 ;
_pG = 0.5 ;
break ;
default :
# ifdef RETINACOLORDEBUG
std : : cerr < < " RetinaColor::No or wrong color sampling method, skeeping " < < std : : endl ;
# endif
return ;
break ; //.. not useful, yes
}
// feeling the mosaic buffer:
_RGBmosaic = 0 ;
for ( unsigned int index = 0 ; index < _filterOutput . getNBpixels ( ) ; + + index )
// the RGB _RGBmosaic buffer contains 1 where the pixel corresponds to a sampled color
_RGBmosaic [ _colorSampling [ index ] ] = 1.0 ;
// computing photoreceptors local density
_spatiotemporalLPfilter ( & _RGBmosaic [ 0 ] , & _colorLocalDensity [ 0 ] ) ;
_spatiotemporalLPfilter ( & _RGBmosaic [ 0 ] + _filterOutput . getNBpixels ( ) , & _colorLocalDensity [ 0 ] + _filterOutput . getNBpixels ( ) ) ;
_spatiotemporalLPfilter ( & _RGBmosaic [ 0 ] + _filterOutput . getDoubleNBpixels ( ) , & _colorLocalDensity [ 0 ] + _filterOutput . getDoubleNBpixels ( ) ) ;
unsigned int maxNBpixels = 3 * _filterOutput . getNBpixels ( ) ;
2011-08-21 13:01:53 +02:00
register float * colorLocalDensityPTR = & _colorLocalDensity [ 0 ] ;
2011-08-11 22:42:08 +02:00
for ( unsigned int i = 0 ; i < maxNBpixels ; + + i , + + colorLocalDensityPTR )
* colorLocalDensityPTR = 1.0 / * colorLocalDensityPTR ;
# ifdef RETINACOLORDEBUG
std : : cout < < " INIT _colorLocalDensity max, min: " < < _colorLocalDensity . max ( ) < < " , " < < _colorLocalDensity . min ( ) < < std : : endl ;
# endif
// end of the init step
_objectInit = true ;
}
// public functions
2011-08-21 13:01:53 +02:00
void RetinaColor : : runColorDemultiplexing ( const std : : valarray < float > & multiplexedColorFrame , const bool adaptiveFiltering , const float maxInputValue )
2011-08-11 22:42:08 +02:00
{
// demultiplex the grey frame to RGB frame
// -> first set demultiplexed frame to 0
_demultiplexedTempBuffer = 0 ;
// -> demultiplex process
register unsigned int * colorSamplingPRT = & _colorSampling [ 0 ] ;
2011-08-21 13:01:53 +02:00
register const float * multiplexedColorFramePTR = get_data ( multiplexedColorFrame ) ;
2011-08-11 22:42:08 +02:00
for ( unsigned int indexa = 0 ; indexa < _filterOutput . getNBpixels ( ) ; + + indexa )
_demultiplexedTempBuffer [ * ( colorSamplingPRT + + ) ] = * ( multiplexedColorFramePTR + + ) ;
// interpolate the demultiplexed frame depending on the color sampling method
if ( ! adaptiveFiltering )
_interpolateImageDemultiplexedImage ( & _demultiplexedTempBuffer [ 0 ] ) ;
// low pass filtering the demultiplexed frame
_spatiotemporalLPfilter ( & _demultiplexedTempBuffer [ 0 ] , & _chrominance [ 0 ] ) ;
_spatiotemporalLPfilter ( & _demultiplexedTempBuffer [ 0 ] + _filterOutput . getNBpixels ( ) , & _chrominance [ 0 ] + _filterOutput . getNBpixels ( ) ) ;
_spatiotemporalLPfilter ( & _demultiplexedTempBuffer [ 0 ] + _filterOutput . getDoubleNBpixels ( ) , & _chrominance [ 0 ] + _filterOutput . getDoubleNBpixels ( ) ) ;
/*if (_samplingMethod=BAYER)
{
_applyRIFfilter ( _chrominance , _chrominance ) ;
_applyRIFfilter ( _chrominance + _filterOutput . getNBpixels ( ) , _chrominance + _filterOutput . getNBpixels ( ) ) ;
_applyRIFfilter ( _chrominance + _filterOutput . getDoubleNBpixels ( ) , _chrominance + _filterOutput . getDoubleNBpixels ( ) ) ;
} */
// normalize by the photoreceptors local density and retrieve the local luminance
2011-08-21 13:01:53 +02:00
register float * chrominancePTR = & _chrominance [ 0 ] ;
register float * colorLocalDensityPTR = & _colorLocalDensity [ 0 ] ;
register float * luminance = & ( * _luminance ) [ 0 ] ;
2011-08-11 22:42:08 +02:00
if ( ! adaptiveFiltering ) // compute the gradient on the luminance
{
if ( _samplingMethod = = RETINA_COLOR_RANDOM )
for ( unsigned int indexc = 0 ; indexc < _filterOutput . getNBpixels ( ) ; + + indexc , + + chrominancePTR , + + colorLocalDensityPTR , + + luminance )
{
// normalize by photoreceptors density
2011-08-21 13:01:53 +02:00
float Cr = * ( chrominancePTR ) * _colorLocalDensity [ indexc ] ;
float Cg = * ( chrominancePTR + _filterOutput . getNBpixels ( ) ) * _colorLocalDensity [ indexc + _filterOutput . getNBpixels ( ) ] ;
float Cb = * ( chrominancePTR + _filterOutput . getDoubleNBpixels ( ) ) * _colorLocalDensity [ indexc + _filterOutput . getDoubleNBpixels ( ) ] ;
2011-08-11 22:42:08 +02:00
* luminance = ( Cr + Cg + Cb ) * _pG ;
* ( chrominancePTR ) = Cr - * luminance ;
* ( chrominancePTR + _filterOutput . getNBpixels ( ) ) = Cg - * luminance ;
* ( chrominancePTR + _filterOutput . getDoubleNBpixels ( ) ) = Cb - * luminance ;
}
else
for ( unsigned int indexc = 0 ; indexc < _filterOutput . getNBpixels ( ) ; + + indexc , + + chrominancePTR , + + colorLocalDensityPTR , + + luminance )
{
2011-08-21 13:01:53 +02:00
float Cr = * ( chrominancePTR ) ;
float Cg = * ( chrominancePTR + _filterOutput . getNBpixels ( ) ) ;
float Cb = * ( chrominancePTR + _filterOutput . getDoubleNBpixels ( ) ) ;
2011-08-11 22:42:08 +02:00
* luminance = _pR * Cr + _pG * Cg + _pB * Cb ;
* ( chrominancePTR ) = Cr - * luminance ;
* ( chrominancePTR + _filterOutput . getNBpixels ( ) ) = Cg - * luminance ;
* ( chrominancePTR + _filterOutput . getDoubleNBpixels ( ) ) = Cb - * luminance ;
}
// in order to get the color image, each colored map needs to be added the luminance
// -> to do so, compute: multiplexedColorFrame - remultiplexed chrominances
runColorMultiplexing ( _chrominance , _tempMultiplexedFrame ) ;
//lum = 1/3((f*(ImR))/(f*mR) + (f*(ImG))/(f*mG) + (f*(ImB))/(f*mB));
2011-08-21 13:01:53 +02:00
float * luminancePTR = & ( * _luminance ) [ 0 ] ;
2011-08-11 22:42:08 +02:00
chrominancePTR = & _chrominance [ 0 ] ;
2011-08-21 13:01:53 +02:00
float * demultiplexedColorFramePTR = & _demultiplexedColorFrame [ 0 ] ;
2011-08-11 22:42:08 +02:00
for ( unsigned int indexp = 0 ; indexp < _filterOutput . getNBpixels ( ) ; + + indexp , + + luminancePTR , + + chrominancePTR , + + demultiplexedColorFramePTR )
{
* luminancePTR = ( multiplexedColorFrame [ indexp ] - _tempMultiplexedFrame [ indexp ] ) ;
* ( demultiplexedColorFramePTR ) = * ( chrominancePTR ) + * luminancePTR ;
* ( demultiplexedColorFramePTR + _filterOutput . getNBpixels ( ) ) = * ( chrominancePTR + _filterOutput . getNBpixels ( ) ) + * luminancePTR ;
* ( demultiplexedColorFramePTR + _filterOutput . getDoubleNBpixels ( ) ) = * ( chrominancePTR + _filterOutput . getDoubleNBpixels ( ) ) + * luminancePTR ;
}
} else
{
2011-08-21 13:01:53 +02:00
register const float * multiplexedColorFramePTR = get_data ( multiplexedColorFrame ) ;
2011-08-11 22:42:08 +02:00
for ( unsigned int indexc = 0 ; indexc < _filterOutput . getNBpixels ( ) ; + + indexc , + + chrominancePTR , + + colorLocalDensityPTR , + + luminance , + + multiplexedColorFramePTR )
{
// normalize by photoreceptors density
2011-08-21 13:01:53 +02:00
float Cr = * ( chrominancePTR ) * _colorLocalDensity [ indexc ] ;
float Cg = * ( chrominancePTR + _filterOutput . getNBpixels ( ) ) * _colorLocalDensity [ indexc + _filterOutput . getNBpixels ( ) ] ;
float Cb = * ( chrominancePTR + _filterOutput . getDoubleNBpixels ( ) ) * _colorLocalDensity [ indexc + _filterOutput . getDoubleNBpixels ( ) ] ;
2011-08-11 22:42:08 +02:00
* luminance = ( Cr + Cg + Cb ) * _pG ;
_demultiplexedTempBuffer [ _colorSampling [ indexc ] ] = * multiplexedColorFramePTR - * luminance ;
}
// compute the gradient of the luminance
_computeGradient ( & ( * _luminance ) [ 0 ] ) ;
// adaptively filter the submosaics to get the adaptive densities, here the buffer _chrominance is used as a temp buffer
_adaptiveSpatialLPfilter ( & _RGBmosaic [ 0 ] , & _chrominance [ 0 ] ) ;
_adaptiveSpatialLPfilter ( & _RGBmosaic [ 0 ] + _filterOutput . getNBpixels ( ) , & _chrominance [ 0 ] + _filterOutput . getNBpixels ( ) ) ;
_adaptiveSpatialLPfilter ( & _RGBmosaic [ 0 ] + _filterOutput . getDoubleNBpixels ( ) , & _chrominance [ 0 ] + _filterOutput . getDoubleNBpixels ( ) ) ;
_adaptiveSpatialLPfilter ( & _demultiplexedTempBuffer [ 0 ] , & _demultiplexedColorFrame [ 0 ] ) ;
_adaptiveSpatialLPfilter ( & _demultiplexedTempBuffer [ 0 ] + _filterOutput . getNBpixels ( ) , & _demultiplexedColorFrame [ 0 ] + _filterOutput . getNBpixels ( ) ) ;
_adaptiveSpatialLPfilter ( & _demultiplexedTempBuffer [ 0 ] + _filterOutput . getDoubleNBpixels ( ) , & _demultiplexedColorFrame [ 0 ] + _filterOutput . getDoubleNBpixels ( ) ) ;
for ( unsigned int index = 0 ; index < _filterOutput . getNBpixels ( ) * 3 ; + + index ) // cette boucle pourrait <20> tre supprimee en passant la densit<69> <20> la fonction de filtrage
_demultiplexedColorFrame [ index ] / = _chrominance [ index ] ;
// compute and substract the residual luminance
for ( unsigned int index = 0 ; index < _filterOutput . getNBpixels ( ) ; + + index )
{
2011-08-21 13:01:53 +02:00
float residu = _pR * _demultiplexedColorFrame [ index ] + _pG * _demultiplexedColorFrame [ index + _filterOutput . getNBpixels ( ) ] + _pB * _demultiplexedColorFrame [ index + _filterOutput . getDoubleNBpixels ( ) ] ;
2011-08-11 22:42:08 +02:00
_demultiplexedColorFrame [ index ] = _demultiplexedColorFrame [ index ] - residu ;
_demultiplexedColorFrame [ index + _filterOutput . getNBpixels ( ) ] = _demultiplexedColorFrame [ index + _filterOutput . getNBpixels ( ) ] - residu ;
_demultiplexedColorFrame [ index + _filterOutput . getDoubleNBpixels ( ) ] = _demultiplexedColorFrame [ index + _filterOutput . getDoubleNBpixels ( ) ] - residu ;
}
// multiplex the obtained chrominance
runColorMultiplexing ( _demultiplexedColorFrame , _tempMultiplexedFrame ) ;
_demultiplexedTempBuffer = 0 ;
// get the luminance, et and add it to each chrominance
for ( unsigned int index = 0 ; index < _filterOutput . getNBpixels ( ) ; + + index )
{
( * _luminance ) [ index ] = multiplexedColorFrame [ index ] - _tempMultiplexedFrame [ index ] ;
_demultiplexedTempBuffer [ _colorSampling [ index ] ] = _demultiplexedColorFrame [ _colorSampling [ index ] ] ; //multiplexedColorFrame[index] - (*_luminance)[index];
}
_spatiotemporalLPfilter ( & _demultiplexedTempBuffer [ 0 ] , & _demultiplexedTempBuffer [ 0 ] ) ;
_spatiotemporalLPfilter ( & _demultiplexedTempBuffer [ 0 ] + _filterOutput . getNBpixels ( ) , & _demultiplexedTempBuffer [ 0 ] + _filterOutput . getNBpixels ( ) ) ;
_spatiotemporalLPfilter ( & _demultiplexedTempBuffer [ 0 ] + _filterOutput . getDoubleNBpixels ( ) , & _demultiplexedTempBuffer [ 0 ] + _filterOutput . getDoubleNBpixels ( ) ) ;
// get the luminance and add it to each chrominance
for ( unsigned int index = 0 ; index < _filterOutput . getNBpixels ( ) ; + + index )
{
_demultiplexedColorFrame [ index ] = _demultiplexedTempBuffer [ index ] * _colorLocalDensity [ index ] + ( * _luminance ) [ index ] ;
_demultiplexedColorFrame [ index + _filterOutput . getNBpixels ( ) ] = _demultiplexedTempBuffer [ index + _filterOutput . getNBpixels ( ) ] * _colorLocalDensity [ index + _filterOutput . getNBpixels ( ) ] + ( * _luminance ) [ index ] ;
_demultiplexedColorFrame [ index + _filterOutput . getDoubleNBpixels ( ) ] = _demultiplexedTempBuffer [ index + _filterOutput . getDoubleNBpixels ( ) ] * _colorLocalDensity [ index + _filterOutput . getDoubleNBpixels ( ) ] + ( * _luminance ) [ index ] ;
}
}
// eliminate saturated colors by simple clipping values to the input range
clipRGBOutput_0_maxInputValue ( NULL , maxInputValue ) ;
/* transfert image gradient in order to check validity
2011-08-21 13:01:53 +02:00
memcpy ( ( * _luminance ) , _imageGradient , sizeof ( float ) * _filterOutput . getNBpixels ( ) ) ;
memcpy ( _demultiplexedColorFrame , _imageGradient + _filterOutput . getNBpixels ( ) , sizeof ( float ) * _filterOutput . getNBpixels ( ) ) ;
memcpy ( _demultiplexedColorFrame + _filterOutput . getNBpixels ( ) , _imageGradient + _filterOutput . getNBpixels ( ) , sizeof ( float ) * _filterOutput . getNBpixels ( ) ) ;
memcpy ( _demultiplexedColorFrame + 2 * _filterOutput . getNBpixels ( ) , _imageGradient + _filterOutput . getNBpixels ( ) , sizeof ( float ) * _filterOutput . getNBpixels ( ) ) ;
2011-08-11 22:42:08 +02:00
*/
if ( _saturateColors )
{
2011-08-21 13:01:53 +02:00
TemplateBuffer < float > : : normalizeGrayOutputCentredSigmoide ( 128 , _colorSaturationValue , maxInputValue , & _demultiplexedColorFrame [ 0 ] , & _demultiplexedColorFrame [ 0 ] , _filterOutput . getNBpixels ( ) ) ;
TemplateBuffer < float > : : normalizeGrayOutputCentredSigmoide ( 128 , _colorSaturationValue , maxInputValue , & _demultiplexedColorFrame [ 0 ] + _filterOutput . getNBpixels ( ) , & _demultiplexedColorFrame [ 0 ] + _filterOutput . getNBpixels ( ) , _filterOutput . getNBpixels ( ) ) ;
TemplateBuffer < float > : : normalizeGrayOutputCentredSigmoide ( 128 , _colorSaturationValue , maxInputValue , & _demultiplexedColorFrame [ 0 ] + _filterOutput . getNBpixels ( ) * 2 , & _demultiplexedColorFrame [ 0 ] + _filterOutput . getNBpixels ( ) * 2 , _filterOutput . getNBpixels ( ) ) ;
2011-08-11 22:42:08 +02:00
}
}
// color multiplexing: input frame size=_NBrows*_filterOutput.getNBcolumns()*3, multiplexedFrame output size=_NBrows*_filterOutput.getNBcolumns()
2011-08-21 13:01:53 +02:00
void RetinaColor : : runColorMultiplexing ( const std : : valarray < float > & demultiplexedInputFrame , std : : valarray < float > & multiplexedFrame )
2011-08-11 22:42:08 +02:00
{
// multiply each color layer by its bayer mask
register unsigned int * colorSamplingPTR = & _colorSampling [ 0 ] ;
2011-08-21 13:01:53 +02:00
register float * multiplexedFramePTR = & multiplexedFrame [ 0 ] ;
2011-08-11 22:42:08 +02:00
for ( unsigned int indexp = 0 ; indexp < _filterOutput . getNBpixels ( ) ; + + indexp )
* ( multiplexedFramePTR + + ) = demultiplexedInputFrame [ * ( colorSamplingPTR + + ) ] ;
}
2011-08-21 13:01:53 +02:00
void RetinaColor : : normalizeRGBOutput_0_maxOutputValue ( const float maxOutputValue )
2011-08-11 22:42:08 +02:00
{
//normalizeGrayOutputCentredSigmoide(0.0, 2, _chrominance);
2011-08-21 13:01:53 +02:00
TemplateBuffer < float > : : normalizeGrayOutput_0_maxOutputValue ( & _demultiplexedColorFrame [ 0 ] , 3 * _filterOutput . getNBpixels ( ) , maxOutputValue ) ;
2011-08-11 22:42:08 +02:00
//normalizeGrayOutputCentredSigmoide(0.0, 2, _chrominance+_filterOutput.getNBpixels());
//normalizeGrayOutput_0_maxOutputValue(_demultiplexedColorFrame+_filterOutput.getNBpixels(), _filterOutput.getNBpixels(), maxOutputValue);
//normalizeGrayOutputCentredSigmoide(0.0, 2, _chrominance+2*_filterOutput.getNBpixels());
//normalizeGrayOutput_0_maxOutputValue(_demultiplexedColorFrame+_filterOutput.getDoubleNBpixels(), _filterOutput.getNBpixels(), maxOutputValue);
2011-08-21 13:01:53 +02:00
TemplateBuffer < float > : : normalizeGrayOutput_0_maxOutputValue ( & ( * _luminance ) [ 0 ] , _filterOutput . getNBpixels ( ) , maxOutputValue ) ;
2011-08-11 22:42:08 +02:00
}
/// normalize output between 0 and maxOutputValue;
2011-08-21 13:01:53 +02:00
void RetinaColor : : clipRGBOutput_0_maxInputValue ( float * inputOutputBuffer , const float maxInputValue )
2011-08-11 22:42:08 +02:00
{
//std::cout<<"RetinaColor::normalizing RGB frame..."<<std::endl;
// if outputBuffer unsassigned, the rewrite the buffer
if ( inputOutputBuffer = = NULL )
inputOutputBuffer = & _demultiplexedColorFrame [ 0 ] ;
2011-08-21 13:01:53 +02:00
register float * inputOutputBufferPTR = inputOutputBuffer ;
2011-08-11 22:42:08 +02:00
for ( register unsigned int jf = 0 ; jf < _filterOutput . getNBpixels ( ) * 3 ; + + jf , + + inputOutputBufferPTR )
{
if ( * inputOutputBufferPTR > maxInputValue )
* inputOutputBufferPTR = maxInputValue ;
else if ( * inputOutputBufferPTR < 0 )
* inputOutputBufferPTR = 0 ;
}
//std::cout<<"RetinaColor::...normalizing RGB frame OK"<<std::endl;
}
2011-08-21 13:01:53 +02:00
void RetinaColor : : _interpolateImageDemultiplexedImage ( float * inputOutputBuffer )
2011-08-11 22:42:08 +02:00
{
switch ( _samplingMethod )
{
case RETINA_COLOR_RANDOM :
return ; // no need to interpolate
break ;
case RETINA_COLOR_DIAGONAL :
_interpolateSingleChannelImage111 ( inputOutputBuffer ) ;
break ;
case RETINA_COLOR_BAYER : // default sets bayer sampling
_interpolateBayerRGBchannels ( inputOutputBuffer ) ;
break ;
default :
std : : cerr < < " RetinaColor::No or wrong color sampling method, skeeping " < < std : : endl ;
return ;
break ; //.. not useful, yes
}
}
2011-08-21 13:01:53 +02:00
void RetinaColor : : _interpolateSingleChannelImage111 ( float * inputOutputBuffer )
2011-08-11 22:42:08 +02:00
{
for ( unsigned int indexr = 0 ; indexr < _filterOutput . getNBrows ( ) ; + + indexr )
{
for ( unsigned int indexc = 1 ; indexc < _filterOutput . getNBcolumns ( ) - 1 ; + + indexc )
{
unsigned int index = indexc + indexr * _filterOutput . getNBcolumns ( ) ;
inputOutputBuffer [ index ] = ( inputOutputBuffer [ index - 1 ] + inputOutputBuffer [ index ] + inputOutputBuffer [ index + 1 ] ) / 3.0 ;
}
}
for ( unsigned int indexc = 0 ; indexc < _filterOutput . getNBcolumns ( ) ; + + indexc )
{
for ( unsigned int indexr = 1 ; indexr < _filterOutput . getNBrows ( ) - 1 ; + + indexr )
{
unsigned int index = indexc + indexr * _filterOutput . getNBcolumns ( ) ;
inputOutputBuffer [ index ] = ( inputOutputBuffer [ index - _filterOutput . getNBcolumns ( ) ] + inputOutputBuffer [ index ] + inputOutputBuffer [ index + _filterOutput . getNBcolumns ( ) ] ) / 3.0 ;
}
}
}
2011-08-21 13:01:53 +02:00
void RetinaColor : : _interpolateBayerRGBchannels ( float * inputOutputBuffer )
2011-08-11 22:42:08 +02:00
{
for ( unsigned int indexr = 0 ; indexr < _filterOutput . getNBrows ( ) - 1 ; indexr + = 2 )
{
for ( unsigned int indexc = 1 ; indexc < _filterOutput . getNBcolumns ( ) - 1 ; indexc + = 2 )
{
unsigned int indexR = indexc + indexr * _filterOutput . getNBcolumns ( ) ;
unsigned int indexB = _filterOutput . getDoubleNBpixels ( ) + indexc + 1 + ( indexr + 1 ) * _filterOutput . getNBcolumns ( ) ;
inputOutputBuffer [ indexR ] = ( inputOutputBuffer [ indexR - 1 ] + inputOutputBuffer [ indexR + 1 ] ) / 2.0 ;
inputOutputBuffer [ indexB ] = ( inputOutputBuffer [ indexB - 1 ] + inputOutputBuffer [ indexB + 1 ] ) / 2.0 ;
}
}
for ( unsigned int indexr = 1 ; indexr < _filterOutput . getNBrows ( ) - 1 ; indexr + = 2 )
{
for ( unsigned int indexc = 0 ; indexc < _filterOutput . getNBcolumns ( ) ; + + indexc )
{
unsigned int indexR = indexc + indexr * _filterOutput . getNBcolumns ( ) ;
unsigned int indexB = _filterOutput . getDoubleNBpixels ( ) + indexc + 1 + ( indexr + 1 ) * _filterOutput . getNBcolumns ( ) ;
inputOutputBuffer [ indexR ] = ( inputOutputBuffer [ indexR - _filterOutput . getNBcolumns ( ) ] + inputOutputBuffer [ indexR + _filterOutput . getNBcolumns ( ) ] ) / 2.0 ;
inputOutputBuffer [ indexB ] = ( inputOutputBuffer [ indexB - _filterOutput . getNBcolumns ( ) ] + inputOutputBuffer [ indexB + _filterOutput . getNBcolumns ( ) ] ) / 2.0 ;
}
}
for ( unsigned int indexr = 1 ; indexr < _filterOutput . getNBrows ( ) - 1 ; + + indexr )
for ( unsigned int indexc = 0 ; indexc < _filterOutput . getNBcolumns ( ) ; indexc + = 2 )
{
unsigned int indexG = _filterOutput . getNBpixels ( ) + indexc + ( indexr ) * _filterOutput . getNBcolumns ( ) + indexr % 2 ;
inputOutputBuffer [ indexG ] = ( inputOutputBuffer [ indexG - 1 ] + inputOutputBuffer [ indexG + 1 ] + inputOutputBuffer [ indexG - _filterOutput . getNBcolumns ( ) ] + inputOutputBuffer [ indexG + _filterOutput . getNBcolumns ( ) ] ) * 0.25 ;
}
}
2011-08-21 13:01:53 +02:00
void RetinaColor : : _applyRIFfilter ( const float * sourceBuffer , float * destinationBuffer )
2011-08-11 22:42:08 +02:00
{
for ( unsigned int indexr = 1 ; indexr < _filterOutput . getNBrows ( ) - 1 ; + + indexr )
{
for ( unsigned int indexc = 1 ; indexc < _filterOutput . getNBcolumns ( ) - 1 ; + + indexc )
{
unsigned int index = indexc + indexr * _filterOutput . getNBcolumns ( ) ;
_tempMultiplexedFrame [ index ] = ( 4.0 * sourceBuffer [ index ] + sourceBuffer [ index - 1 - _filterOutput . getNBcolumns ( ) ] + sourceBuffer [ index - 1 + _filterOutput . getNBcolumns ( ) ] + sourceBuffer [ index + 1 - _filterOutput . getNBcolumns ( ) ] + sourceBuffer [ index + 1 + _filterOutput . getNBcolumns ( ) ] ) * 0.125 ;
}
}
2011-08-21 13:01:53 +02:00
memcpy ( destinationBuffer , & _tempMultiplexedFrame [ 0 ] , sizeof ( float ) * _filterOutput . getNBpixels ( ) ) ;
2011-08-11 22:42:08 +02:00
}
2011-08-21 13:01:53 +02:00
void RetinaColor : : _getNormalizedContoursImage ( const float * inputFrame , float * outputFrame )
2011-08-11 22:42:08 +02:00
{
2011-08-21 13:01:53 +02:00
float maxValue = 0 ;
float normalisationFactor = 1.0 / 3.0 ;
2011-08-11 22:42:08 +02:00
for ( unsigned int indexr = 1 ; indexr < _filterOutput . getNBrows ( ) - 1 ; + + indexr )
{
for ( unsigned int indexc = 1 ; indexc < _filterOutput . getNBcolumns ( ) - 1 ; + + indexc )
{
unsigned int index = indexc + indexr * _filterOutput . getNBcolumns ( ) ;
outputFrame [ index ] = normalisationFactor * fabs ( 8.0 * inputFrame [ index ] - inputFrame [ index - 1 ] - inputFrame [ index + 1 ] - inputFrame [ index - _filterOutput . getNBcolumns ( ) ] - inputFrame [ index + _filterOutput . getNBcolumns ( ) ] - inputFrame [ index - 1 - _filterOutput . getNBcolumns ( ) ] - inputFrame [ index - 1 + _filterOutput . getNBcolumns ( ) ] - inputFrame [ index + 1 - _filterOutput . getNBcolumns ( ) ] - inputFrame [ index + 1 + _filterOutput . getNBcolumns ( ) ] ) ;
if ( outputFrame [ index ] > maxValue )
maxValue = outputFrame [ index ] ;
}
}
normalisationFactor = 1.0 / maxValue ;
// normalisation [0, 1]
for ( unsigned int indexp = 1 ; indexp < _filterOutput . getNBrows ( ) - 1 ; + + indexp )
outputFrame [ indexp ] = outputFrame [ indexp ] * normalisationFactor ;
}
//////////////////////////////////////////////////////////
// ADAPTIVE BASIC RETINA FILTER
//////////////////////////////////////////////////////////
// run LP filter for a new frame input and save result at a specific output adress
2011-08-21 13:01:53 +02:00
void RetinaColor : : _adaptiveSpatialLPfilter ( const float * inputFrame , float * outputFrame )
2011-08-11 22:42:08 +02:00
{
/**********/
_gain = ( 1 - 0.57 ) * ( 1 - 0.57 ) * ( 1 - 0.06 ) * ( 1 - 0.06 ) ;
// launch the serie of 1D directional filters in order to compute the 2D low pass filter
_adaptiveHorizontalCausalFilter_addInput ( inputFrame , outputFrame , 0 , _filterOutput . getNBrows ( ) ) ;
_adaptiveHorizontalAnticausalFilter ( outputFrame , 0 , _filterOutput . getNBrows ( ) ) ;
_adaptiveVerticalCausalFilter ( outputFrame , 0 , _filterOutput . getNBcolumns ( ) ) ;
_adaptiveVerticalAnticausalFilter_multGain ( outputFrame , 0 , _filterOutput . getNBcolumns ( ) ) ;
}
// horizontal causal filter which adds the input inside
2011-08-21 13:01:53 +02:00
void RetinaColor : : _adaptiveHorizontalCausalFilter_addInput ( const float * inputFrame , float * outputFrame , unsigned int IDrowStart , unsigned int IDrowEnd )
2011-08-11 22:42:08 +02:00
{
2011-08-21 13:01:53 +02:00
register float * outputPTR = outputFrame + IDrowStart * _filterOutput . getNBcolumns ( ) ;
register const float * inputPTR = inputFrame + IDrowStart * _filterOutput . getNBcolumns ( ) ;
register float * imageGradientPTR = & _imageGradient [ 0 ] + IDrowStart * _filterOutput . getNBcolumns ( ) ;
2011-08-11 22:42:08 +02:00
for ( unsigned int IDrow = IDrowStart ; IDrow < IDrowEnd ; + + IDrow )
{
2011-08-21 13:01:53 +02:00
register float result = 0 ;
2011-08-11 22:42:08 +02:00
for ( unsigned int index = 0 ; index < _filterOutput . getNBcolumns ( ) ; + + index )
{
//std::cout<<(*imageGradientPTR)<<" ";
result = * ( inputPTR + + ) + ( * imageGradientPTR ) * result ;
* ( outputPTR + + ) = result ;
+ + imageGradientPTR ;
}
// std::cout<<" "<<std::endl;
}
}
// horizontal anticausal filter (basic way, no add on)
2011-08-21 13:01:53 +02:00
void RetinaColor : : _adaptiveHorizontalAnticausalFilter ( float * outputFrame , unsigned int IDrowStart , unsigned int IDrowEnd )
2011-08-11 22:42:08 +02:00
{
2011-08-21 13:01:53 +02:00
register float * outputPTR = outputFrame + IDrowEnd * ( _filterOutput . getNBcolumns ( ) ) - 1 ;
register float * imageGradientPTR = & _imageGradient [ 0 ] + IDrowEnd * ( _filterOutput . getNBcolumns ( ) ) - 1 ;
2011-08-11 22:42:08 +02:00
for ( unsigned int IDrow = IDrowStart ; IDrow < IDrowEnd ; + + IDrow )
{
2011-08-21 13:01:53 +02:00
register float result = 0 ;
2011-08-11 22:42:08 +02:00
for ( unsigned int index = 0 ; index < _filterOutput . getNBcolumns ( ) ; + + index )
{
result = * ( outputPTR ) + ( * imageGradientPTR ) * result ;
* ( outputPTR - - ) = result ;
- - imageGradientPTR ;
}
}
}
// vertical anticausal filter
2011-08-21 13:01:53 +02:00
void RetinaColor : : _adaptiveVerticalCausalFilter ( float * outputFrame , unsigned int IDcolumnStart , unsigned int IDcolumnEnd )
2011-08-11 22:42:08 +02:00
{
for ( unsigned int IDcolumn = IDcolumnStart ; IDcolumn < IDcolumnEnd ; + + IDcolumn )
{
2011-08-21 13:01:53 +02:00
register float result = 0 ;
register float * outputPTR = outputFrame + IDcolumn ;
register float * imageGradientPTR = & _imageGradient [ 0 ] + IDcolumn ;
2011-08-11 22:42:08 +02:00
for ( unsigned int index = 0 ; index < _filterOutput . getNBrows ( ) ; + + index )
{
result = * ( outputPTR ) + ( * ( imageGradientPTR + _filterOutput . getNBpixels ( ) ) ) * result ;
* ( outputPTR ) = result ;
outputPTR + = _filterOutput . getNBcolumns ( ) ;
imageGradientPTR + = _filterOutput . getNBcolumns ( ) ;
}
}
}
// vertical anticausal filter which multiplies the output by _gain
2011-08-21 13:01:53 +02:00
void RetinaColor : : _adaptiveVerticalAnticausalFilter_multGain ( float * outputFrame , unsigned int IDcolumnStart , unsigned int IDcolumnEnd )
2011-08-11 22:42:08 +02:00
{
2011-08-21 13:01:53 +02:00
float * outputOffset = outputFrame + _filterOutput . getNBpixels ( ) - _filterOutput . getNBcolumns ( ) ;
float * gradOffset = & _imageGradient [ 0 ] + _filterOutput . getNBpixels ( ) - _filterOutput . getNBcolumns ( ) ;
2011-08-11 22:42:08 +02:00
for ( unsigned int IDcolumn = IDcolumnStart ; IDcolumn < IDcolumnEnd ; + + IDcolumn )
{
2011-08-21 13:01:53 +02:00
register float result = 0 ;
register float * outputPTR = outputOffset + IDcolumn ;
register float * imageGradientPTR = gradOffset + IDcolumn ;
2011-08-11 22:42:08 +02:00
for ( unsigned int index = 0 ; index < _filterOutput . getNBrows ( ) ; + + index )
{
result = * ( outputPTR ) + ( * ( imageGradientPTR + _filterOutput . getNBpixels ( ) ) ) * result ;
* ( outputPTR ) = _gain * result ;
outputPTR - = _filterOutput . getNBcolumns ( ) ;
imageGradientPTR - = _filterOutput . getNBcolumns ( ) ;
}
}
}
///////////////////////////
2011-08-21 13:01:53 +02:00
void RetinaColor : : _computeGradient ( const float * luminance )
2011-08-11 22:42:08 +02:00
{
for ( unsigned int idLine = 2 ; idLine < _filterOutput . getNBrows ( ) - 2 ; + + idLine )
{
for ( unsigned int idColumn = 2 ; idColumn < _filterOutput . getNBcolumns ( ) - 2 ; + + idColumn )
{
const unsigned int pixelIndex = idColumn + _filterOutput . getNBcolumns ( ) * idLine ;
// horizontal and vertical local gradients
2011-08-21 13:01:53 +02:00
const float verticalGrad = fabs ( luminance [ pixelIndex + _filterOutput . getNBcolumns ( ) ] - luminance [ pixelIndex - _filterOutput . getNBcolumns ( ) ] ) ;
const float horizontalGrad = fabs ( luminance [ pixelIndex + 1 ] - luminance [ pixelIndex - 1 ] ) ;
2011-08-11 22:42:08 +02:00
// neighborhood horizontal and vertical gradients
2011-08-21 13:01:53 +02:00
const float verticalGrad_p = fabs ( luminance [ pixelIndex ] - luminance [ pixelIndex - 2 * _filterOutput . getNBcolumns ( ) ] ) ;
const float horizontalGrad_p = fabs ( luminance [ pixelIndex ] - luminance [ pixelIndex - 2 ] ) ;
const float verticalGrad_n = fabs ( luminance [ pixelIndex + 2 * _filterOutput . getNBcolumns ( ) ] - luminance [ pixelIndex ] ) ;
const float horizontalGrad_n = fabs ( luminance [ pixelIndex + 2 ] - luminance [ pixelIndex ] ) ;
2011-08-11 22:42:08 +02:00
2011-08-21 13:01:53 +02:00
const float horizontalGradient = 0.5 * horizontalGrad + 0.25 * ( horizontalGrad_p + horizontalGrad_n ) ;
const float verticalGradient = 0.5 * verticalGrad + 0.25 * ( verticalGrad_p + verticalGrad_n ) ;
2011-08-11 22:42:08 +02:00
// compare local gradient means and fill the appropriate filtering coefficient value that will be used in adaptative filters
if ( horizontalGradient < verticalGradient )
{
_imageGradient [ pixelIndex + _filterOutput . getNBpixels ( ) ] = 0.06 ;
_imageGradient [ pixelIndex ] = 0.57 ;
}
else
{
_imageGradient [ pixelIndex + _filterOutput . getNBpixels ( ) ] = 0.57 ;
_imageGradient [ pixelIndex ] = 0.06 ;
}
}
}
}
2011-08-21 13:01:53 +02:00
const bool RetinaColor : : applyKrauskopfLMS2Acr1cr2Transform ( std : : valarray < float > & result )
2011-08-11 22:42:08 +02:00
{
bool processSuccess = true ;
// basic preliminary error check
if ( result . size ( ) ! = _demultiplexedColorFrame . size ( ) )
{
std : : cerr < < " RetinaColor::applyKrauskopfLMS2Acr1cr2Transform: input buffer does not match retina buffer size, conversion aborted " < < std : : endl ;
return false ;
}
// apply transformation
_applyImageColorSpaceConversion ( _demultiplexedColorFrame , result , _LMStoACr1Cr2 ) ;
return processSuccess ;
}
2011-08-21 13:01:53 +02:00
const bool RetinaColor : : applyLMS2LabTransform ( std : : valarray < float > & result )
2011-08-11 22:42:08 +02:00
{
bool processSuccess = true ;
// basic preliminary error check
if ( result . size ( ) ! = _demultiplexedColorFrame . size ( ) )
{
std : : cerr < < " RetinaColor::applyKrauskopfLMS2Acr1cr2Transform: input buffer does not match retina buffer size, conversion aborted " < < std : : endl ;
return false ;
}
// apply transformation
_applyImageColorSpaceConversion ( _demultiplexedColorFrame , result , _LMStoLab ) ;
return processSuccess ;
}
// template function able to perform a custom color space transformation
2011-08-21 13:01:53 +02:00
void RetinaColor : : _applyImageColorSpaceConversion ( const std : : valarray < float > & inputFrameBuffer , std : : valarray < float > & outputFrameBuffer , const float * transformTable )
2011-08-11 22:42:08 +02:00
{
// two step methods in order to allow inputFrame and outputFrame to be the same
2011-08-12 13:28:17 +02:00
unsigned int nbPixels = ( unsigned int ) ( inputFrameBuffer . size ( ) / 3 ) , dbpixels = ( unsigned int ) ( 2 * inputFrameBuffer . size ( ) / 3 ) ;
2011-08-11 22:42:08 +02:00
2011-08-21 13:01:53 +02:00
const float * inputFrame = get_data ( inputFrameBuffer ) ;
float * outputFrame = & outputFrameBuffer [ 0 ] ;
2011-08-11 22:42:08 +02:00
for ( unsigned int dataIndex = 0 ; dataIndex < nbPixels ; + + dataIndex , + + outputFrame , + + inputFrame )
{
// first step, compute each new values
2011-08-21 13:01:53 +02:00
float layer1 = * ( inputFrame ) * * ( transformTable + 0 ) + * ( inputFrame + nbPixels ) * * ( transformTable + 1 ) + * ( inputFrame + dbpixels ) * * ( transformTable + 2 ) ;
float layer2 = * ( inputFrame ) * * ( transformTable + 3 ) + * ( inputFrame + nbPixels ) * * ( transformTable + 4 ) + * ( inputFrame + dbpixels ) * * ( transformTable + 5 ) ;
float layer3 = * ( inputFrame ) * * ( transformTable + 6 ) + * ( inputFrame + nbPixels ) * * ( transformTable + 7 ) + * ( inputFrame + dbpixels ) * * ( transformTable + 8 ) ;
2011-08-11 22:42:08 +02:00
// second, affect the output
* ( outputFrame ) = layer1 ;
* ( outputFrame + nbPixels ) = layer2 ;
* ( outputFrame + dbpixels ) = layer3 ;
}
}
}