im_histcum() as a class

This commit is contained in:
John Cupitt 2013-08-13 14:22:25 +01:00
parent c60b75aed2
commit 4e9ed44432
10 changed files with 147 additions and 150 deletions

View File

@ -3,7 +3,7 @@
- rename image arrays as image matrices ... INTERPRETATION_ARRAY ->
INTERPRETATION_MATRIX etc.
- rewrite im_buildlut(), im_identity*(), im_maplut(), im_falsecolour(),
im_gammacorrect(), im_histgr() as classes
im_gammacorrect(), im_histgr(), im_histcum() 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

View File

@ -3324,6 +3324,23 @@ im_maplut( IMAGE *in, IMAGE *out, IMAGE *lut )
return( 0 );
}
int
im_histcum( IMAGE *in, IMAGE *out )
{
VipsImage *x;
if( vips_hist_cum( in, &x, NULL ) )
return( -1 );
if( im_copy( x, out ) ) {
g_object_unref( x );
return( -1 );
}
g_object_unref( x );
return( 0 );
}
int
im_hist( IMAGE *in, IMAGE *out, int bandno )
{

View File

@ -2,6 +2,7 @@ noinst_LTLIBRARIES = libhistogram.la
libhistogram_la_SOURCES = \
maplut.c \
hist_cum.c \
histogram.c \
phistogram.h \
hist_dispatch.c \

View File

@ -62,10 +62,15 @@
#include "phistogram.h"
typedef VipsHistogram VipsHistCum;
typedef VipsHistogramClass VipsHistCumClass;
G_DEFINE_TYPE( VipsHistCum, vips_hist_cum, VIPS_TYPE_HISTOGRAM );
#define ACCUMULATE( ITYPE, OTYPE ) { \
for( b = 0; b < nb; b++ ) { \
ITYPE *p = (ITYPE *) in->data; \
OTYPE *q = (OTYPE *) outbuf; \
ITYPE *p = (ITYPE *) in; \
OTYPE *q = (OTYPE *) out; \
OTYPE total; \
\
total = 0; \
@ -76,74 +81,99 @@
} \
}
/**
* im_histcum:
* @in: input image
* @out: output image
*
* Form cumulative histogram.
*
* See also: im_histnorm().
*
* Returns: 0 on success, -1 on error
*/
int
im_histcum( IMAGE *in, IMAGE *out )
static void
vips_hist_cum_buffer( VipsHistogram *histogram,
VipsPel *out, VipsPel *in, int width )
{
const guint64 px = VIPS_IMAGE_N_PELS( in );
const int nb = vips_bandfmt_iscomplex( in->BandFmt ) ?
in->Bands * 2 : in->Bands;
const guint64 mx = px * nb;
const int bands = vips_image_get_bands( histogram->in );
const int nb = vips_bandfmt_iscomplex( histogram->in->BandFmt ) ?
bands * 2 : bands;
int mx = width * nb;
VipsPel *outbuf;
guint64 b, x;
int x, b;
if( im_check_uncoded( "im_histcum", in ) ||
im_check_hist( "im_histcum", in ) ||
im_iocheck( in, out ) )
return( -1 );
if( im_cp_desc( out, in ) )
return( -1 );
out->Xsize = px;
out->Ysize = 1;
if( vips_bandfmt_isuint( in->BandFmt ) )
out->BandFmt = IM_BANDFMT_UINT;
else if( vips_bandfmt_isint( in->BandFmt ) )
out->BandFmt = IM_BANDFMT_INT;
if( im_setupout( out ) )
return( -1 );
if( !(outbuf = im_malloc( out, IM_IMAGE_SIZEOF_LINE( out ))) )
return( -1 );
switch( in->BandFmt ) {
case IM_BANDFMT_CHAR:
switch( vips_image_get_format( histogram->in ) ) {
case VIPS_FORMAT_CHAR:
ACCUMULATE( signed char, signed int ); break;
case IM_BANDFMT_UCHAR:
case VIPS_FORMAT_UCHAR:
ACCUMULATE( unsigned char, unsigned int ); break;
case IM_BANDFMT_SHORT:
case VIPS_FORMAT_SHORT:
ACCUMULATE( signed short, signed int ); break;
case IM_BANDFMT_USHORT:
case VIPS_FORMAT_USHORT:
ACCUMULATE( unsigned short, unsigned int ); break;
case IM_BANDFMT_INT:
case VIPS_FORMAT_INT:
ACCUMULATE( signed int, signed int ); break;
case IM_BANDFMT_UINT:
case VIPS_FORMAT_UINT:
ACCUMULATE( unsigned int, unsigned int ); break;
case IM_BANDFMT_FLOAT:
case IM_BANDFMT_COMPLEX:
case VIPS_FORMAT_FLOAT:
case VIPS_FORMAT_COMPLEX:
ACCUMULATE( float, float ); break;
case IM_BANDFMT_DOUBLE:
case IM_BANDFMT_DPCOMPLEX:
case VIPS_FORMAT_DOUBLE:
case VIPS_FORMAT_DPCOMPLEX:
ACCUMULATE( double, double ); break;
default:
g_assert( 0 );
}
if( im_writeline( 0, out, outbuf ) )
return( -1 );
return( 0 );
}
/* Save a bit of typing.
*/
#define UC VIPS_FORMAT_UCHAR
#define C VIPS_FORMAT_CHAR
#define US VIPS_FORMAT_USHORT
#define S VIPS_FORMAT_SHORT
#define UI VIPS_FORMAT_UINT
#define I VIPS_FORMAT_INT
#define F VIPS_FORMAT_FLOAT
#define X VIPS_FORMAT_COMPLEX
#define D VIPS_FORMAT_DOUBLE
#define DX VIPS_FORMAT_DPCOMPLEX
static const VipsBandFormat vips_bandfmt_hist_cum[10] = {
/* UC C US S UI I F X D DX */
UI, I, UI, I, UI, I, F, F, D, D
};
static void
vips_hist_cum_class_init( VipsHistCumClass *class )
{
VipsObjectClass *object_class = (VipsObjectClass *) class;
VipsHistogramClass *hclass = VIPS_HISTOGRAM_CLASS( class );
object_class->nickname = "hist_cum";
object_class->description = _( "form cumulative histogram" );
hclass->format_table = vips_bandfmt_hist_cum;
hclass->process = vips_hist_cum_buffer;
}
static void
vips_hist_cum_init( VipsHistCum *hist_cum )
{
}
/**
* vips_hist_cum:
* @in: input image
* @out: output image
*
* Form cumulative histogram.
*
* See also: vips_hist_norm().
*
* Returns: 0 on success, -1 on error
*/
int
vips_hist_cum( VipsImage *in, VipsImage **out, ... )
{
va_list ap;
int result;
va_start( ap, out );
result = vips_call_split( "hist_cum", ap, in, out );
va_end( ap );
return( result );
}

View File

@ -80,6 +80,9 @@ vips_histogram_build( VipsObject *object )
{
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
VipsHistogram *histogram = VIPS_HISTOGRAM( object );
VipsHistogramClass *hclass = VIPS_HISTOGRAM_GET_CLASS( histogram );
VipsPel *outbuf;
#ifdef DEBUG
printf( "vips_histogram_build: " );
@ -87,12 +90,34 @@ vips_histogram_build( VipsObject *object )
printf( "\n" );
#endif /*DEBUG*/
g_object_set( histogram, "out", vips_image_new(), NULL );
if( VIPS_OBJECT_CLASS( vips_histogram_parent_class )->build( object ) )
return( -1 );
if( vips_check_hist( class->nickname, histogram->in ) )
g_object_set( histogram, "out", vips_image_new(), NULL );
if( vips_check_hist( class->nickname, histogram->in ) ||
vips_check_uncoded( class->nickname, histogram->in ) )
return( -1 );
if( vips_image_wio_input( histogram->in ) ||
vips_image_copy_fields( histogram->out, histogram->in ) )
return( -1 );
histogram->out->Xsize = VIPS_IMAGE_N_PELS( histogram->in );
histogram->out->Ysize = 1;
if( hclass->format_table )
histogram->out->BandFmt =
hclass->format_table[histogram->in->BandFmt];
if( !(outbuf = vips_malloc( object,
VIPS_IMAGE_SIZEOF_LINE( histogram->out ))) )
return( -1 );
hclass->process( histogram,
outbuf, VIPS_IMAGE_ADDR( histogram->in, 0, 0 ),
histogram->in->Xsize );
if( vips_image_write_line( histogram->out, 0, outbuf ) )
return( -1 );
return( 0 );
@ -137,6 +162,8 @@ void
vips_histogram_operation_init( void )
{
extern GType vips_maplut_get_type( void );
extern GType vips_hist_cum_get_type( void );
vips_maplut_get_type();
vips_hist_cum_get_type();
}

View File

@ -58,93 +58,6 @@
#include <vips/vips.h>
#define ACCUMULATE( ITYPE, OTYPE ) { \
for( b = 0; b < nb; b++ ) { \
ITYPE *p = (ITYPE *) in->data; \
OTYPE *q = (OTYPE *) outbuf; \
OTYPE total; \
\
total = 0; \
for( x = b; x < mx; x += nb ) { \
total += p[x]; \
q[x] = total; \
} \
} \
}
/**
* im_histcum:
* @in: input image
* @out: output image
*
* Form cumulative histogram.
*
* See also: im_histnorm().
*
* Returns: 0 on success, -1 on error
*/
int
im_histcum( IMAGE *in, IMAGE *out )
{
const guint64 px = VIPS_IMAGE_N_PELS( in );
const int nb = vips_bandfmt_iscomplex( in->BandFmt ) ?
in->Bands * 2 : in->Bands;
const guint64 mx = px * nb;
VipsPel *outbuf;
guint64 b, x;
if( im_check_uncoded( "im_histcum", in ) ||
im_check_hist( "im_histcum", in ) ||
im_iocheck( in, out ) )
return( -1 );
if( im_cp_desc( out, in ) )
return( -1 );
out->Xsize = px;
out->Ysize = 1;
if( vips_bandfmt_isuint( in->BandFmt ) )
out->BandFmt = IM_BANDFMT_UINT;
else if( vips_bandfmt_isint( in->BandFmt ) )
out->BandFmt = IM_BANDFMT_INT;
if( im_setupout( out ) )
return( -1 );
if( !(outbuf = im_malloc( out, IM_IMAGE_SIZEOF_LINE( out ))) )
return( -1 );
switch( in->BandFmt ) {
case IM_BANDFMT_CHAR:
ACCUMULATE( signed char, signed int ); break;
case IM_BANDFMT_UCHAR:
ACCUMULATE( unsigned char, unsigned int ); break;
case IM_BANDFMT_SHORT:
ACCUMULATE( signed short, signed int ); break;
case IM_BANDFMT_USHORT:
ACCUMULATE( unsigned short, unsigned int ); break;
case IM_BANDFMT_INT:
ACCUMULATE( signed int, signed int ); break;
case IM_BANDFMT_UINT:
ACCUMULATE( unsigned int, unsigned int ); break;
case IM_BANDFMT_FLOAT:
case IM_BANDFMT_COMPLEX:
ACCUMULATE( float, float ); break;
case IM_BANDFMT_DOUBLE:
case IM_BANDFMT_DPCOMPLEX:
ACCUMULATE( double, double ); break;
default:
g_assert( 0 );
}
if( im_writeline( 0, out, outbuf ) )
return( -1 );
return( 0 );
}
/**
* im_histnorm:
* @in: input image

View File

@ -52,6 +52,10 @@ extern "C" {
(G_TYPE_INSTANCE_GET_CLASS( (obj), \
VIPS_TYPE_HISTOGRAM, VipsHistogramClass ))
struct _VipsHistogram;
typedef void (*VipsHistogramProcessFn)( struct _VipsHistogram *histogram,
VipsPel *out, VipsPel *in, int width );
typedef struct _VipsHistogram {
VipsOperation parent_instance;
@ -66,6 +70,11 @@ typedef struct _VipsHistogram {
typedef struct _VipsHistogramClass {
VipsOperationClass parent_class;
/* For each input format, what output format.
*/
const VipsBandFormat *format_table;
VipsHistogramProcessFn process;
} VipsHistogramClass;
GType vips_histogram_get_type( void );

View File

@ -40,6 +40,8 @@ extern "C" {
int vips_maplut( VipsImage *in, VipsImage **out, VipsImage *lut, ... )
__attribute__((sentinel));
int vips_hist_cum( VipsImage *in, VipsImage **out, ... )
__attribute__((sentinel));
int im_histnD( VipsImage *in, VipsImage *out, int bins );
@ -49,7 +51,6 @@ int im_invertlut( DOUBLEMASK *input, VipsImage *output, int lut_size );
int im_project( VipsImage *in, VipsImage *hout, VipsImage *vout );
int im_histnorm( VipsImage *in, VipsImage *out );
int im_histcum( VipsImage *in, VipsImage *out );
int im_histeq( VipsImage *in, VipsImage *out );
int im_histspec( VipsImage *in, VipsImage *ref, VipsImage *out );
int im_ismonotonic( VipsImage *lut, int *out );

View File

@ -852,6 +852,7 @@ int im_quadratic( IMAGE *in, IMAGE *out, IMAGE *coeff );
int im_maplut( VipsImage *in, VipsImage *out, VipsImage *lut );
int im_hist( VipsImage *in, VipsImage *out, int bandno );
int im_histgr( VipsImage *in, VipsImage *out, int bandno );
int im_histcum( VipsImage *in, VipsImage *out );
/* ruby-vips uses this
*/

View File

@ -1923,8 +1923,6 @@ vips_image_write_prepare( VipsImage *image )
break;
case VIPS_IMAGE_SETBUF:
/* Allocate memory.
*/
if( !image->data &&
!(image->data = vips_tracked_malloc(
VIPS_IMAGE_SIZEOF_IMAGE( image ))) )