vips_max() returns arrays for position and value
int array type too for x/y position arrays
This commit is contained in:
parent
4b9ca4cfce
commit
1e332d2f29
@ -24,6 +24,7 @@
|
||||
- preserve jpeg app13 (photoshop ipct)
|
||||
- nearest neighbour goes back to round down ... round to nearest caused a
|
||||
range of annoying problems, such as strange half-pixels along edges
|
||||
- vips_max() tracks the top n maxima
|
||||
|
||||
14/11/12 started 7.30.6
|
||||
- capture tiff warnings earlier
|
||||
|
@ -22,7 +22,7 @@
|
||||
* - avoid NaN in float/double/complex images
|
||||
* - allow +/- INFINITY as a result
|
||||
* 4/12/12
|
||||
* - track top n values
|
||||
* - track and return top n values
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -109,6 +109,13 @@ typedef struct _VipsMax {
|
||||
int x;
|
||||
int y;
|
||||
|
||||
/* And the postions and values we found as VipsArrays for returning to
|
||||
* our caller.
|
||||
*/
|
||||
VipsArrayDouble *max_array;
|
||||
VipsArrayInt *x_array;
|
||||
VipsArrayInt *y_array;
|
||||
|
||||
/* Global state here.
|
||||
*/
|
||||
VipsValues values;
|
||||
@ -159,7 +166,7 @@ vips_values_add( VipsValues *values, double v, int x, int y )
|
||||
else {
|
||||
/* Not full, move stuff to the right into empty space.
|
||||
*/
|
||||
for( j = values->n + 1; j > i; j-- ) {
|
||||
for( j = values->n; j > i; j-- ) {
|
||||
values->value[j] = values->value[j - 1];
|
||||
values->x_pos[j] = values->x_pos[j - 1];
|
||||
values->y_pos[j] = values->y_pos[j - 1];
|
||||
@ -198,6 +205,14 @@ vips_max_build( VipsObject *object )
|
||||
* will trigger an error later.
|
||||
*/
|
||||
if( values->n > 0 ) {
|
||||
VipsArrayDouble *out_array;
|
||||
VipsArrayInt *x_array;
|
||||
VipsArrayInt *y_array;
|
||||
|
||||
out_array = vips_array_double_new( values->value, values->n );
|
||||
x_array = vips_array_int_new( values->x_pos, values->n );
|
||||
y_array = vips_array_int_new( values->y_pos, values->n );
|
||||
|
||||
/* We have to set the props via g_object_set() to stop vips
|
||||
* complaining they are unset.
|
||||
*/
|
||||
@ -205,9 +220,25 @@ vips_max_build( VipsObject *object )
|
||||
"out", values->value[values->n - 1],
|
||||
"x", values->x_pos[values->n - 1],
|
||||
"y", values->y_pos[values->n - 1],
|
||||
"out_array", out_array,
|
||||
"x_array", x_array,
|
||||
"y_array", y_array,
|
||||
NULL );
|
||||
|
||||
vips_area_unref( (VipsArea *) out_array );
|
||||
vips_area_unref( (VipsArea *) x_array );
|
||||
vips_area_unref( (VipsArea *) y_array );
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "vips_max_build: %d values found\n", values->n );
|
||||
for( i = 0; i < values->n; i++ )
|
||||
printf( "%d) %g\t%d\t%d\n",
|
||||
i,
|
||||
values->value[i],
|
||||
values->x_pos[i], values->y_pos[i] );
|
||||
#endif /*DEBUG*/
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
@ -243,19 +274,25 @@ vips_max_stop( VipsStatistic *statistic, void *seq )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Real max with an upper bound. Stop if our array fills with maxval.
|
||||
/* Real max with an upper bound.
|
||||
*
|
||||
* Add values to the buffer if they are greater than the buffer minimum. If
|
||||
* the buffer isn't full, there is no minimum.
|
||||
*
|
||||
* Avoid a double test by splitting the loop into two phases: before and after
|
||||
* the buffer fills.
|
||||
*
|
||||
* Stop if our array fills with maxval.
|
||||
*/
|
||||
#define LOOPU( TYPE, UPPER ) { \
|
||||
TYPE *p = (TYPE *) in; \
|
||||
TYPE m; \
|
||||
\
|
||||
if( values->n ) \
|
||||
m = values->value[0]; \
|
||||
else { \
|
||||
m = p[0]; \
|
||||
} \
|
||||
for( i = 0; i < sz && values->n < values->size; i++ ) \
|
||||
vips_values_add( values, p[i], x + i / bands, y ); \
|
||||
m = values->value[0]; \
|
||||
\
|
||||
for( i = 0; i < sz; i++ ) { \
|
||||
for( ; i < sz; i++ ) { \
|
||||
if( p[i] > m ) { \
|
||||
vips_values_add( values, p[i], x + i / bands, y ); \
|
||||
m = values->value[0]; \
|
||||
@ -277,45 +314,44 @@ vips_max_stop( VipsStatistic *statistic, void *seq )
|
||||
#define LOOPF( TYPE ) { \
|
||||
TYPE *p = (TYPE *) in; \
|
||||
TYPE m; \
|
||||
gboolean set; \
|
||||
\
|
||||
set = values->n > 0; \
|
||||
if( set ) \
|
||||
m = values->value[0]; \
|
||||
for( i = 0; i < sz && values->n < values->size; i++ ) \
|
||||
if( !isnan( p[i] ) ) \
|
||||
vips_values_add( values, p[i], x + i / bands, y ); \
|
||||
m = values->value[0]; \
|
||||
\
|
||||
for( i = 0; i < sz; i++ ) { \
|
||||
if( (set && p[i] > m) || \
|
||||
(!set && !isnan( p[i] )) ) { \
|
||||
for( ; i < sz; i++ ) \
|
||||
if( p[i] > m ) { \
|
||||
vips_values_add( values, p[i], x + i / bands, y ); \
|
||||
m = values->value[0]; \
|
||||
set = TRUE; \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
/* As LOOPF, but complex. Track max(mod) to avoid sqrt().
|
||||
/* As LOOPF, but complex. Track max(mod ** 2) to avoid sqrt().
|
||||
*/
|
||||
#define LOOPC( TYPE ) { \
|
||||
TYPE *p = (TYPE *) in; \
|
||||
TYPE m; \
|
||||
gboolean set; \
|
||||
\
|
||||
set = values->n > 0; \
|
||||
if( set ) \
|
||||
m = values->value[0]; \
|
||||
\
|
||||
for( i = 0; i < sz; i++ ) { \
|
||||
TYPE mod; \
|
||||
for( i = 0; i < sz && values->n < values->size; i++ ) { \
|
||||
TYPE mod2 = p[0] * p[0] + p[1] * p[1]; \
|
||||
\
|
||||
if( !isnan( mod2 ) ) \
|
||||
vips_values_add( values, p[i], x + i / bands, y ); \
|
||||
\
|
||||
mod = p[0] * p[0] + p[1] * p[1]; \
|
||||
p += 2; \
|
||||
} \
|
||||
m = values->value[0]; \
|
||||
\
|
||||
for( ; i < sz; i++ ) { \
|
||||
TYPE mod2 = p[0] * p[0] + p[1] * p[1]; \
|
||||
\
|
||||
if( (set && mod > m) || \
|
||||
(!set && !isnan( mod )) ) { \
|
||||
vips_values_add( values, mod, x + i / bands, y ); \
|
||||
if( mod2 > m ) { \
|
||||
vips_values_add( values, mod2, x + i / bands, y ); \
|
||||
m = values->value[0]; \
|
||||
set = TRUE; \
|
||||
} \
|
||||
\
|
||||
p += 2; \
|
||||
} \
|
||||
}
|
||||
|
||||
@ -408,12 +444,32 @@ vips_max_class_init( VipsMaxClass *class )
|
||||
G_STRUCT_OFFSET( VipsMax, size ),
|
||||
0, 1000000, 10 );
|
||||
|
||||
VIPS_ARG_BOXED( class, "out_array", 6,
|
||||
_( "Output array" ),
|
||||
_( "Array of output values" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_OUTPUT,
|
||||
G_STRUCT_OFFSET( VipsMax, max_array ),
|
||||
VIPS_TYPE_ARRAY_DOUBLE );
|
||||
|
||||
VIPS_ARG_BOXED( class, "x_array", 7,
|
||||
_( "x array" ),
|
||||
_( "Array of horizontal positions" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_OUTPUT,
|
||||
G_STRUCT_OFFSET( VipsMax, x_array ),
|
||||
VIPS_TYPE_ARRAY_INT );
|
||||
|
||||
VIPS_ARG_BOXED( class, "y_array", 8,
|
||||
_( "y array" ),
|
||||
_( "Array of vertical positions" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_OUTPUT,
|
||||
G_STRUCT_OFFSET( VipsMax, y_array ),
|
||||
VIPS_TYPE_ARRAY_INT );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_max_init( VipsMax *max )
|
||||
{
|
||||
max->size = 10;
|
||||
max->size = 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -427,6 +483,9 @@ vips_max_init( VipsMax *max )
|
||||
* @x: horizontal position of maximum
|
||||
* @y: vertical position of maximum
|
||||
* @size: number of maxima to find
|
||||
* @out_array: return array of maximum values
|
||||
* @x_array: corresponding horizontal positions
|
||||
* @y_array: corresponding vertical positions
|
||||
*
|
||||
* This operation finds the maximum value in an image.
|
||||
*
|
||||
@ -439,7 +498,9 @@ vips_max_init( VipsMax *max )
|
||||
*
|
||||
* For complex images, this operation finds the maximum modulus.
|
||||
*
|
||||
* You can read out the position of the maximum with @x and @y.
|
||||
* You can read out the position of the maximum with @x and @y. You can read
|
||||
* out arrays of the values and positions of the top @size maxima with
|
||||
* @out_array, @x_array and @y_array.
|
||||
*
|
||||
* See also: vips_min(), vips_stats().
|
||||
*
|
||||
|
@ -2810,9 +2810,13 @@ im_quadratic( IMAGE *in, IMAGE *out, IMAGE *coeff )
|
||||
int
|
||||
im_maxpos_vec( VipsImage *im, int *xpos, int *ypos, double *maxima, int n )
|
||||
{
|
||||
printf( "im_maxpos_vec: fixme\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
int
|
||||
im_minpos_vec( VipsImage *im, int *xpos, int *ypos, double *minima, int n )
|
||||
{
|
||||
printf( "im_minpos_vec: fixme\n" );
|
||||
return( -1 );
|
||||
}
|
||||
|
@ -128,7 +128,6 @@ GType vips_ref_string_get_type( void );
|
||||
#define VIPS_TYPE_BLOB (vips_blob_get_type())
|
||||
GType vips_blob_get_type( void );
|
||||
|
||||
|
||||
/**
|
||||
* VIPS_TYPE_ARRAY_DOUBLE:
|
||||
*
|
||||
@ -140,6 +139,17 @@ VipsArrayDouble *vips_array_double_new( const double *array, int n );
|
||||
VipsArrayDouble *vips_array_double_newv( int n, ... );
|
||||
GType vips_array_double_get_type( void );
|
||||
|
||||
/**
|
||||
* VIPS_TYPE_ARRAY_INT:
|
||||
*
|
||||
* The #GType for a #VipsArrayInt.
|
||||
*/
|
||||
#define VIPS_TYPE_ARRAY_INT (vips_array_int_get_type())
|
||||
typedef VipsArea VipsArrayInt;
|
||||
VipsArrayInt *vips_array_int_new( const int *array, int n );
|
||||
VipsArrayInt *vips_array_int_newv( int n, ... );
|
||||
GType vips_array_int_get_type( void );
|
||||
|
||||
/**
|
||||
* VIPS_TYPE_ARRAY_IMAGE:
|
||||
*
|
||||
@ -171,6 +181,9 @@ void *vips_value_get_array( const GValue *value,
|
||||
double *vips_value_get_array_double( const GValue *value, int *n );
|
||||
int vips_value_set_array_double( GValue *value, const double *array, int n );
|
||||
|
||||
int *vips_value_get_array_int( const GValue *value, int *n );
|
||||
int vips_value_set_array_int( GValue *value, const int *array, int n );
|
||||
|
||||
GObject **vips_value_get_array_object( const GValue *value, int *n );
|
||||
int vips_value_set_array_object( GValue *value, int n );
|
||||
|
||||
|
@ -546,6 +546,78 @@ vips_blob_get_type( void )
|
||||
return( type );
|
||||
}
|
||||
|
||||
static void
|
||||
transform_array_int_g_string( const GValue *src_value, GValue *dest_value )
|
||||
{
|
||||
int n;
|
||||
int *array = vips_value_get_array_int( src_value, &n );
|
||||
|
||||
char txt[1024];
|
||||
VipsBuf buf = VIPS_BUF_STATIC( txt );
|
||||
int i;
|
||||
|
||||
for( i = 0; i < n; i++ )
|
||||
/* Use space as a separator since ',' may be a decimal point
|
||||
* in this locale.
|
||||
*/
|
||||
vips_buf_appendf( &buf, "%d ", array[i] );
|
||||
|
||||
g_value_set_string( dest_value, vips_buf_all( &buf ) );
|
||||
}
|
||||
|
||||
/* It'd be great to be able to write a generic string->array function, but
|
||||
* it doesn't seem possible.
|
||||
*/
|
||||
static void
|
||||
transform_g_string_array_int( const GValue *src_value, GValue *dest_value )
|
||||
{
|
||||
char *str;
|
||||
int n;
|
||||
char *p, *q;
|
||||
int i;
|
||||
int *array;
|
||||
|
||||
/* Walk the string to get the number of elements.
|
||||
* We need a copy of the string, since we insert \0 during
|
||||
* scan.
|
||||
*
|
||||
* We can't allow ',' as a separator, since some locales use it as a
|
||||
* decimal point.
|
||||
*/
|
||||
str = g_value_dup_string( src_value );
|
||||
n = 0;
|
||||
for( p = str; (q = vips_break_token( p, "\t; " )); p = q )
|
||||
n += 1;
|
||||
g_free( str );
|
||||
|
||||
vips_value_set_array( dest_value, n, G_TYPE_INT, sizeof( int ) );
|
||||
array = (int *) vips_value_get_array( dest_value, NULL, NULL, NULL );
|
||||
|
||||
str = g_value_dup_string( src_value );
|
||||
i = 0;
|
||||
for( p = str; (q = vips_break_token( p, "\t; " )); p = q )
|
||||
array[i++] = atoi( p );
|
||||
g_free( str );
|
||||
}
|
||||
|
||||
GType
|
||||
vips_array_int_get_type( void )
|
||||
{
|
||||
static GType type = 0;
|
||||
|
||||
if( !type ) {
|
||||
type = g_boxed_type_register_static( "VipsArrayInt",
|
||||
(GBoxedCopyFunc) vips_area_copy,
|
||||
(GBoxedFreeFunc) vips_area_unref );
|
||||
g_value_register_transform_func( type, G_TYPE_STRING,
|
||||
transform_array_int_g_string );
|
||||
g_value_register_transform_func( G_TYPE_STRING, type,
|
||||
transform_g_string_array_int );
|
||||
}
|
||||
|
||||
return( type );
|
||||
}
|
||||
|
||||
static void
|
||||
transform_array_double_g_string( const GValue *src_value, GValue *dest_value )
|
||||
{
|
||||
@ -915,6 +987,105 @@ vips_value_get_array( const GValue *value,
|
||||
return( area->data );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_array_int_new:
|
||||
* @array: (array length=n): array of int
|
||||
* @n: number of ints
|
||||
*
|
||||
* Allocate a new array of ints and copy @array into it. Free with
|
||||
* vips_area_unref().
|
||||
*
|
||||
* See also: #VipsArea.
|
||||
*
|
||||
* Returns: (transfer full): A new #VipsArrayInt.
|
||||
*/
|
||||
VipsArrayInt *
|
||||
vips_array_int_new( const int *array, int n )
|
||||
{
|
||||
VipsArea *area;
|
||||
int *array_copy;
|
||||
|
||||
area = vips_area_new_array( G_TYPE_INT, sizeof( int ), n );
|
||||
array_copy = vips_area_get_data( area, NULL, NULL, NULL, NULL );
|
||||
memcpy( array_copy, array, n * sizeof( int ) );
|
||||
|
||||
return( area );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_array_int_newv:
|
||||
* @n: number of ints
|
||||
* @...: list of int arguments
|
||||
*
|
||||
* Allocate a new array of @n ints and copy @... into it. Free with
|
||||
* vips_area_unref().
|
||||
*
|
||||
* See also: vips_array_int_new()
|
||||
*
|
||||
* Returns: (transfer full): A new #VipsArrayInt.
|
||||
*/
|
||||
VipsArrayInt *
|
||||
vips_array_int_newv( int n, ... )
|
||||
{
|
||||
va_list ap;
|
||||
VipsArea *area;
|
||||
int *array;
|
||||
int i;
|
||||
|
||||
area = vips_area_new_array( G_TYPE_INT, sizeof( int ), n );
|
||||
array = vips_area_get_data( area, NULL, NULL, NULL, NULL );
|
||||
|
||||
va_start( ap, n );
|
||||
for( i = 0; i < n; i++ )
|
||||
array[i] = va_arg( ap, int );
|
||||
va_end( ap );
|
||||
|
||||
return( area );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_value_get_array_int:
|
||||
* @value: %GValue to get from
|
||||
* @n: (allow-none): return the number of elements here, optionally
|
||||
*
|
||||
* Return the start of the array of ints held by @value.
|
||||
* optionally return the number of elements in @n.
|
||||
*
|
||||
* See also: vips_array_int_set().
|
||||
*
|
||||
* Returns: (transfer none): The array address.
|
||||
*/
|
||||
int *
|
||||
vips_value_get_array_int( const GValue *value, int *n )
|
||||
{
|
||||
return( vips_value_get_array( value, n, NULL, NULL ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_value_set_array_int:
|
||||
* @value: (out): %GValue to get from
|
||||
* @array: (array length=n): array of ints
|
||||
* @n: the number of elements
|
||||
*
|
||||
* Set @value to hold a copy of @array. Pass in the array length in @n.
|
||||
*
|
||||
* See also: vips_array_int_get().
|
||||
*
|
||||
* Returns: 0 on success, -1 otherwise.
|
||||
*/
|
||||
int
|
||||
vips_value_set_array_int( GValue *value, const int *array, int n )
|
||||
{
|
||||
int *array_copy;
|
||||
|
||||
g_value_init( value, VIPS_TYPE_ARRAY_INT );
|
||||
vips_value_set_array( value, n, G_TYPE_INT, sizeof( int ) );
|
||||
array_copy = vips_value_get_array_int( value, NULL );
|
||||
memcpy( array_copy, array, n * sizeof( int ) );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* vips_array_double_new:
|
||||
* @array: (array length=n): array of double
|
||||
|
Loading…
Reference in New Issue
Block a user