#include "decompose.h" #include #include #include #include #define SQRT2PI 2.506628253 #ifdef TURBO_DECOMPOSE int DecomposeHistogram( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int max_dists, double default_sigma, int iterations ) { //Step 1: Find the actual peaks. int i; int peak = 0; for( i = 0; i < bins; i++ ) { float offset = 0; float prev = histogram[(i-1+bins)%bins]; float this = histogram[i]; float next = histogram[(i+1)%bins]; if( prev > this || next > this ) continue; if( prev == this && next == this ) continue; //i is at a peak... float totaldiff = (( this - prev ) + ( this - next )); float porpdiffP = (this-prev)/totaldiff; //close to 0 = closer to this side... 0.5 = in the middle ... 1.0 away. float porpdiffN = (this-next)/totaldiff; if( porpdiffP < porpdiffN ) { //Closer to prev. offset = -(0.5 - porpdiffP); } else { offset = (0.5 - porpdiffN); } out_means[peak] = i + offset; //XXX XXX TODO Examine difference or relationship of "this" and "totaldiff" out_amps[peak] = this * 4; //powf( totaldiff, .8) * 10;//powf( totaldiff, .5 )*4; // out_sigmas[peak] = default_sigma; peak++; } for( i = peak; i < max_dists; i++ ) { out_means[i] = -1; out_amps[i] = 0; out_sigmas[i] = default_sigma; } return peak; } //Yick: Doesn't match.. I guess it's only for debugging, right? float CalcHistAt( float pt, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists ) { int i; float mark = 0.0; for( i = 0; i < cur_dists; i++ ) { float amp = out_amps[i]; float mean = out_means[i]; float var = out_sigmas[i]; float x = mean - pt; if( x < - bins / 2 ) x += bins; if( x > bins / 2 ) x -= bins; float nrm = amp / (var * SQRT2PI ) * expf( - ( x * x ) / ( 2 * var * var ) ); mark += nrm; } return mark; } #else float AttemptDecomposition( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists ); float CalcHistAt( float pt, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists ); int DecomposeHistogram( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int max_dists, double default_sigma, int iterations ) { //NOTE: The sigma may change depending on all sorts of things, maybe? int sigs = 0; int i; int went_up = 0; float vhist = histogram[bins-1]; for( i = 0; i <= bins; i++ ) { float thishist = histogram[i%bins]; if( thishist > vhist ) { went_up = 1; } else if( went_up) { went_up = 0; out_amps[sigs] = thishist / (default_sigma + 1); out_sigmas[sigs] = default_sigma; out_means[sigs] = i-0.5; sigs++; } vhist = thishist; } if( sigs == 0 ) return 0; int iteration; float errbest = AttemptDecomposition( histogram, bins, out_means, out_amps, out_sigmas, sigs ); int dropped[bins]; for( i = 0; i < bins; i++ ) { dropped[i] = 0; } for( iteration = 0; iteration < iterations; iteration++ ) { if( dropped[iteration%sigs] ) continue; //Tweak with the values until they are closer to what we want. float backup_mean = out_means[iteration%sigs]; float backup_amps = out_amps[iteration%sigs]; float backup_sigmas = out_sigmas[iteration%sigs]; float mute = 20. / (iteration+20.); #define RANDFN ((rand()%2)-0.5)*mute //#define RANDFN ((rand()%10000)-5000.0) / 5000.0 * mute // out_sigmas[iteration%sigs] += RANDFN; out_means[iteration%sigs] += RANDFN; out_amps[iteration%sigs] += RANDFN; float err = AttemptDecomposition( histogram, bins, out_means, out_amps, out_sigmas, sigs ); if( err > errbest ) { out_means[iteration%sigs] = backup_mean; out_amps[iteration%sigs] = backup_amps; out_sigmas[iteration%sigs] = backup_sigmas; } else { if( out_amps[iteration%sigs] < 0.01 ) { dropped[iteration%sigs] = 1; out_amps[iteration%sigs] = 0.0; } errbest = err; } } // printf( "%f / %f = %f\n", origerr, errbest, origerr/errbest ); return sigs; } float CalcHistAt( float pt, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists ) { int i; float mark = 0.0; for( i = 0; i < cur_dists; i++ ) { float amp = out_amps[i]; float mean = out_means[i]; float var = out_sigmas[i]; float x = mean - pt; if( x < - bins / 2 ) x += bins; if( x > bins / 2 ) x -= bins; float nrm = amp / (var * SQRT2PI ) * expf( - ( x * x ) / ( 2 * var * var ) ); mark += nrm; } return mark; } float AttemptDecomposition( float * histogram, int bins, float * out_means, float * out_amps, float * out_sigmas, int cur_dists ) { int i, j; float hist[bins]; memcpy( hist, histogram, sizeof(hist) ); for( i = 0; i < cur_dists; i++ ) { float amp = out_amps[i]; float mean = out_means[i]; float var = out_sigmas[i]; for( j = 0; j < bins; j++ ) { float x = mean - j; if( x < - bins / 2 ) x += bins; if( x > bins / 2 ) x -= bins; float nrm = amp / (var * SQRT2PI ) * expf( - ( x * x ) / ( 2 * var * var ) ); hist[j] -= nrm; } } float remain = 0; for( j = 0; j < bins; j++ ) { remain += hist[j] * hist[j]; } return remain; } #endif