make vips_gaussnoise() pixels reproducible

previously, pixel values were regenerated on every calculation, so they
changed on recomputation

pixel values are now generated from the pixel (x, y) coordinate plus a per-call
seed

thanks MvGulik, see

https://github.com/jcupitt/nip2/issues/60

https://github.com/jcupitt/libvips/issues/583
This commit is contained in:
John Cupitt 2017-01-24 09:36:25 +00:00
parent c963678549
commit 36761bcfd7
6 changed files with 48 additions and 40 deletions

View File

@ -28,6 +28,7 @@
- kick load operations from cache on read error, thanks gaillard
- fix return from C++ assignment operator overloads (+=, -= etc)
- add @max_slope to vips_local_hist() to implement CLAHE, thanks hunter-87
- vips_gaussnoise() pixels are reproducible on recalc, thanks MvGulik
8/12/16 started 8.4.5
- allow libgsf-1.14.26 to help centos, thanks tdiprima

View File

@ -22,6 +22,10 @@
* - redo as a class
* 8/11/14
* - use g_random_double()
* 24/1/17
* - use g_random_double() once per image, use vips__random() for pixel
* values from (x, y) position ... makes pixels reproducible on
* recalculation
*/
/*
@ -71,6 +75,9 @@ typedef struct _VipsGaussnoise {
double mean;
double sigma;
/* Per-image seed.
*/
guint32 seed;
} VipsGaussnoise;
typedef VipsCreateClass VipsGaussnoiseClass;
@ -93,12 +100,19 @@ vips_gaussnoise_gen( VipsRegion *or, void *seq, void *a, void *b,
int x;
for( x = 0; x < sz; x++ ) {
guint32 seed;
double sum;
int i;
seed = gaussnoise->seed;
seed = vips__random_add( seed, or->valid.left + x );
seed = vips__random_add( seed, or->valid.top + y );
sum = 0.0;
for( i = 0; i < 12; i++ )
sum += g_random_double();
for( i = 0; i < 12; i++ ) {
seed = vips__random( seed );
sum += (double) seed / UINT_MAX;
}
q[x] = (sum - 6.0) * gaussnoise->sigma +
gaussnoise->mean;
@ -124,6 +138,11 @@ vips_gaussnoise_build( VipsObject *object )
vips_image_pipelinev( create->out,
VIPS_DEMAND_STYLE_ANY, NULL );
/* The seed for this image. Each pixel is seeded by this plus the (x,
* y) coordinate.
*/
gaussnoise->seed = UINT_MAX * g_random_double();
if( vips_image_generate( create->out,
NULL, vips_gaussnoise_gen, NULL, gaussnoise, NULL ) )
return( -1 );

View File

@ -92,21 +92,6 @@ typedef struct _Sequence {
} Sequence;
/* A very simple random number generator. See:
* http://isthe.com/chongo/tech/comp/fnv/#FNV-source
*/
static guint32
vips_perlin_random( guint32 seed )
{
return( 1103515245u * seed + 12345 );
}
static guint32
vips_perlin_seed_add( guint32 seed, int value )
{
return( ((2166136261u ^ seed) * 16777619u) ^ value );
}
/* Generate a 3 x 3 grid of cells around a point.
*/
static void
@ -135,13 +120,12 @@ vips_perlin_create_cells( VipsPerlin *perlin,
if( cy >= perlin->cells_down )
cy = 0;
seed = vips_perlin_seed_add( seed, cy );
seed = vips__random_add( seed, cy );
if( cx >= perlin->cells_across )
cx = 0;
seed = vips_perlin_seed_add( seed, cx );
seed = vips__random_add( seed, cx );
seed = vips_perlin_random( seed );
angle = (seed ^ (seed >> 8) ^ (seed >> 16)) & 0xff;
gx[ci] = vips_perlin_cos[angle];

View File

@ -107,21 +107,6 @@ typedef struct _Sequence {
} Sequence;
/* A very simple random number generator. See:
* http://isthe.com/chongo/tech/comp/fnv/#FNV-source
*/
static guint32
vips_worley_random( guint32 seed )
{
return( 1103515245u * seed + 12345 );
}
static guint32
vips_worley_seed_add( guint32 seed, int value )
{
return( ((2166136261u ^ seed) * 16777619u) ^ value );
}
/* Generate a 3 x 3 grid of cells around a point.
*/
static void
@ -154,7 +139,7 @@ vips_worley_create_cells( VipsWorley *worley,
value = worley->cells_across - 1;
else
value = cell->cell_x;
seed = vips_worley_seed_add( seed, value );
seed = vips__random_add( seed, value );
if( cell->cell_y >= worley->cells_down )
value = 0;
@ -162,20 +147,19 @@ vips_worley_create_cells( VipsWorley *worley,
value = worley->cells_down - 1;
else
value = cell->cell_y;
seed = vips_worley_seed_add( seed, value );
seed = vips__random_add( seed, value );
/* [1, MAX_FEATURES)
*/
seed = vips_worley_random( seed );
cell->n_features = (seed % (MAX_FEATURES - 1)) + 1;
for( j = 0; j < cell->n_features; j++ ) {
seed = vips_worley_random( seed );
seed = vips__random( seed );
cell->feature_x[j] =
cell->cell_x * worley->cell_size +
seed % worley->cell_size;
seed = vips_worley_random( seed );
seed = vips__random( seed );
cell->feature_y[j] =
cell->cell_y * worley->cell_size +
seed % worley->cell_size;

View File

@ -328,6 +328,9 @@ void vips__change_suffix( const char *name, char *out, int mx,
char *vips_realpath( const char *path );
guint32 vips__random( guint32 seed );
guint32 vips__random_add( guint32 seed, int value );
#ifdef __cplusplus
}
#endif /*__cplusplus*/

View File

@ -1912,3 +1912,20 @@ vips_realpath( const char *path )
return( real );
}
/* A very simple random number generator. See:
* http://isthe.com/chongo/tech/comp/fnv/#FNV-source
*/
guint32
vips__random( guint32 seed )
{
return( 1103515245u * seed + 12345 );
}
guint32
vips__random_add( guint32 seed, int value )
{
seed = ((2166136261u ^ seed) * 16777619u) ^ value;
return( vips__random( seed ) );
}