more im_histindexed() to a class
This commit is contained in:
parent
f0359b7f38
commit
13cf12f0df
@ -4,7 +4,7 @@
|
||||
INTERPRETATION_MATRIX etc.
|
||||
- rewrite im_buildlut(), im_identity*(), im_maplut(), im_falsecolour(),
|
||||
im_gammacorrect(), im_histgr(), im_histcum(), im_histnorm(), im_heq(),
|
||||
im_histnD() as classes
|
||||
im_histnD(), im_histindexed() as classes
|
||||
- added vips_error_freeze() / vips_error_thaw()
|
||||
- used freeze() / thaw() to stop file format sniffers logging spurious errors
|
||||
- vipsthumbnail uses embedded jpg thumbnails if it can
|
||||
|
@ -17,6 +17,7 @@ libarithmetic_la_SOURCES = \
|
||||
max.c \
|
||||
hist_find.c \
|
||||
hist_find_ndim.c \
|
||||
hist_find_indexed.c \
|
||||
subtract.c \
|
||||
math.c \
|
||||
arithmetic.c \
|
||||
|
@ -692,6 +692,7 @@ vips_arithmetic_operation_init( void )
|
||||
extern GType vips_stats_get_type( void );
|
||||
extern GType vips_hist_find_get_type( void );
|
||||
extern GType vips_hist_find_ndim_get_type( void );
|
||||
extern GType vips_hist_find_indexed_get_type( void );
|
||||
extern GType vips_measure_get_type( void );
|
||||
extern GType vips_round_get_type( void );
|
||||
extern GType vips_relational_get_type( void );
|
||||
@ -723,6 +724,7 @@ vips_arithmetic_operation_init( void )
|
||||
vips_stats_get_type();
|
||||
vips_hist_find_get_type();
|
||||
vips_hist_find_ndim_get_type();
|
||||
vips_hist_find_indexed_get_type();
|
||||
vips_measure_get_type();
|
||||
vips_round_get_type();
|
||||
vips_relational_get_type();
|
||||
|
@ -367,12 +367,11 @@ vips_hist_find_scan( VipsStatistic *statistic, void *seq,
|
||||
*/
|
||||
#define UC VIPS_FORMAT_UCHAR
|
||||
#define US VIPS_FORMAT_USHORT
|
||||
#define UI VIPS_FORMAT_UINT
|
||||
|
||||
/* Type mapping: go to uchar or ushort.
|
||||
*/
|
||||
static const VipsBandFormat bandfmt_histgr[10] = {
|
||||
/* UC C US S UI I F X D DX */
|
||||
/* UC C US S UI I F X D DX */
|
||||
UC, UC, US, US, US, US, US, US, US, US
|
||||
};
|
||||
|
||||
@ -431,7 +430,7 @@ vips_hist_find_init( VipsHistFind *hist_find )
|
||||
*
|
||||
* @in is cast to u8 or u16. @out is always u32.
|
||||
*
|
||||
* See also: vips_hist_find_indexed().
|
||||
* See also: vips_hist_find_ndim(), vips_hist_find_indexed().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
|
@ -48,22 +48,29 @@
|
||||
|
||||
#include "statistic.h"
|
||||
|
||||
struct _VipsHistFindIndexed;
|
||||
|
||||
/* Accumulate a histogram in one of these.
|
||||
*/
|
||||
typedef struct {
|
||||
REGION *vreg; /* Get index pixels with this */
|
||||
struct _VipsHistFindIndexed *indexed;
|
||||
|
||||
VipsRegion *reg; /* Get index pixels with this */
|
||||
|
||||
int bands; /* Number of bands in output */
|
||||
int size; /* Length of bins */
|
||||
int mx; /* Maximum value we have seen */
|
||||
double *bins; /* All the bins! */
|
||||
} Histogram;
|
||||
|
||||
typedef struct _VipsHistFind {
|
||||
typedef struct _VipsHistFindIndexed {
|
||||
VipsStatistic parent_instance;
|
||||
|
||||
VipsImage *index;
|
||||
|
||||
/* Index image, cast to uchar/ushort.
|
||||
*/
|
||||
VipsImage *index_ready;
|
||||
|
||||
/* Main image histogram. Subhists accumulate to this.
|
||||
*/
|
||||
Histogram *hist;
|
||||
@ -72,83 +79,140 @@ typedef struct _VipsHistFind {
|
||||
*/
|
||||
VipsImage *out;
|
||||
|
||||
} VipsHistFind;
|
||||
} VipsHistFindIndexed;
|
||||
|
||||
typedef VipsStatisticClass VipsHistFindClass;
|
||||
typedef VipsStatisticClass VipsHistFindIndexedClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsHistFind, vips_hist_find, VIPS_TYPE_STATISTIC );
|
||||
G_DEFINE_TYPE( VipsHistFindIndexed,
|
||||
vips_hist_find_indexed, VIPS_TYPE_STATISTIC );
|
||||
|
||||
/* Free a Histogram.
|
||||
*/
|
||||
static void
|
||||
histogram_free( Histogram *hist )
|
||||
{
|
||||
IM_FREE( hist->bins );
|
||||
IM_FREEF( im_region_free, hist->vreg );
|
||||
IM_FREE( hist );
|
||||
}
|
||||
|
||||
/* Build a Histogram.
|
||||
*/
|
||||
static Histogram *
|
||||
histogram_new( IMAGE *index, IMAGE *value, IMAGE *out, int bands, int size )
|
||||
histogram_new( VipsHistFindIndexed *indexed )
|
||||
{
|
||||
VipsStatistic *statistic = VIPS_STATISTIC( indexed );
|
||||
int bands = statistic->ready->Bands;
|
||||
Histogram *hist;
|
||||
|
||||
if( !(hist = IM_NEW( NULL, Histogram )) )
|
||||
if( !(hist = VIPS_NEW( indexed, Histogram )) )
|
||||
return( NULL );
|
||||
|
||||
hist->index = index;
|
||||
hist->value = value;
|
||||
hist->out = out;
|
||||
hist->vreg = NULL;
|
||||
hist->bands = bands;
|
||||
hist->size = size;
|
||||
hist->indexed = indexed;
|
||||
hist->reg = NULL;
|
||||
hist->size = indexed->index_ready->BandFmt == VIPS_FORMAT_UCHAR ?
|
||||
256 : 65536;
|
||||
hist->mx = 0;
|
||||
hist->bins = NULL;
|
||||
|
||||
if( !(hist->bins = IM_ARRAY( NULL, bands * size, double )) ||
|
||||
!(hist->vreg = im_region_create( value )) ) {
|
||||
hist_free( hist );
|
||||
if( !(hist->bins = VIPS_ARRAY( indexed, bands * hist->size, double )) ||
|
||||
!(hist->reg = vips_region_new( indexed->index_ready )) )
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
memset( hist->bins, 0, bands * size * sizeof( double ) );
|
||||
memset( hist->bins, 0, bands * hist->size * sizeof( double ) );
|
||||
|
||||
return( hist );
|
||||
}
|
||||
|
||||
/* Build a sub-hist, based on the main hist.
|
||||
/* Save a bit of typing.
|
||||
*/
|
||||
static void *
|
||||
hist_start( IMAGE *out, void *a, void *b )
|
||||
{
|
||||
Histogram *mhist = (Histogram *) a;
|
||||
#define UC VIPS_FORMAT_UCHAR
|
||||
#define US VIPS_FORMAT_USHORT
|
||||
|
||||
return( (void *)
|
||||
hist_build( mhist->index, mhist->value, mhist->out,
|
||||
mhist->bands, mhist->size ) );
|
||||
/* Type mapping: go to uchar or ushort.
|
||||
*/
|
||||
static const VipsBandFormat vips_hist_find_indexed_format[10] = {
|
||||
/* UC C US S UI I F X D DX */
|
||||
UC, UC, US, US, US, US, US, US, US, US
|
||||
};
|
||||
|
||||
static int
|
||||
vips_hist_find_indexed_build( VipsObject *object )
|
||||
{
|
||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
||||
VipsStatistic *statistic = VIPS_STATISTIC( object );
|
||||
VipsHistFindIndexed *indexed = (VipsHistFindIndexed *) object;
|
||||
VipsImage **t = (VipsImage **) vips_object_local_array( object, 1 );
|
||||
|
||||
g_object_set( object,
|
||||
"out", vips_image_new(),
|
||||
NULL );
|
||||
|
||||
/* main hist made on first thread start.
|
||||
*/
|
||||
|
||||
/* index image must be cast to uchar/ushort.
|
||||
*/
|
||||
if( indexed->index &&
|
||||
statistic->in ) {
|
||||
if( vips_check_uncoded( class->nickname, indexed->index ) ||
|
||||
vips_check_size_same( class->nickname,
|
||||
indexed->index, statistic->in ) ||
|
||||
vips_check_mono( class->nickname, indexed->index ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_cast( indexed->index, &t[0],
|
||||
vips_hist_find_indexed_format[indexed->index->BandFmt],
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
|
||||
indexed->index_ready = t[0];
|
||||
}
|
||||
|
||||
if( VIPS_OBJECT_CLASS( vips_hist_find_indexed_parent_class )->
|
||||
build( object ) )
|
||||
return( -1 );
|
||||
|
||||
VIPS_UNREF( indexed->hist->reg );
|
||||
|
||||
if( vips_image_copy_fieldsv( indexed->out,
|
||||
statistic->ready, indexed->index_ready, NULL ) )
|
||||
return( -1 );
|
||||
vips_image_init_fields( indexed->out,
|
||||
indexed->hist->mx + 1, 1, statistic->ready->Bands,
|
||||
VIPS_FORMAT_DOUBLE, VIPS_CODING_NONE,
|
||||
VIPS_INTERPRETATION_HISTOGRAM, 1.0, 1.0 );
|
||||
|
||||
if( vips_image_write_line( indexed->out, 0,
|
||||
(VipsPel *) indexed->hist->bins ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Join a sub-hist onto the main hist, then free it.
|
||||
static void *
|
||||
vips_hist_find_indexed_start( VipsStatistic *statistic )
|
||||
{
|
||||
VipsHistFindIndexed *indexed = (VipsHistFindIndexed *) statistic;
|
||||
|
||||
/* Make the main hist, if necessary.
|
||||
*/
|
||||
if( !indexed->hist )
|
||||
indexed->hist = histogram_new( indexed );
|
||||
|
||||
return( (void *) histogram_new( indexed ) );
|
||||
}
|
||||
|
||||
/* Join a sub-hist onto the main hist.
|
||||
*/
|
||||
static int
|
||||
hist_stop( void *seq, void *a, void *b )
|
||||
vips_hist_find_indexed_stop( VipsStatistic *statistic, void *seq )
|
||||
{
|
||||
Histogram *shist = (Histogram *) seq;
|
||||
Histogram *mhist = (Histogram *) a;
|
||||
int i;
|
||||
Histogram *sub_hist = (Histogram *) seq;
|
||||
VipsHistFindIndexed *indexed = (VipsHistFindIndexed *) statistic;
|
||||
Histogram *hist = indexed->hist;
|
||||
int bands = statistic->ready->Bands;
|
||||
|
||||
g_assert( shist->bands == mhist->bands && shist->size == mhist->size );
|
||||
int i;
|
||||
|
||||
/* Add on sub-data.
|
||||
*/
|
||||
mhist->mx = IM_MAX( mhist->mx, shist->mx );
|
||||
for( i = 0; i < mhist->bands * mhist->size; i++ )
|
||||
mhist->bins[i] += shist->bins[i];
|
||||
hist->mx = VIPS_MAX( hist->mx, sub_hist->mx );
|
||||
for( i = 0; i < bands * hist->size; i++ ) {
|
||||
hist->bins[i] += sub_hist->bins[i];
|
||||
sub_hist->bins[i] = 0;
|
||||
}
|
||||
|
||||
VIPS_UNREF( sub_hist->reg );
|
||||
|
||||
hist_free( shist );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
@ -156,9 +220,9 @@ hist_stop( void *seq, void *a, void *b )
|
||||
*/
|
||||
#define ACCUMULATE_UCHAR( TYPE ) { \
|
||||
int x, z; \
|
||||
TYPE *tv = (TYPE *) v; \
|
||||
TYPE *tv = (TYPE *) in; \
|
||||
\
|
||||
for( x = 0; x < width; x++ ) { \
|
||||
for( x = 0; x < n; x++ ) { \
|
||||
double *bin = hist->bins + i[x] * bands; \
|
||||
\
|
||||
for( z = 0; z < bands; z++ ) \
|
||||
@ -170,66 +234,48 @@ hist_stop( void *seq, void *a, void *b )
|
||||
|
||||
/* A uchar index image.
|
||||
*/
|
||||
static int
|
||||
hist_scan_uchar( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
|
||||
static void
|
||||
vips_hist_find_indexed_uchar_scan( VipsHistFindIndexed *indexed,
|
||||
Histogram *hist, void *in, void *index, int n )
|
||||
{
|
||||
Histogram *hist = (Histogram *) seq;
|
||||
Rect *r = ®->valid;
|
||||
IMAGE *value = hist->value;
|
||||
int bands = value->Bands;
|
||||
int width = r->width;
|
||||
VipsStatistic *statistic = VIPS_STATISTIC( indexed );
|
||||
int bands = statistic->ready->Bands;
|
||||
unsigned char *i = (unsigned char *) index;
|
||||
|
||||
int y;
|
||||
switch( statistic->ready->BandFmt ) {
|
||||
case VIPS_FORMAT_UCHAR:
|
||||
ACCUMULATE_UCHAR( unsigned char ); break;
|
||||
case VIPS_FORMAT_CHAR:
|
||||
ACCUMULATE_UCHAR( signed char ); break;
|
||||
case VIPS_FORMAT_USHORT:
|
||||
ACCUMULATE_UCHAR( unsigned short ); break;
|
||||
case VIPS_FORMAT_SHORT:
|
||||
ACCUMULATE_UCHAR( signed short ); break;
|
||||
case VIPS_FORMAT_UINT:
|
||||
ACCUMULATE_UCHAR( unsigned int ); break;
|
||||
case VIPS_FORMAT_INT:
|
||||
ACCUMULATE_UCHAR( signed int ); break;
|
||||
case VIPS_FORMAT_FLOAT:
|
||||
ACCUMULATE_UCHAR( float ); break;
|
||||
case VIPS_FORMAT_DOUBLE:
|
||||
ACCUMULATE_UCHAR( double ); break;
|
||||
|
||||
/* Need the correspondiing area of the value image.
|
||||
*/
|
||||
if( im_prepare( hist->vreg, r ) )
|
||||
return( -1 );
|
||||
|
||||
/* Accumulate!
|
||||
*/
|
||||
for( y = 0; y < r->height; y++ ) {
|
||||
VipsPel *i = IM_REGION_ADDR( reg, r->left, r->top + y );
|
||||
VipsPel *v = IM_REGION_ADDR( hist->vreg,
|
||||
r->left, r->top + y );
|
||||
|
||||
switch( value->BandFmt ) {
|
||||
case IM_BANDFMT_UCHAR:
|
||||
ACCUMULATE_UCHAR( unsigned char ); break;
|
||||
case IM_BANDFMT_CHAR:
|
||||
ACCUMULATE_UCHAR( signed char ); break;
|
||||
case IM_BANDFMT_USHORT:
|
||||
ACCUMULATE_UCHAR( unsigned short ); break;
|
||||
case IM_BANDFMT_SHORT:
|
||||
ACCUMULATE_UCHAR( signed short ); break;
|
||||
case IM_BANDFMT_UINT:
|
||||
ACCUMULATE_UCHAR( unsigned int ); break;
|
||||
case IM_BANDFMT_INT:
|
||||
ACCUMULATE_UCHAR( signed int ); break;
|
||||
case IM_BANDFMT_FLOAT:
|
||||
ACCUMULATE_UCHAR( float ); break;
|
||||
case IM_BANDFMT_DOUBLE:
|
||||
ACCUMULATE_UCHAR( double ); break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
|
||||
/* Max is always 255.
|
||||
*/
|
||||
hist->mx = 255;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Accumulate a buffer of pels, ushort index.
|
||||
*/
|
||||
#define ACCUMULATE_USHORT( TYPE ) { \
|
||||
int x, z; \
|
||||
TYPE *tv = (TYPE *) v; \
|
||||
TYPE *tv = (TYPE *) in; \
|
||||
\
|
||||
for( x = 0; x < width; x++ ) { \
|
||||
for( x = 0; x < n; x++ ) { \
|
||||
int ix = i[x]; \
|
||||
double *bin = hist->bins + ix * bands; \
|
||||
\
|
||||
@ -245,87 +291,118 @@ hist_scan_uchar( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
|
||||
|
||||
/* A ushort index image.
|
||||
*/
|
||||
static int
|
||||
hist_scan_ushort( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
|
||||
static void
|
||||
vips_hist_find_indexed_ushort_scan( VipsHistFindIndexed *indexed,
|
||||
Histogram *hist, void *in, void *index, int n )
|
||||
{
|
||||
Histogram *hist = (Histogram *) seq;
|
||||
Rect *r = ®->valid;
|
||||
IMAGE *value = hist->value;
|
||||
int bands = value->Bands;
|
||||
int width = r->width;
|
||||
VipsStatistic *statistic = VIPS_STATISTIC( indexed );
|
||||
int bands = statistic->ready->Bands;
|
||||
unsigned short *i = (unsigned short *) index;
|
||||
|
||||
int y, mx;
|
||||
int mx;
|
||||
|
||||
/* Need the correspondiing area of the value image.
|
||||
*/
|
||||
if( im_prepare( hist->vreg, r ) )
|
||||
return( -1 );
|
||||
|
||||
/* Accumulate!
|
||||
*/
|
||||
mx = hist->mx;
|
||||
for( y = 0; y < r->height; y++ ) {
|
||||
unsigned short *i = (unsigned short *) IM_REGION_ADDR( reg,
|
||||
r->left, r->top + y );
|
||||
VipsPel *v = IM_REGION_ADDR( hist->vreg,
|
||||
r->left, r->top + y );
|
||||
|
||||
switch( value->BandFmt ) {
|
||||
case IM_BANDFMT_UCHAR:
|
||||
ACCUMULATE_USHORT( unsigned char ); break;
|
||||
case IM_BANDFMT_CHAR:
|
||||
ACCUMULATE_USHORT( signed char ); break;
|
||||
case IM_BANDFMT_USHORT:
|
||||
ACCUMULATE_USHORT( unsigned short ); break;
|
||||
case IM_BANDFMT_SHORT:
|
||||
ACCUMULATE_USHORT( signed short ); break;
|
||||
case IM_BANDFMT_UINT:
|
||||
ACCUMULATE_USHORT( unsigned int ); break;
|
||||
case IM_BANDFMT_INT:
|
||||
ACCUMULATE_USHORT( signed int ); break;
|
||||
case IM_BANDFMT_FLOAT:
|
||||
ACCUMULATE_USHORT( float ); break;
|
||||
case IM_BANDFMT_DOUBLE:
|
||||
ACCUMULATE_USHORT( double ); break;
|
||||
switch( statistic->ready->BandFmt ) {
|
||||
case VIPS_FORMAT_UCHAR:
|
||||
ACCUMULATE_USHORT( unsigned char ); break;
|
||||
case VIPS_FORMAT_CHAR:
|
||||
ACCUMULATE_USHORT( signed char ); break;
|
||||
case VIPS_FORMAT_USHORT:
|
||||
ACCUMULATE_USHORT( unsigned short ); break;
|
||||
case VIPS_FORMAT_SHORT:
|
||||
ACCUMULATE_USHORT( signed short ); break;
|
||||
case VIPS_FORMAT_UINT:
|
||||
ACCUMULATE_USHORT( unsigned int ); break;
|
||||
case VIPS_FORMAT_INT:
|
||||
ACCUMULATE_USHORT( signed int ); break;
|
||||
case VIPS_FORMAT_FLOAT:
|
||||
ACCUMULATE_USHORT( float ); break;
|
||||
case VIPS_FORMAT_DOUBLE:
|
||||
ACCUMULATE_USHORT( double ); break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
|
||||
/* Note the maximum.
|
||||
*/
|
||||
hist->mx = mx;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
typedef void (*VipsHistFindIndexedScanFn)( VipsHistFindIndexed *indexed,
|
||||
Histogram *hist, void *in, void *index, int n );
|
||||
|
||||
static int
|
||||
hist_write( IMAGE *out, Histogram *hist )
|
||||
vips_hist_find_indexed_scan( VipsStatistic *statistic, void *seq,
|
||||
int x, int y, void *in, int n )
|
||||
{
|
||||
if( im_cp_descv( out, hist->index, hist->value, NULL ) )
|
||||
return( -1 );
|
||||
im_initdesc( out,
|
||||
hist->mx + 1, 1, hist->value->Bands,
|
||||
IM_BBITS_DOUBLE, IM_BANDFMT_DOUBLE,
|
||||
IM_CODING_NONE, IM_TYPE_HISTOGRAM, 1.0, 1.0, 0, 0 );
|
||||
if( im_setupout( out ) )
|
||||
Histogram *hist = (Histogram *) seq;
|
||||
VipsHistFindIndexed *indexed = (VipsHistFindIndexed *) statistic;
|
||||
|
||||
VipsRect r = { x, y, n, 1 };
|
||||
VipsHistFindIndexedScanFn scan;
|
||||
|
||||
/* Need the corresponding area of the index image.
|
||||
*/
|
||||
if( vips_region_prepare( hist->reg, &r ) )
|
||||
return( -1 );
|
||||
|
||||
if( im_writeline( 0, out, (VipsPel *) hist->bins ) )
|
||||
return( -1 );
|
||||
if( indexed->index_ready->BandFmt == VIPS_FORMAT_UCHAR )
|
||||
scan = vips_hist_find_indexed_uchar_scan;
|
||||
else
|
||||
scan = vips_hist_find_indexed_ushort_scan;
|
||||
|
||||
return( 0 );
|
||||
scan( indexed, hist, in, VIPS_REGION_ADDR( hist->reg, x, y ), n );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_hist_find_indexed_class_init( VipsHistFindIndexedClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = (GObjectClass *) class;
|
||||
VipsObjectClass *object_class = (VipsObjectClass *) class;
|
||||
VipsStatisticClass *sclass = VIPS_STATISTIC_CLASS( class );
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
object_class->nickname = "hist_find_indexed";
|
||||
object_class->description = _( "find indexed image histogram" );
|
||||
object_class->build = vips_hist_find_indexed_build;
|
||||
|
||||
sclass->start = vips_hist_find_indexed_start;
|
||||
sclass->scan = vips_hist_find_indexed_scan;
|
||||
sclass->stop = vips_hist_find_indexed_stop;
|
||||
|
||||
VIPS_ARG_IMAGE( class, "index", 90,
|
||||
_( "Index" ),
|
||||
_( "Index image" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsHistFindIndexed, index ) );
|
||||
|
||||
VIPS_ARG_IMAGE( class, "out", 100,
|
||||
_( "Output" ),
|
||||
_( "Output histogram" ),
|
||||
VIPS_ARGUMENT_REQUIRED_OUTPUT,
|
||||
G_STRUCT_OFFSET( VipsHistFindIndexed, out ) );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
vips_hist_find_indexed_init( VipsHistFindIndexed *hist_find )
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* im_hist_indexed:
|
||||
* @index: input image
|
||||
* @value: input image
|
||||
* vips_hist_find_indexed:
|
||||
* @in: input image
|
||||
* @index: input index image
|
||||
* @out: output image
|
||||
*
|
||||
* Make a histogram of @value, but use image @index to pick the bins. In other
|
||||
* words, element zero in @out contains the sum of all the pixels in @value
|
||||
* Make a histogram of @in, but use image @index to pick the bins. In other
|
||||
* words, element zero in @out contains the sum of all the pixels in @in
|
||||
* whose corresponding pixel in @index is zero.
|
||||
*
|
||||
* @index must have just one band and be u8 or u16. @value must be
|
||||
@ -334,56 +411,19 @@ hist_write( IMAGE *out, Histogram *hist )
|
||||
* This operation is useful in conjunction with im_label_regions(). You can
|
||||
* use it to find the centre of gravity of blobs in an image, for example.
|
||||
*
|
||||
* See also: im_histgr(), im_label_regions().
|
||||
* See also: vips_hist_find(), im_label_regions().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
im_hist_indexed( IMAGE *index, IMAGE *value, IMAGE *out )
|
||||
int
|
||||
vips_hist_find_indexed( VipsImage *in, VipsImage *index, VipsImage **out, ... )
|
||||
{
|
||||
int size; /* Length of hist */
|
||||
Histogram *mhist;
|
||||
VipsGenerateFn scanfn;
|
||||
va_list ap;
|
||||
int result;
|
||||
|
||||
/* Check images. PIO from in, WIO to out.
|
||||
*/
|
||||
if( im_pincheck( index ) ||
|
||||
im_pincheck( value ) ||
|
||||
im_outcheck( out ) ||
|
||||
im_check_uncoded( "im_hist_indexed", index ) ||
|
||||
im_check_uncoded( "im_hist_indexed", value ) ||
|
||||
im_check_noncomplex( "im_hist_indexed", value ) ||
|
||||
im_check_size_same( "im_hist_indexed", index, value ) ||
|
||||
im_check_u8or16( "im_hist_indexed", index ) ||
|
||||
im_check_mono( "im_hist_indexed", index ) )
|
||||
return( -1 );
|
||||
va_start( ap, out );
|
||||
result = vips_call_split( "hist_find_indexed", ap, in, index, out );
|
||||
va_end( ap );
|
||||
|
||||
/* Find the range of pixel values we must handle.
|
||||
*/
|
||||
if( index->BandFmt == IM_BANDFMT_UCHAR ) {
|
||||
size = 256;
|
||||
scanfn = hist_scan_uchar;
|
||||
}
|
||||
else {
|
||||
size = 65536;
|
||||
scanfn = hist_scan_ushort;
|
||||
}
|
||||
|
||||
/* Build main hist we accumulate data in.
|
||||
*/
|
||||
if( !(mhist = hist_build( index, value, out, value->Bands, size )) )
|
||||
return( -1 );
|
||||
|
||||
/* Accumulate data.
|
||||
*/
|
||||
if( vips_sink( index,
|
||||
hist_start, scanfn, hist_stop, mhist, NULL ) ||
|
||||
hist_write( out, mhist ) ) {
|
||||
hist_free( mhist );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
hist_free( mhist );
|
||||
|
||||
return( 0 );
|
||||
return( result );
|
||||
}
|
||||
|
@ -63,7 +63,6 @@ vips_statistic_scan_start( VipsImage *in, void *a, void *b )
|
||||
|
||||
return( class->start( statistic ) );
|
||||
}
|
||||
|
||||
static int
|
||||
vips_statistic_scan( VipsRegion *region,
|
||||
void *seq, void *a, void *b, gboolean *stop )
|
||||
|
@ -3439,6 +3439,23 @@ im_histnD( VipsImage *in, VipsImage *out, int bins )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_hist_indexed( VipsImage *index, VipsImage *value, VipsImage *out )
|
||||
{
|
||||
VipsImage *x;
|
||||
|
||||
if( vips_hist_find_indexed( value, index, &x, NULL ) )
|
||||
return( -1 );
|
||||
|
||||
if( im_copy( x, out ) ) {
|
||||
g_object_unref( x );
|
||||
return( -1 );
|
||||
}
|
||||
g_object_unref( x );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_falsecolour( IMAGE *in, IMAGE *out )
|
||||
{
|
||||
|
@ -12,7 +12,6 @@ libhistogram_la_SOURCES = \
|
||||
\
|
||||
hist_dispatch.c \
|
||||
im_histplot.c \
|
||||
im_histindexed.c \
|
||||
im_histspec.c \
|
||||
im_hsp.c \
|
||||
im_mpercent.c \
|
||||
|
@ -1,370 +0,0 @@
|
||||
/* indexed histogram: use an index image to pick the bins
|
||||
*
|
||||
* 13/10/09
|
||||
* - from im_histgr.c
|
||||
* 24/3/10
|
||||
* - gtkdoc
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
This file is part of VIPS.
|
||||
|
||||
VIPS is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
|
||||
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif /*HAVE_CONFIG_H*/
|
||||
#include <vips/intl.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
|
||||
/* Accumulate a histogram in one of these.
|
||||
*/
|
||||
typedef struct {
|
||||
IMAGE *index; /* Get bin number from here */
|
||||
IMAGE *value; /* Add values from here */
|
||||
IMAGE *out;
|
||||
|
||||
REGION *vreg; /* Get value pixels with this */
|
||||
|
||||
int bands; /* Number of bands in output */
|
||||
int size; /* Length of bins */
|
||||
int mx; /* Maximum value we have seen */
|
||||
double *bins; /* All the bins! */
|
||||
} Histogram;
|
||||
|
||||
/* Free a Histogram.
|
||||
*/
|
||||
static void
|
||||
hist_free( Histogram *hist )
|
||||
{
|
||||
IM_FREE( hist->bins );
|
||||
IM_FREEF( im_region_free, hist->vreg );
|
||||
IM_FREE( hist );
|
||||
}
|
||||
|
||||
/* Build a Histogram.
|
||||
*/
|
||||
static Histogram *
|
||||
hist_build( IMAGE *index, IMAGE *value, IMAGE *out, int bands, int size )
|
||||
{
|
||||
Histogram *hist;
|
||||
|
||||
if( !(hist = IM_NEW( NULL, Histogram )) )
|
||||
return( NULL );
|
||||
|
||||
hist->index = index;
|
||||
hist->value = value;
|
||||
hist->out = out;
|
||||
hist->vreg = NULL;
|
||||
hist->bands = bands;
|
||||
hist->size = size;
|
||||
hist->mx = 0;
|
||||
hist->bins = NULL;
|
||||
|
||||
if( !(hist->bins = IM_ARRAY( NULL, bands * size, double )) ||
|
||||
!(hist->vreg = im_region_create( value )) ) {
|
||||
hist_free( hist );
|
||||
return( NULL );
|
||||
}
|
||||
|
||||
memset( hist->bins, 0, bands * size * sizeof( double ) );
|
||||
|
||||
return( hist );
|
||||
}
|
||||
|
||||
/* Build a sub-hist, based on the main hist.
|
||||
*/
|
||||
static void *
|
||||
hist_start( IMAGE *out, void *a, void *b )
|
||||
{
|
||||
Histogram *mhist = (Histogram *) a;
|
||||
|
||||
return( (void *)
|
||||
hist_build( mhist->index, mhist->value, mhist->out,
|
||||
mhist->bands, mhist->size ) );
|
||||
}
|
||||
|
||||
/* Join a sub-hist onto the main hist, then free it.
|
||||
*/
|
||||
static int
|
||||
hist_stop( void *seq, void *a, void *b )
|
||||
{
|
||||
Histogram *shist = (Histogram *) seq;
|
||||
Histogram *mhist = (Histogram *) a;
|
||||
int i;
|
||||
|
||||
g_assert( shist->bands == mhist->bands && shist->size == mhist->size );
|
||||
|
||||
/* Add on sub-data.
|
||||
*/
|
||||
mhist->mx = IM_MAX( mhist->mx, shist->mx );
|
||||
for( i = 0; i < mhist->bands * mhist->size; i++ )
|
||||
mhist->bins[i] += shist->bins[i];
|
||||
|
||||
hist_free( shist );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Accumulate a buffer of pels, uchar index.
|
||||
*/
|
||||
#define ACCUMULATE_UCHAR( TYPE ) { \
|
||||
int x, z; \
|
||||
TYPE *tv = (TYPE *) v; \
|
||||
\
|
||||
for( x = 0; x < width; x++ ) { \
|
||||
double *bin = hist->bins + i[x] * bands; \
|
||||
\
|
||||
for( z = 0; z < bands; z++ ) \
|
||||
bin[z] += tv[z]; \
|
||||
\
|
||||
tv += bands; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* A uchar index image.
|
||||
*/
|
||||
static int
|
||||
hist_scan_uchar( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
|
||||
{
|
||||
Histogram *hist = (Histogram *) seq;
|
||||
Rect *r = ®->valid;
|
||||
IMAGE *value = hist->value;
|
||||
int bands = value->Bands;
|
||||
int width = r->width;
|
||||
|
||||
int y;
|
||||
|
||||
/* Need the correspondiing area of the value image.
|
||||
*/
|
||||
if( im_prepare( hist->vreg, r ) )
|
||||
return( -1 );
|
||||
|
||||
/* Accumulate!
|
||||
*/
|
||||
for( y = 0; y < r->height; y++ ) {
|
||||
VipsPel *i = IM_REGION_ADDR( reg, r->left, r->top + y );
|
||||
VipsPel *v = IM_REGION_ADDR( hist->vreg,
|
||||
r->left, r->top + y );
|
||||
|
||||
switch( value->BandFmt ) {
|
||||
case IM_BANDFMT_UCHAR:
|
||||
ACCUMULATE_UCHAR( unsigned char ); break;
|
||||
case IM_BANDFMT_CHAR:
|
||||
ACCUMULATE_UCHAR( signed char ); break;
|
||||
case IM_BANDFMT_USHORT:
|
||||
ACCUMULATE_UCHAR( unsigned short ); break;
|
||||
case IM_BANDFMT_SHORT:
|
||||
ACCUMULATE_UCHAR( signed short ); break;
|
||||
case IM_BANDFMT_UINT:
|
||||
ACCUMULATE_UCHAR( unsigned int ); break;
|
||||
case IM_BANDFMT_INT:
|
||||
ACCUMULATE_UCHAR( signed int ); break;
|
||||
case IM_BANDFMT_FLOAT:
|
||||
ACCUMULATE_UCHAR( float ); break;
|
||||
case IM_BANDFMT_DOUBLE:
|
||||
ACCUMULATE_UCHAR( double ); break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/* Max is always 255.
|
||||
*/
|
||||
hist->mx = 255;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Accumulate a buffer of pels, ushort index.
|
||||
*/
|
||||
#define ACCUMULATE_USHORT( TYPE ) { \
|
||||
int x, z; \
|
||||
TYPE *tv = (TYPE *) v; \
|
||||
\
|
||||
for( x = 0; x < width; x++ ) { \
|
||||
int ix = i[x]; \
|
||||
double *bin = hist->bins + ix * bands; \
|
||||
\
|
||||
if( ix > mx ) \
|
||||
mx = ix; \
|
||||
\
|
||||
for( z = 0; z < bands; z++ ) \
|
||||
bin[z] += tv[z]; \
|
||||
\
|
||||
tv += bands; \
|
||||
} \
|
||||
}
|
||||
|
||||
/* A ushort index image.
|
||||
*/
|
||||
static int
|
||||
hist_scan_ushort( REGION *reg, void *seq, void *a, void *b, gboolean *stop )
|
||||
{
|
||||
Histogram *hist = (Histogram *) seq;
|
||||
Rect *r = ®->valid;
|
||||
IMAGE *value = hist->value;
|
||||
int bands = value->Bands;
|
||||
int width = r->width;
|
||||
|
||||
int y, mx;
|
||||
|
||||
/* Need the correspondiing area of the value image.
|
||||
*/
|
||||
if( im_prepare( hist->vreg, r ) )
|
||||
return( -1 );
|
||||
|
||||
/* Accumulate!
|
||||
*/
|
||||
mx = hist->mx;
|
||||
for( y = 0; y < r->height; y++ ) {
|
||||
unsigned short *i = (unsigned short *) IM_REGION_ADDR( reg,
|
||||
r->left, r->top + y );
|
||||
VipsPel *v = IM_REGION_ADDR( hist->vreg,
|
||||
r->left, r->top + y );
|
||||
|
||||
switch( value->BandFmt ) {
|
||||
case IM_BANDFMT_UCHAR:
|
||||
ACCUMULATE_USHORT( unsigned char ); break;
|
||||
case IM_BANDFMT_CHAR:
|
||||
ACCUMULATE_USHORT( signed char ); break;
|
||||
case IM_BANDFMT_USHORT:
|
||||
ACCUMULATE_USHORT( unsigned short ); break;
|
||||
case IM_BANDFMT_SHORT:
|
||||
ACCUMULATE_USHORT( signed short ); break;
|
||||
case IM_BANDFMT_UINT:
|
||||
ACCUMULATE_USHORT( unsigned int ); break;
|
||||
case IM_BANDFMT_INT:
|
||||
ACCUMULATE_USHORT( signed int ); break;
|
||||
case IM_BANDFMT_FLOAT:
|
||||
ACCUMULATE_USHORT( float ); break;
|
||||
case IM_BANDFMT_DOUBLE:
|
||||
ACCUMULATE_USHORT( double ); break;
|
||||
|
||||
default:
|
||||
g_assert( 0 );
|
||||
}
|
||||
}
|
||||
|
||||
/* Note the maximum.
|
||||
*/
|
||||
hist->mx = mx;
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
hist_write( IMAGE *out, Histogram *hist )
|
||||
{
|
||||
if( im_cp_descv( out, hist->index, hist->value, NULL ) )
|
||||
return( -1 );
|
||||
im_initdesc( out,
|
||||
hist->mx + 1, 1, hist->value->Bands,
|
||||
IM_BBITS_DOUBLE, IM_BANDFMT_DOUBLE,
|
||||
IM_CODING_NONE, IM_TYPE_HISTOGRAM, 1.0, 1.0, 0, 0 );
|
||||
if( im_setupout( out ) )
|
||||
return( -1 );
|
||||
|
||||
if( im_writeline( 0, out, (VipsPel *) hist->bins ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/**
|
||||
* im_hist_indexed:
|
||||
* @index: input image
|
||||
* @value: input image
|
||||
* @out: output image
|
||||
*
|
||||
* Make a histogram of @value, but use image @index to pick the bins. In other
|
||||
* words, element zero in @out contains the sum of all the pixels in @value
|
||||
* whose corresponding pixel in @index is zero.
|
||||
*
|
||||
* @index must have just one band and be u8 or u16. @value must be
|
||||
* non-complex. @out always has the same size and format as @value.
|
||||
*
|
||||
* This operation is useful in conjunction with im_label_regions(). You can
|
||||
* use it to find the centre of gravity of blobs in an image, for example.
|
||||
*
|
||||
* See also: im_histgr(), im_label_regions().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
im_hist_indexed( IMAGE *index, IMAGE *value, IMAGE *out )
|
||||
{
|
||||
int size; /* Length of hist */
|
||||
Histogram *mhist;
|
||||
VipsGenerateFn scanfn;
|
||||
|
||||
/* Check images. PIO from in, WIO to out.
|
||||
*/
|
||||
if( im_pincheck( index ) ||
|
||||
im_pincheck( value ) ||
|
||||
im_outcheck( out ) ||
|
||||
im_check_uncoded( "im_hist_indexed", index ) ||
|
||||
im_check_uncoded( "im_hist_indexed", value ) ||
|
||||
im_check_noncomplex( "im_hist_indexed", value ) ||
|
||||
im_check_size_same( "im_hist_indexed", index, value ) ||
|
||||
im_check_u8or16( "im_hist_indexed", index ) ||
|
||||
im_check_mono( "im_hist_indexed", index ) )
|
||||
return( -1 );
|
||||
|
||||
/* Find the range of pixel values we must handle.
|
||||
*/
|
||||
if( index->BandFmt == IM_BANDFMT_UCHAR ) {
|
||||
size = 256;
|
||||
scanfn = hist_scan_uchar;
|
||||
}
|
||||
else {
|
||||
size = 65536;
|
||||
scanfn = hist_scan_ushort;
|
||||
}
|
||||
|
||||
/* Build main hist we accumulate data in.
|
||||
*/
|
||||
if( !(mhist = hist_build( index, value, out, value->Bands, size )) )
|
||||
return( -1 );
|
||||
|
||||
/* Accumulate data.
|
||||
*/
|
||||
if( vips_sink( index,
|
||||
hist_start, scanfn, hist_stop, mhist, NULL ) ||
|
||||
hist_write( out, mhist ) ) {
|
||||
hist_free( mhist );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
hist_free( mhist );
|
||||
|
||||
return( 0 );
|
||||
}
|
@ -381,6 +381,9 @@ int vips_hist_find( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_hist_find_ndim( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_hist_find_indexed( VipsImage *in, VipsImage *index,
|
||||
VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -48,8 +48,6 @@ int vips_hist_equal( VipsImage *in, VipsImage **out, ... )
|
||||
__attribute__((sentinel));
|
||||
|
||||
|
||||
int im_hist_indexed( VipsImage *index, VipsImage *value, VipsImage *out );
|
||||
|
||||
int im_invertlut( DOUBLEMASK *input, VipsImage *output, int lut_size );
|
||||
int im_project( VipsImage *in, VipsImage *hout, VipsImage *vout );
|
||||
|
||||
|
@ -857,6 +857,7 @@ int im_histnorm( VipsImage *in, VipsImage *out );
|
||||
int im_histeq( VipsImage *in, VipsImage *out );
|
||||
int im_heq( VipsImage *in, VipsImage *out, int bandno );
|
||||
int im_histnD( VipsImage *in, VipsImage *out, int bins );
|
||||
int im_hist_indexed( VipsImage *index, VipsImage *value, VipsImage *out );
|
||||
|
||||
/* ruby-vips uses this
|
||||
*/
|
||||
|
@ -324,7 +324,7 @@ vips_leak( void )
|
||||
vips_tracked_get_files() ) {
|
||||
vips_buf_appendf( &buf, "memory: %d allocations, %zd bytes\n",
|
||||
vips_tracked_get_allocs(), vips_tracked_get_mem() );
|
||||
vips_buf_appendf( &buf, "\nfiles: %d open\n",
|
||||
vips_buf_appendf( &buf, "files: %d open\n",
|
||||
vips_tracked_get_files() );
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user