Adds MEAN and MEDIAN methods for region shrink
This commit is contained in:
parent
cf36336e8e
commit
eada4a7731
@ -1401,10 +1401,10 @@ strip_shrink( Layer *layer )
|
||||
|
||||
/* None? All done.
|
||||
*/
|
||||
if( vips_rect_isempty( &target ) )
|
||||
if( vips_rect_isempty( &target ) )
|
||||
break;
|
||||
|
||||
(void) vips_region_shrink( from, to, &target );
|
||||
(void) vips_region_shrink( from, to, &target, VIPS_REGION_SHRINK_MEAN );
|
||||
|
||||
below->write_y += target.height;
|
||||
|
||||
|
@ -1389,10 +1389,10 @@ layer_strip_shrink( Layer *layer )
|
||||
|
||||
/* None? All done.
|
||||
*/
|
||||
if( vips_rect_isempty( &target ) )
|
||||
if( vips_rect_isempty( &target ) )
|
||||
break;
|
||||
|
||||
(void) vips_region_shrink( from, to, &target );
|
||||
(void) vips_region_shrink( from, to, &target, VIPS_REGION_SHRINK_MEAN );
|
||||
|
||||
below->write_y += target.height;
|
||||
|
||||
|
@ -55,6 +55,12 @@ extern "C" {
|
||||
(G_TYPE_INSTANCE_GET_CLASS( (obj), \
|
||||
VIPS_TYPE_REGION, VipsRegionClass ))
|
||||
|
||||
typedef enum {
|
||||
VIPS_REGION_SHRINK_MEAN,
|
||||
VIPS_REGION_SHRINK_MEDIAN,
|
||||
VIPS_REGION_SHRINK_LAST
|
||||
} VipsRegionShrink;
|
||||
|
||||
/* Sub-area of image.
|
||||
*/
|
||||
typedef struct _VipsRegion {
|
||||
@ -115,13 +121,14 @@ void vips_region_paint( VipsRegion *reg, const VipsRect *r, int value );
|
||||
void vips_region_paint_pel( VipsRegion *reg,
|
||||
const VipsRect *r, const VipsPel *ink );
|
||||
void vips_region_black( VipsRegion *reg );
|
||||
void vips_region_copy( VipsRegion *reg, VipsRegion *dest,
|
||||
void vips_region_copy( VipsRegion *reg, VipsRegion *dest,
|
||||
const VipsRect *r, int x, int y );
|
||||
int vips_region_shrink( VipsRegion *from,
|
||||
VipsRegion *to, const VipsRect *target );
|
||||
int vips_region_shrink( VipsRegion *from,
|
||||
VipsRegion *to, const VipsRect *target,
|
||||
VipsRegionShrink method );
|
||||
|
||||
int vips_region_prepare( VipsRegion *reg, const VipsRect *r );
|
||||
int vips_region_prepare_to( VipsRegion *reg,
|
||||
int vips_region_prepare_to( VipsRegion *reg,
|
||||
VipsRegion *dest, const VipsRect *r, int x, int y );
|
||||
|
||||
void vips_region_invalidate( VipsRegion *reg );
|
||||
|
@ -1166,7 +1166,7 @@ vips_region_shrink_labpack( VipsRegion *from,
|
||||
}
|
||||
}
|
||||
|
||||
#define SHRINK_TYPE_INT( TYPE ) \
|
||||
#define SHRINK_TYPE_MEAN_INT( TYPE ) \
|
||||
for( x = 0; x < target->width; x++ ) { \
|
||||
TYPE *tp = (TYPE *) p; \
|
||||
TYPE *tp1 = (TYPE *) (p + ls); \
|
||||
@ -1185,7 +1185,7 @@ vips_region_shrink_labpack( VipsRegion *from,
|
||||
q += ps; \
|
||||
}
|
||||
|
||||
#define SHRINK_TYPE_FLOAT( TYPE ) \
|
||||
#define SHRINK_TYPE_MEAN_FLOAT( TYPE ) \
|
||||
for( x = 0; x < target->width; x++ ) { \
|
||||
TYPE *tp = (TYPE *) p; \
|
||||
TYPE *tp1 = (TYPE *) (p + ls); \
|
||||
@ -1204,10 +1204,30 @@ vips_region_shrink_labpack( VipsRegion *from,
|
||||
q += ps; \
|
||||
}
|
||||
|
||||
// This *DOES* gurantee the result is taken from one of the input values
|
||||
// It therefore does *NOT* interpolate between the two middle values
|
||||
// It is *NOT* stable with respect to the set of values
|
||||
// It *IS* however stable with respect to the initial arrangement of values
|
||||
#define SHRINK_TYPE_MEDIAN( TYPE ) \
|
||||
for( x = 0; x < target->width; x++ ) { \
|
||||
TYPE *tp = (TYPE *) p; \
|
||||
TYPE *tp1 = (TYPE *) (p + ls); \
|
||||
TYPE *tq = (TYPE *) q; \
|
||||
\
|
||||
for( z = 0; z < nb; z++ ) { \
|
||||
tq[z] = VIPS_MIN( VIPS_MAX( tp[z], tp[z + nb] ), VIPS_MAX( tp1[z], tp1[z + nb] ) ); \
|
||||
} \
|
||||
\
|
||||
/* Move on two pels in input. \
|
||||
*/ \
|
||||
p += ps << 1; \
|
||||
q += ps; \
|
||||
}
|
||||
|
||||
/* Generate area @target in @to using pixels in @from. Non-complex.
|
||||
*/
|
||||
static void
|
||||
vips_region_shrink_uncoded( VipsRegion *from,
|
||||
vips_region_shrink_uncoded_mean( VipsRegion *from,
|
||||
VipsRegion *to, const VipsRect *target )
|
||||
{
|
||||
int ls = VIPS_REGION_LSKIP( from );
|
||||
@ -1225,22 +1245,22 @@ vips_region_shrink_uncoded( VipsRegion *from,
|
||||
/* Process this line of pels.
|
||||
*/
|
||||
switch( from->im->BandFmt ) {
|
||||
case VIPS_FORMAT_UCHAR:
|
||||
SHRINK_TYPE_INT( unsigned char ); break;
|
||||
case VIPS_FORMAT_CHAR:
|
||||
SHRINK_TYPE_INT( signed char ); break;
|
||||
case VIPS_FORMAT_USHORT:
|
||||
SHRINK_TYPE_INT( unsigned short ); break;
|
||||
case VIPS_FORMAT_SHORT:
|
||||
SHRINK_TYPE_INT( signed short ); break;
|
||||
case VIPS_FORMAT_UINT:
|
||||
SHRINK_TYPE_INT( unsigned int ); break;
|
||||
case VIPS_FORMAT_INT:
|
||||
SHRINK_TYPE_INT( signed int ); break;
|
||||
case VIPS_FORMAT_FLOAT:
|
||||
SHRINK_TYPE_FLOAT( float ); break;
|
||||
case VIPS_FORMAT_DOUBLE:
|
||||
SHRINK_TYPE_FLOAT( double ); break;
|
||||
case VIPS_FORMAT_UCHAR:
|
||||
SHRINK_TYPE_MEAN_INT( unsigned char ); break;
|
||||
case VIPS_FORMAT_CHAR:
|
||||
SHRINK_TYPE_MEAN_INT( signed char ); break;
|
||||
case VIPS_FORMAT_USHORT:
|
||||
SHRINK_TYPE_MEAN_INT( unsigned short ); break;
|
||||
case VIPS_FORMAT_SHORT:
|
||||
SHRINK_TYPE_MEAN_INT( signed short ); break;
|
||||
case VIPS_FORMAT_UINT:
|
||||
SHRINK_TYPE_MEAN_INT( unsigned int ); break;
|
||||
case VIPS_FORMAT_INT:
|
||||
SHRINK_TYPE_MEAN_INT( signed int ); break;
|
||||
case VIPS_FORMAT_FLOAT:
|
||||
SHRINK_TYPE_MEAN_FLOAT( float ); break;
|
||||
case VIPS_FORMAT_DOUBLE:
|
||||
SHRINK_TYPE_MEAN_FLOAT( double ); break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
@ -1248,6 +1268,67 @@ vips_region_shrink_uncoded( VipsRegion *from,
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate area @target in @to using pixels in @from. Non-complex.
|
||||
*/
|
||||
static void
|
||||
vips_region_shrink_uncoded_median( VipsRegion *from,
|
||||
VipsRegion *to, const VipsRect *target )
|
||||
{
|
||||
int ls = VIPS_REGION_LSKIP( from );
|
||||
int ps = VIPS_IMAGE_SIZEOF_PEL( from->im );
|
||||
int nb = from->im->Bands;
|
||||
|
||||
int x, y, z;
|
||||
|
||||
for( y = 0; y < target->height; y++ ) {
|
||||
VipsPel *p = VIPS_REGION_ADDR( from,
|
||||
target->left * 2, (target->top + y) * 2 );
|
||||
VipsPel *q = VIPS_REGION_ADDR( to,
|
||||
target->left, target->top + y );
|
||||
|
||||
/* Process this line of pels.
|
||||
*/
|
||||
switch( from->im->BandFmt ) {
|
||||
case VIPS_FORMAT_UCHAR:
|
||||
SHRINK_TYPE_MEDIAN( unsigned char ); break;
|
||||
case VIPS_FORMAT_CHAR:
|
||||
SHRINK_TYPE_MEDIAN( signed char ); break;
|
||||
case VIPS_FORMAT_USHORT:
|
||||
SHRINK_TYPE_MEDIAN( unsigned short ); break;
|
||||
case VIPS_FORMAT_SHORT:
|
||||
SHRINK_TYPE_MEDIAN( signed short ); break;
|
||||
case VIPS_FORMAT_UINT:
|
||||
SHRINK_TYPE_MEDIAN( unsigned int ); break;
|
||||
case VIPS_FORMAT_INT:
|
||||
SHRINK_TYPE_MEDIAN( signed int ); break;
|
||||
case VIPS_FORMAT_FLOAT:
|
||||
SHRINK_TYPE_MEDIAN( float ); break;
|
||||
case VIPS_FORMAT_DOUBLE:
|
||||
SHRINK_TYPE_MEDIAN( double ); break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate area @target in @to using pixels in @from. Non-complex.
|
||||
*/
|
||||
static void
|
||||
vips_region_shrink_uncoded( VipsRegion *from,
|
||||
VipsRegion *to, const VipsRect *target, VipsRegionShrink method )
|
||||
{
|
||||
switch( method ) {
|
||||
case VIPS_REGION_SHRINK_MEAN:
|
||||
vips_region_shrink_uncoded_mean( from, to, target ); break;
|
||||
case VIPS_REGION_SHRINK_MEDIAN:
|
||||
vips_region_shrink_uncoded_median( from, to, target ); break;
|
||||
|
||||
default:
|
||||
g_assert_not_reached();
|
||||
}
|
||||
}
|
||||
|
||||
/* No point having an int path, this will always be horribly slow.
|
||||
*/
|
||||
#define SHRINK_ALPHA_TYPE( TYPE ) { \
|
||||
@ -1333,9 +1414,10 @@ vips_region_shrink_alpha( VipsRegion *from,
|
||||
|
||||
/**
|
||||
* vips_region_shrink:
|
||||
* @from: source region
|
||||
* @to: (inout): destination region
|
||||
* @from: source region
|
||||
* @to: (inout): destination region
|
||||
* @target: #VipsRect of pixels you need to copy
|
||||
* @method: #VipsRegionShrink method to use when generating target pixels
|
||||
*
|
||||
* Write the pixels @target in @to from the x2 larger area in @from.
|
||||
* Non-complex uncoded images and LABQ only. Images with alpha (see
|
||||
@ -1344,7 +1426,7 @@ vips_region_shrink_alpha( VipsRegion *from,
|
||||
* See also: vips_region_copy().
|
||||
*/
|
||||
int
|
||||
vips_region_shrink( VipsRegion *from, VipsRegion *to, const VipsRect *target )
|
||||
vips_region_shrink( VipsRegion *from, VipsRegion *to, const VipsRect *target, VipsRegionShrink method )
|
||||
{
|
||||
VipsImage *image = from->im;
|
||||
|
||||
@ -1355,10 +1437,10 @@ vips_region_shrink( VipsRegion *from, VipsRegion *to, const VipsRect *target )
|
||||
if( vips_check_noncomplex( "vips_region_shrink", image ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_image_hasalpha( image ) )
|
||||
if( vips_image_hasalpha( image ) )
|
||||
vips_region_shrink_alpha( from, to, target );
|
||||
else
|
||||
vips_region_shrink_uncoded( from, to, target );
|
||||
vips_region_shrink_uncoded( from, to, target, method );
|
||||
}
|
||||
else
|
||||
vips_region_shrink_labpack( from, to, target );
|
||||
|
Loading…
Reference in New Issue
Block a user