sync
This commit is contained in:
parent
9493ea7e29
commit
90849a44c5
8
TODO
8
TODO
@ -1,5 +1,13 @@
|
|||||||
|
- add an INTERPRETATION for "array"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- im_open_local() is broken? try Adam's prog under 7.27
|
- im_open_local() is broken? try Adam's prog under 7.27
|
||||||
|
|
||||||
|
... it's the operation cache, we just need to call vips_shutdown()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- see: vips_abs_build(), should that set an arithmetic member? ugly
|
- see: vips_abs_build(), should that set an arithmetic member? ugly
|
||||||
|
@ -79,7 +79,8 @@
|
|||||||
* bands of the input image: use im_stats() if you need to find an
|
* bands of the input image: use im_stats() if you need to find an
|
||||||
* maximum for each band. For complex images, find the maximum modulus.
|
* maximum for each band. For complex images, find the maximum modulus.
|
||||||
*
|
*
|
||||||
* See also: #VipsAvg, #VipsMin, im_stats(), im_bandmean(), im_deviate(), im_rank()
|
* See also: #VipsAvg, #VipsMin, im_stats(), im_bandmean(), #VipsDeviate,
|
||||||
|
* im_rank().
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct _VipsMax {
|
typedef struct _VipsMax {
|
||||||
|
@ -85,8 +85,6 @@
|
|||||||
* bands together, row 1 has stats for band 1, and so on.
|
* bands together, row 1 has stats for band 1, and so on.
|
||||||
*
|
*
|
||||||
* See also: #VipsAvg, #VipsMin, and friends.
|
* See also: #VipsAvg, #VipsMin, and friends.
|
||||||
*
|
|
||||||
* Returns: 0 on success, -1 on error
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct _VipsStats {
|
typedef struct _VipsStats {
|
||||||
@ -94,12 +92,33 @@ typedef struct _VipsStats {
|
|||||||
|
|
||||||
VipsImage *out;
|
VipsImage *out;
|
||||||
|
|
||||||
|
gboolean set; /* FALSE means no value yet */
|
||||||
} VipsStats;
|
} VipsStats;
|
||||||
|
|
||||||
typedef VipsStatisticClass VipsStatsClass;
|
typedef VipsStatisticClass VipsStatsClass;
|
||||||
|
|
||||||
G_DEFINE_TYPE( VipsStats, vips_stats, VIPS_TYPE_STATISTIC );
|
G_DEFINE_TYPE( VipsStats, vips_stats, VIPS_TYPE_STATISTIC );
|
||||||
|
|
||||||
|
/* Names for our columns.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
COL_MIN = 0,
|
||||||
|
COL_MAX = 1,
|
||||||
|
COL_SUM = 2,
|
||||||
|
COL_SUM2 = 3,
|
||||||
|
COL_AVG = 4,
|
||||||
|
COL_SD = 5,
|
||||||
|
COL_XMIN = 6,
|
||||||
|
COL_YMIN = 7,
|
||||||
|
COL_XMAX = 8,
|
||||||
|
COL_YMAX = 9,
|
||||||
|
COL_LAST = 10
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Address a double in our array image.
|
||||||
|
*/
|
||||||
|
#define ARY( im, x, y ) ((double *) VIPS_IMAGE_ADDR( im, x, y ))
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vips_stats_build( VipsObject *object )
|
vips_stats_build( VipsObject *object )
|
||||||
{
|
{
|
||||||
@ -107,76 +126,150 @@ vips_stats_build( VipsObject *object )
|
|||||||
VipsStats *stats = (VipsStats *) object;
|
VipsStats *stats = (VipsStats *) object;
|
||||||
|
|
||||||
gint64 vals;
|
gint64 vals;
|
||||||
double average;
|
|
||||||
|
|
||||||
if( statistic->in ) {
|
if( statistic->in ) {
|
||||||
int bands = vips_image_get_bands( statistic->in->Bands );
|
int bands = vips_image_get_bands( statistic->in->Bands ) : 0;
|
||||||
|
|
||||||
g_object_set( object,
|
g_object_set( object,
|
||||||
"out", vips_image_new_array( 10, bands + 1 ),
|
"out", vips_image_new_array( COL_LAST, bands + 1 ),
|
||||||
NULL );
|
NULL );
|
||||||
}
|
}
|
||||||
|
|
||||||
if( VIPS_OBJECT_CLASS( vips_stats_parent_class )->build( object ) )
|
if( VIPS_OBJECT_CLASS( vips_stats_parent_class )->build( object ) )
|
||||||
return( -1 );
|
return( -1 );
|
||||||
|
|
||||||
/* Calculate average. For complex, we accumulate re*re +
|
|
||||||
* im*im, so we need to sqrt.
|
|
||||||
*/
|
|
||||||
vals = (gint64)
|
vals = (gint64)
|
||||||
vips_image_get_width( statistic->in ) *
|
vips_image_get_width( statistic->in ) *
|
||||||
vips_image_get_height( statistic->in ) *
|
vips_image_get_height( statistic->in ) *
|
||||||
vips_image_get_bands( statistic->in );
|
vips_image_get_bands( statistic->in );
|
||||||
average = stats->sum / vals;
|
|
||||||
if( vips_bandfmt_iscomplex( vips_image_get_format( statistic->in ) ) )
|
for( b = 0; b < vips_image_get_bands( statistic->in ); b++ ) {
|
||||||
average = sqrt( average );
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
row = out->coeff + (i + 1) * 6;
|
||||||
|
for( j = 0; j < 4; j++ )
|
||||||
|
row[j] = global_stats[i * 4 + j];
|
||||||
|
|
||||||
|
out->coeff[0] = IM_MIN( out->coeff[0], row[0] );
|
||||||
|
out->coeff[1] = IM_MAX( out->coeff[1], row[1] );
|
||||||
|
out->coeff[2] += row[2];
|
||||||
|
out->coeff[3] += row[3];
|
||||||
|
row[4] = row[2] / pels;
|
||||||
|
row[5] = sqrt( fabs( row[3] - (row[2] * row[2] / pels) ) /
|
||||||
|
(pels - 1) );
|
||||||
|
}
|
||||||
|
out->coeff[4] = out->coeff[2] / vals;
|
||||||
|
out->coeff[5] = sqrt( fabs( out->coeff[3] -
|
||||||
|
(out->coeff[2] * out->coeff[2] / vals) ) / (vals - 1) );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Start function: allocate space for a double in which we can accumulate the
|
/* Stop function. Add these little stats to the main set of stats.
|
||||||
* sum for this thread.
|
|
||||||
*/
|
|
||||||
static void *
|
|
||||||
vips_stats_start( VipsStatistic *statistic )
|
|
||||||
{
|
|
||||||
return( (void *) g_new0( double, 1 ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Stop function. Add this little sum to the main sum.
|
|
||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
vips_stats_stop( VipsStatistic *statistic, void *seq )
|
vips_stats_stop( VipsStatistic *statistic, void *seq )
|
||||||
{
|
{
|
||||||
VipsStats *stats = (VipsStats *) statistic;
|
int bands = vips_image_get_bands( statistic->in->Bands );
|
||||||
double *sum = (double *) seq;
|
VipsStats *global = (VipsStats *) statistic;
|
||||||
|
VipsStats *local = (VipsStats *) seq;
|
||||||
|
|
||||||
stats->sum += *sum;
|
int b;
|
||||||
|
|
||||||
g_free( seq );
|
if( local->set && !global->set ) {
|
||||||
|
for( b = 0; b < bands; b++ ) {
|
||||||
|
double *p = ARY( local->out, 0, b + 1 );
|
||||||
|
double *q = ARY( global->out, 0, b + 1 );
|
||||||
|
|
||||||
|
p[COL_MIN] = q[COL_MIN];
|
||||||
|
p[COL_MAX] = q[COL_MAX];
|
||||||
|
p[COL_SUM] = q[COL_SUM];
|
||||||
|
p[COL_SUM2] = q[COL_SUM2];
|
||||||
|
}
|
||||||
|
|
||||||
|
global->set = TRUE;
|
||||||
|
}
|
||||||
|
else if( local->set && global->set ) {
|
||||||
|
for( b = 0; b < bands; b++ ) {
|
||||||
|
double *p = ARY( local->out, 0, b + 1 );
|
||||||
|
double *q = ARY( global->out, 0, b + 1 );
|
||||||
|
|
||||||
|
q[COL_MIN] = VIPS_MIN( q[COL_MIN], p[COL_MIN] );
|
||||||
|
q[COL_MAX] = VIPS_MAX( q[COL_MAX], p[COL_MAX] );
|
||||||
|
q[COL_SUM] += p[COL_SUM];
|
||||||
|
q[COL_SUM2] += p[COL_SUM2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VIPS_FREEF( g_object_unref, local->out );
|
||||||
|
VIPS_FREEF( g_free, seq );
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Sum pels in this section.
|
/* Start function: make a dummy local stats for the private use of this thread.
|
||||||
*/
|
*/
|
||||||
#define LOOP( TYPE ) { \
|
static void *
|
||||||
TYPE *p = (TYPE *) in; \
|
vips_stats_start( VipsStatistic *statistic )
|
||||||
\
|
{
|
||||||
for( i = 0; i < sz; i++ ) \
|
int bands = vips_image_get_bands( statistic->in->Bands );
|
||||||
m += p[i]; \
|
|
||||||
|
VipsStats *stats;
|
||||||
|
|
||||||
|
stats = g_new( VipsStats, 1 );
|
||||||
|
if( !(stats->out = vips_image_new_array( COL_LAST, bands + 1 )) ) {
|
||||||
|
g_free( stats );
|
||||||
|
return( NULL );
|
||||||
|
}
|
||||||
|
stats->set = FALSE;
|
||||||
|
|
||||||
|
return( (void *) stats );
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CLOOP( TYPE ) { \
|
/* We scan lines bands times to avoid repeating band loops.
|
||||||
TYPE *p = (TYPE *) in; \
|
* Use temp variables of same type for min/max for faster comparisons.
|
||||||
|
*/
|
||||||
|
#define LOOP( TYPE ) { \
|
||||||
|
for( b = 0; b < bands; b++ ) { \
|
||||||
|
TYPE *p = ((TYPE *) in) + b; \
|
||||||
|
double *q = ARY( local->out, 0, b + 1 ); \
|
||||||
|
TYPE small, big; \
|
||||||
|
double sum, sum2; \
|
||||||
\
|
\
|
||||||
for( i = 0; i < sz; i++ ) { \
|
if( local->set ) { \
|
||||||
double mod; \
|
small = q[COL_MIN]; \
|
||||||
|
big = q[COL_MAX]; \
|
||||||
|
sum = q[COL_SUM]; \
|
||||||
|
sum2 = q[COL_SUM2]; \
|
||||||
|
} \
|
||||||
|
else { \
|
||||||
|
small = p[0]; \
|
||||||
|
big = p[0]; \
|
||||||
|
sum = 0; \
|
||||||
|
sum2 = 0; \
|
||||||
|
} \
|
||||||
\
|
\
|
||||||
mod = p[0] * p[0] + p[1] * p[1]; \
|
for( i = 0; i < n; i++ ) { \
|
||||||
p += 2; \
|
TYPE value = *p; \
|
||||||
\
|
\
|
||||||
m += mod; \
|
sum += value;\
|
||||||
|
sum2 += (double) value * (double) value;\
|
||||||
|
if( value > big ) \
|
||||||
|
big = value; \
|
||||||
|
else if( value < small ) \
|
||||||
|
small = value;\
|
||||||
|
\
|
||||||
|
p += bands; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
q[COL_MIN] = small; \
|
||||||
|
q[COL_MAX] = big; \
|
||||||
|
q[COL_SUM] = sum; \
|
||||||
|
q[COL_SUM2] = sum2; \
|
||||||
|
local->set = TRUE; \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,17 +279,11 @@ static int
|
|||||||
vips_stats_scan( VipsStatistic *statistic, void *seq,
|
vips_stats_scan( VipsStatistic *statistic, void *seq,
|
||||||
int x, int y, void *in, int n )
|
int x, int y, void *in, int n )
|
||||||
{
|
{
|
||||||
const int sz = n * vips_image_get_bands( statistic->in );
|
const int bands = vips_image_get_bands( statistic->in );
|
||||||
|
VipsStats *local = (VipsStats *) seq;
|
||||||
|
|
||||||
double *sum = (double *) seq;
|
int b, i;
|
||||||
|
|
||||||
int i;
|
|
||||||
double m;
|
|
||||||
|
|
||||||
m = *sum;
|
|
||||||
|
|
||||||
/* Now generate code for all types.
|
|
||||||
*/
|
|
||||||
switch( vips_image_get_format( statistic->in ) ) {
|
switch( vips_image_get_format( statistic->in ) ) {
|
||||||
case VIPS_FORMAT_UCHAR: LOOP( unsigned char ); break;
|
case VIPS_FORMAT_UCHAR: LOOP( unsigned char ); break;
|
||||||
case VIPS_FORMAT_CHAR: LOOP( signed char ); break;
|
case VIPS_FORMAT_CHAR: LOOP( signed char ); break;
|
||||||
@ -206,15 +293,11 @@ vips_stats_scan( VipsStatistic *statistic, void *seq,
|
|||||||
case VIPS_FORMAT_INT: LOOP( signed int ); break;
|
case VIPS_FORMAT_INT: LOOP( signed int ); break;
|
||||||
case VIPS_FORMAT_FLOAT: LOOP( float ); break;
|
case VIPS_FORMAT_FLOAT: LOOP( float ); break;
|
||||||
case VIPS_FORMAT_DOUBLE: LOOP( double ); break;
|
case VIPS_FORMAT_DOUBLE: LOOP( double ); break;
|
||||||
case VIPS_FORMAT_COMPLEX: CLOOP( float ); break;
|
|
||||||
case VIPS_FORMAT_DPCOMPLEX: CLOOP( double ); break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
g_assert( 0 );
|
g_assert( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
*sum = m;
|
|
||||||
|
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -238,7 +321,7 @@ vips_stats_class_init( VipsStatsClass *class )
|
|||||||
|
|
||||||
VIPS_ARG_IMAGE( class, "out", 100,
|
VIPS_ARG_IMAGE( class, "out", 100,
|
||||||
_( "Output" ),
|
_( "Output" ),
|
||||||
_( "Output image" ),
|
_( "Output array of statistics" ),
|
||||||
VIPS_ARGUMENT_REQUIRED_OUTPUT,
|
VIPS_ARGUMENT_REQUIRED_OUTPUT,
|
||||||
G_STRUCT_OFFSET( VipsStats, out ) );
|
G_STRUCT_OFFSET( VipsStats, out ) );
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user