add fast path to rank filter for uchar images
around 10x faster for 20x20 windows, the same speed for 3x3
This commit is contained in:
parent
22f3b44d1e
commit
3cd774a10c
@ -11,6 +11,7 @@
|
|||||||
- add "seed" param to perlin, worley and gaussnoise
|
- add "seed" param to perlin, worley and gaussnoise
|
||||||
- add vips_source_g_input_stream_new() to load images from a GInputStream
|
- add vips_source_g_input_stream_new() to load images from a GInputStream
|
||||||
- add openslideload_source(), vipsload_source(), vipssave_target()
|
- add openslideload_source(), vipsload_source(), vipssave_target()
|
||||||
|
- add hist path to rank for large windows on uchar images
|
||||||
|
|
||||||
22/12/20 start 8.10.6
|
22/12/20 start 8.10.6
|
||||||
- don't seek on bad file descriptors [kleisauke]
|
- don't seek on bad file descriptors [kleisauke]
|
||||||
|
@ -108,8 +108,8 @@ vips_hist_local_stop( void *vseq, void *a, void *b )
|
|||||||
|
|
||||||
for( i = 0; i < in->Bands; i++ )
|
for( i = 0; i < in->Bands; i++ )
|
||||||
VIPS_FREE( seq->hist[i] );
|
VIPS_FREE( seq->hist[i] );
|
||||||
VIPS_FREE( seq->hist );
|
|
||||||
}
|
}
|
||||||
|
VIPS_FREE( seq->hist );
|
||||||
VIPS_FREE( seq );
|
VIPS_FREE( seq );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
|
@ -26,6 +26,8 @@
|
|||||||
* - redone as a class
|
* - redone as a class
|
||||||
* 12/11/16
|
* 12/11/16
|
||||||
* - oop, allow index == 0, thanks Rob
|
* - oop, allow index == 0, thanks Rob
|
||||||
|
* 12/1/21
|
||||||
|
* - add hist path for large windows on uchar images
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -81,6 +83,8 @@ typedef struct _VipsRank {
|
|||||||
|
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
|
gboolean hist_path;
|
||||||
|
|
||||||
} VipsRank;
|
} VipsRank;
|
||||||
|
|
||||||
typedef VipsMorphologyClass VipsRankClass;
|
typedef VipsMorphologyClass VipsRankClass;
|
||||||
@ -91,15 +95,33 @@ G_DEFINE_TYPE( VipsRank, vips_rank, VIPS_TYPE_MORPHOLOGY );
|
|||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
VipsRegion *ir;
|
VipsRegion *ir;
|
||||||
|
|
||||||
|
/* Sort array.
|
||||||
|
*/
|
||||||
VipsPel *sort;
|
VipsPel *sort;
|
||||||
|
|
||||||
|
/* For large uchar images, the sort histogram.
|
||||||
|
*/
|
||||||
|
unsigned int **hist;
|
||||||
} VipsRankSequence;
|
} VipsRankSequence;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vips_rank_stop( void *vseq, void *a, void *b )
|
vips_rank_stop( void *vseq, void *a, void *b )
|
||||||
{
|
{
|
||||||
VipsRankSequence *seq = (VipsRankSequence *) vseq;
|
VipsRankSequence *seq = (VipsRankSequence *) vseq;
|
||||||
|
VipsImage *in = (VipsImage *) a;
|
||||||
|
|
||||||
VIPS_UNREF( seq->ir );
|
VIPS_UNREF( seq->ir );
|
||||||
|
VIPS_FREE( seq->sort );
|
||||||
|
|
||||||
|
if( seq->hist &&
|
||||||
|
in ) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for( i = 0; i < in->Bands; i++ )
|
||||||
|
VIPS_FREE( seq->hist[i] );
|
||||||
|
}
|
||||||
|
VIPS_FREE( seq->hist );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
@ -115,17 +137,109 @@ vips_rank_start( VipsImage *out, void *a, void *b )
|
|||||||
return( NULL );
|
return( NULL );
|
||||||
seq->ir = NULL;
|
seq->ir = NULL;
|
||||||
seq->sort = NULL;
|
seq->sort = NULL;
|
||||||
|
seq->hist = NULL;
|
||||||
|
|
||||||
seq->ir = vips_region_new( in );
|
seq->ir = vips_region_new( in );
|
||||||
if( !(seq->sort = VIPS_ARRAY( out,
|
if( !(seq->sort = VIPS_ARRAY( NULL,
|
||||||
VIPS_IMAGE_SIZEOF_ELEMENT( in ) * rank->n, VipsPel )) ) {
|
VIPS_IMAGE_SIZEOF_ELEMENT( in ) * rank->n, VipsPel )) ) {
|
||||||
vips_rank_stop( seq, in, rank );
|
vips_rank_stop( seq, in, rank );
|
||||||
return( NULL );
|
return( NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if( rank->hist_path ) {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if( !(seq->hist =
|
||||||
|
VIPS_ARRAY( NULL, in->Bands, unsigned int * )) ) {
|
||||||
|
vips_rank_stop( seq, in, rank );
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
|
||||||
|
for( i = 0; i < in->Bands; i++ )
|
||||||
|
if( !(seq->hist[i] =
|
||||||
|
VIPS_ARRAY( NULL, 256, unsigned int )) ) {
|
||||||
|
vips_rank_stop( seq, in, rank );
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return( (void *) seq );
|
return( (void *) seq );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Histogram path for large uchar ranks.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
vips_rank_generate_uchar( VipsRegion *or,
|
||||||
|
VipsRankSequence *seq, VipsRank *rank, int y )
|
||||||
|
{
|
||||||
|
VipsImage *in = seq->ir->im;
|
||||||
|
VipsRect *r = &or->valid;
|
||||||
|
const int bands = in->Bands;
|
||||||
|
|
||||||
|
/* Get input and output pointers for this line.
|
||||||
|
*/
|
||||||
|
VipsPel * restrict p =
|
||||||
|
VIPS_REGION_ADDR( seq->ir, r->left, r->top + y );
|
||||||
|
VipsPel * restrict q =
|
||||||
|
VIPS_REGION_ADDR( or, r->left, r->top + y );
|
||||||
|
|
||||||
|
VipsPel * restrict p1;
|
||||||
|
int lsk;
|
||||||
|
int x, i, j, b;
|
||||||
|
|
||||||
|
lsk = VIPS_REGION_LSKIP( seq->ir );
|
||||||
|
|
||||||
|
/* Find histogram for the first output pixel.
|
||||||
|
*/
|
||||||
|
for( b = 0; b < bands; b++ )
|
||||||
|
memset( seq->hist[b], 0, 256 * sizeof( unsigned int ) );
|
||||||
|
p1 = p;
|
||||||
|
for( j = 0; j < rank->height; j++ ) {
|
||||||
|
for( i = 0, x = 0; x < rank->width; x++ )
|
||||||
|
for( b = 0; b < bands; b++, i++ )
|
||||||
|
seq->hist[b][p1[i]] += 1;
|
||||||
|
|
||||||
|
p1 += lsk;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Loop for output pels.
|
||||||
|
*/
|
||||||
|
for( x = 0; x < r->width; x++ ) {
|
||||||
|
for( b = 0; b < bands; b++ ) {
|
||||||
|
/* Calculate cumulative histogram -- the value is the
|
||||||
|
* index at which we pass the rank.
|
||||||
|
*/
|
||||||
|
unsigned int * restrict hist = seq->hist[b];
|
||||||
|
|
||||||
|
int sum;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
sum = 0;
|
||||||
|
for( i = 0; i < 256; i++ ) {
|
||||||
|
sum += hist[i];
|
||||||
|
if( sum > rank->index )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
q[b] = i;
|
||||||
|
|
||||||
|
/* Adapt histogram --- remove the pels from
|
||||||
|
* the left hand column, add in pels for a
|
||||||
|
* new right-hand column.
|
||||||
|
*/
|
||||||
|
p1 = p + b;
|
||||||
|
for( j = 0; j < rank->height; j++ ) {
|
||||||
|
hist[p1[0]] -= 1;
|
||||||
|
hist[p1[bands * rank->width]] += 1;
|
||||||
|
|
||||||
|
p1 += lsk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p += bands;
|
||||||
|
q += bands;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Inner loop for select-sorting TYPE.
|
/* Inner loop for select-sorting TYPE.
|
||||||
*/
|
*/
|
||||||
#define LOOP_SELECT( TYPE ) { \
|
#define LOOP_SELECT( TYPE ) { \
|
||||||
@ -318,7 +432,9 @@ vips_rank_generate( VipsRegion *or,
|
|||||||
ls = VIPS_REGION_LSKIP( ir ) / VIPS_IMAGE_SIZEOF_ELEMENT( in );
|
ls = VIPS_REGION_LSKIP( ir ) / VIPS_IMAGE_SIZEOF_ELEMENT( in );
|
||||||
|
|
||||||
for( y = 0; y < r->height; y++ ) {
|
for( y = 0; y < r->height; y++ ) {
|
||||||
if( rank->index == 0 )
|
if( rank->hist_path )
|
||||||
|
vips_rank_generate_uchar( or, seq, rank, y );
|
||||||
|
else if( rank->index == 0 )
|
||||||
SWITCH( LOOP_MIN )
|
SWITCH( LOOP_MIN )
|
||||||
else if( rank->index == rank->n - 1 )
|
else if( rank->index == rank->n - 1 )
|
||||||
SWITCH( LOOP_MAX )
|
SWITCH( LOOP_MAX )
|
||||||
@ -360,6 +476,19 @@ vips_rank_build( VipsObject *object )
|
|||||||
return( -1 );
|
return( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Enable the hist path if it'll probably help.
|
||||||
|
*/
|
||||||
|
if( in->BandFmt == VIPS_FORMAT_UCHAR ) {
|
||||||
|
/* The hist path gets faster for windows larger than about
|
||||||
|
* 3x3, or 10x10 for the special max/min case.
|
||||||
|
*/
|
||||||
|
if( rank->n < 10 )
|
||||||
|
rank->hist_path = TRUE;
|
||||||
|
else if( rank->n < 90 &&
|
||||||
|
(rank->index == 0 || rank->index == rank->n - 1) )
|
||||||
|
rank->hist_path = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
/* Expand the input.
|
/* Expand the input.
|
||||||
*/
|
*/
|
||||||
if( vips_embed( in, &t[1],
|
if( vips_embed( in, &t[1],
|
||||||
|
Loading…
Reference in New Issue
Block a user