csgo-2018-source/bitmap/floatbitmap_bilateralfilter.cpp

106 lines
2.9 KiB
C++
Raw Permalink Normal View History

2021-07-25 12:11:47 +08:00
//===== 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] );
}
}