/** 
* @file ColorHistogramFeature.cpp
* @brief histogram of oriented gradients ( dalal and triggs )
* @author Erik Rodner
* @date 05/07/2008

*/
#include <iostream>

#include "ColorHistogramFeature.h"
#include "vislearning/cbaselib/FeaturePool.h"

using namespace OBJREC;

using namespace std;
using namespace NICE;


const double epsilon = 10e-8;

/** simple constructor */
ColorHistogramFeature::ColorHistogramFeature( const Config *conf )
{
    window_size_x = conf->gI("ColorHistogramFeature", "window_size_x", 21 );
    window_size_y = conf->gI("ColorHistogramFeature", "window_size_y", 21 );
    scaleStep = conf->gD("ColorHistogramFeature", "scale_step", sqrt(2) );
    numScales = conf->gI("ColorHistogramFeature", "num_scales", 5 );

    int numBinsH = conf->gI("ColorHistogramFeature", "num_bins_h", 4);
    int numBinsS = conf->gI("ColorHistogramFeature", "num_bins_s", 2);
    int numBinsV = conf->gI("ColorHistogramFeature", "num_bins_v", 2);
    numBins = numBinsH*numBinsS*numBinsV;
}

/** simple destructor */
ColorHistogramFeature::~ColorHistogramFeature()
{
}

double ColorHistogramFeature::val( const Example *example ) const
{
    const NICE::MultiChannelImageT<double> & img = 
	example->ce->getDChannel ( CachedExample::D_INTEGRALCOLOR );
    int tm_xsize = img.xsize;
    int tm_ysize = img.ysize;

    int xsize;
    int ysize;
    example->ce->getImageSize ( xsize, ysize );

    int wsx2, wsy2;
    int exwidth = example->width;
    if ( exwidth == 0 ) {
	wsx2 = window_size_x * tm_xsize / (2*xsize);
	wsy2 = window_size_y * tm_ysize / (2*ysize);
    } else {
	int exheight = example->height;
	wsx2 = exwidth * tm_xsize / (2*xsize);
	wsy2 = exheight * tm_ysize / (2*ysize);
    }
	
    int xx, yy;
    xx = ( example->x ) * tm_xsize / xsize;
    yy = ( example->y ) * tm_ysize / ysize;

    assert ( (wsx2 > 0) && (wsy2 > 0) );

    int xtl = xx - wsx2;
    int ytl = yy - wsy2;
    int xrb = xx + wsx2;
    int yrb = yy + wsy2;

#define BOUND(x,min,max) (((x)<(min))?(min):((x)>(max)?(max):(x)))
    xtl = BOUND ( xtl, 0, tm_xsize - 1 );
    ytl = BOUND ( ytl, 0, tm_ysize - 1 );
    xrb = BOUND ( xrb, 0, tm_xsize - 1 );
    yrb = BOUND ( yrb, 0, tm_ysize - 1 );
#undef BOUND

    assert ( bin < (int)img.numChannels );
    assert ( img.data[bin] != NULL );

    long kA = xtl + ytl * tm_xsize;
    long kB = xrb + ytl * tm_xsize;
    long kC = xtl + yrb * tm_xsize;
    long kD = xrb + yrb * tm_xsize;
    double A,B,C,D;
    A = img.data[bin][ kA ];
    B = img.data[bin][ kB ];
    C = img.data[bin][ kC ];
    D = img.data[bin][ kD ];

    double val1 =  (D - B - C + A);
    double sum = val1*val1;
    for ( int b = 0 ; b < (int)img.numChannels ; b++)
    {
	if ( b == bin ) continue;
	A = img.data[b][ kA ];
	B = img.data[b][ kB ];
	C = img.data[b][ kC ];
	D = img.data[b][ kD ];
	double val = ( D - B - C + A );
	sum += val*val;
    }
    sum = sqrt(sum);
    return ( val1 + epsilon ) / ( sum + epsilon );
}

void ColorHistogramFeature::explode ( FeaturePool & featurePool, bool variableWindow ) const
{
    int nScales = (variableWindow ? numScales : 1 );

    for ( int i = 0 ; i < nScales ; i++ )
    {
	int wsy = window_size_y;
	int wsx = window_size_x;
	for ( int _bin = 0 ; _bin < numBins ; _bin++ )
	{
	    ColorHistogramFeature *f = new ColorHistogramFeature();
	    f->window_size_x = wsx;
	    f->window_size_y = wsy;
	    f->bin = _bin;
	    featurePool.addFeature ( f, 1.0 / ( numBins * nScales ) ); 
	}
	wsx = (int) (scaleStep * wsx);
	wsy = (int) (scaleStep * wsy);
    }
}

Feature *ColorHistogramFeature::clone() const
{
    ColorHistogramFeature *f = new ColorHistogramFeature();
    f->window_size_x = window_size_x;
    f->window_size_y = window_size_y;
    f->bin = bin;

    return f;
}

Feature *ColorHistogramFeature::generateFirstParameter () const
{
    return clone();
}

void ColorHistogramFeature::restore (istream & is, int format)
{
    is >> window_size_x;
    is >> window_size_y;
    is >> bin;
}

void ColorHistogramFeature::store (ostream & os, int format) const
{
    os << "ColorHistogramFeature "
       << window_size_x << " "
       << window_size_y << " "
       << bin;
}

void ColorHistogramFeature::clear ()
{
}