106 lines
2.9 KiB
C++
106 lines
2.9 KiB
C++
|
//===== Copyright <20> 1996-2006, Valve Corporation, All rights reserved. ======//
|
|||
|
//
|
|||
|
// Purpose:
|
|||
|
//
|
|||
|
//===========================================================================//
|
|||
|
|
|||
|
#include <tier0/platform.h>
|
|||
|
#include <stdio.h>
|
|||
|
#include <string.h>
|
|||
|
#include <math.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include "bitmap/floatbitmap.h"
|
|||
|
#include <tier2/tier2.h>
|
|||
|
#include "tier0/threadtools.h"
|
|||
|
#include "tier0/progressbar.h"
|
|||
|
|
|||
|
// NOTE: This has to be the last file included!
|
|||
|
#include "tier0/memdbgon.h"
|
|||
|
|
|||
|
|
|||
|
struct TBFCalculationContext
|
|||
|
{
|
|||
|
int min_y, max_y; // range to calculate in this thread
|
|||
|
int thread_number;
|
|||
|
int radius_in_pixels;
|
|||
|
float edge_threshold_value;
|
|||
|
FloatBitMap_t const * orig_bm;
|
|||
|
FloatBitMap_t * dest_bm;
|
|||
|
};
|
|||
|
|
|||
|
static uintp TBFCalculationThreadFN( void *ctx1 )
|
|||
|
{
|
|||
|
TBFCalculationContext * ctx = ( TBFCalculationContext * ) ctx1;
|
|||
|
for( int y = ctx->min_y; y <= ctx->max_y; y++ )
|
|||
|
{
|
|||
|
if ( ctx->thread_number == 0 )
|
|||
|
{
|
|||
|
ReportProgress("Performing bilateral filter",(1+ctx->max_y-ctx->min_y), y - ctx->min_y );
|
|||
|
}
|
|||
|
|
|||
|
for( int x = 0; x < ctx->dest_bm->NumCols(); x++ )
|
|||
|
{
|
|||
|
for( int c = 0;c < 4;c++ )
|
|||
|
{
|
|||
|
float sum_weights = 0;
|
|||
|
float filter_sum = 0;
|
|||
|
float centerp = ctx->orig_bm->Pixel( x, y, 0, c );
|
|||
|
for( int iy =- ctx->radius_in_pixels; iy <= ctx->radius_in_pixels; iy++ )
|
|||
|
{
|
|||
|
for( int ix =- ctx->radius_in_pixels; ix <= ctx->radius_in_pixels; ix++ )
|
|||
|
{
|
|||
|
float this_p = ctx->orig_bm->PixelWrapped( x + ix, y + iy, 0, c );
|
|||
|
|
|||
|
// caluclate the g() term. We use a gaussian
|
|||
|
float exp1 = ( ix * ix + iy * iy ) * ( 1.0 / ( 2.0 * ctx->radius_in_pixels *.033 ));
|
|||
|
float g = exp( - exp1 );
|
|||
|
// calculate the "similarity" term. We use a triangle filter
|
|||
|
float s = 1.0;
|
|||
|
float cdiff = fabs( centerp - this_p );
|
|||
|
s = ( cdiff > ctx->edge_threshold_value )?0:
|
|||
|
FLerp( 1, 0, 0, ctx->edge_threshold_value, cdiff );
|
|||
|
sum_weights += s * g;
|
|||
|
filter_sum += s * g * this_p;
|
|||
|
}
|
|||
|
}
|
|||
|
ctx->dest_bm->Pixel( x, y, 0, c ) = filter_sum / sum_weights;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
void FloatBitMap_t::TileableBilateralFilter( int radius_in_pixels,
|
|||
|
float edge_threshold_value )
|
|||
|
{
|
|||
|
FloatBitMap_t orig( this ); // need a copy for the source
|
|||
|
TBFCalculationContext ctxs[32];
|
|||
|
ctxs[0].radius_in_pixels = radius_in_pixels;
|
|||
|
ctxs[0].edge_threshold_value = edge_threshold_value;
|
|||
|
ctxs[0].orig_bm = & orig;
|
|||
|
ctxs[0].dest_bm = this;
|
|||
|
int nthreads = MIN( 32, GetCPUInformation().m_nPhysicalProcessors );
|
|||
|
ThreadHandle_t waithandles[32];
|
|||
|
int starty = 0;
|
|||
|
int ystep = NumRows() / nthreads;
|
|||
|
|
|||
|
for( int t = 0;t < nthreads;t++ )
|
|||
|
{
|
|||
|
if ( t )
|
|||
|
ctxs[t]= ctxs[0];
|
|||
|
ctxs[t].thread_number = t;
|
|||
|
ctxs[t].min_y = starty;
|
|||
|
if ( t != nthreads - 1 )
|
|||
|
ctxs[t].max_y = MIN( NumRows() - 1, starty + ystep - 1 );
|
|||
|
else
|
|||
|
ctxs[t].max_y = NumRows() - 1;
|
|||
|
waithandles[t]= CreateSimpleThread( TBFCalculationThreadFN, & ctxs[t] );
|
|||
|
starty += ystep;
|
|||
|
}
|
|||
|
for( int t = 0;t < nthreads;t++ )
|
|||
|
{
|
|||
|
ThreadJoin( waithandles[t] );
|
|||
|
}
|
|||
|
}
|
|||
|
|