redo im_affine as a class
This commit is contained in:
parent
43d69e74e7
commit
4c82d45463
@ -32,6 +32,7 @@
|
||||
- added scRGB colourspace, linear light float space with sRGB primaries
|
||||
- all interpolators use corner convention ... we had round-to-nearest in
|
||||
several of them before, causing a range of annoying problems
|
||||
- redone im_affine*() as a class
|
||||
|
||||
14/11/12 started 7.30.6
|
||||
- capture tiff warnings earlier
|
||||
|
@ -47,6 +47,7 @@
|
||||
#include <vips/internal.h>
|
||||
#include <vips/debug.h>
|
||||
#include <vips/vector.h>
|
||||
#include <vips/transform.h>
|
||||
|
||||
VipsImage *
|
||||
im_open( const char *filename, const char *mode )
|
||||
@ -2885,3 +2886,94 @@ im_cross_phase( IMAGE *in1, IMAGE *in2, IMAGE *out )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
im__affinei( VipsImage *in, VipsImage *out,
|
||||
VipsInterpolate *interpolate, VipsTransformation *trn )
|
||||
{
|
||||
VipsImage *x;
|
||||
VipsArea *oarea;
|
||||
|
||||
oarea = (VipsArea *) vips_array_int_newv( 4,
|
||||
trn->oarea.left, trn->oarea.top,
|
||||
trn->oarea.width, trn->oarea.height );
|
||||
|
||||
if( vips_affine( in, &x,
|
||||
trn->a, trn->b, trn->c, trn->d,
|
||||
"interpolate", interpolate,
|
||||
"oarea", oarea,
|
||||
"odx", trn->dx,
|
||||
"ody", trn->dy,
|
||||
NULL ) ) {
|
||||
vips_area_unref( oarea );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
vips_area_unref( oarea );
|
||||
|
||||
if( im_copy( x, out ) ) {
|
||||
g_object_unref( x );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
g_object_unref( x );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
int
|
||||
im_affinei( VipsImage *in, VipsImage *out, VipsInterpolate *interpolate,
|
||||
double a, double b, double c, double d, double dx, double dy,
|
||||
int ox, int oy, int ow, int oh )
|
||||
{
|
||||
VipsTransformation trn;
|
||||
|
||||
trn.iarea.left = 0;
|
||||
trn.iarea.top = 0;
|
||||
trn.iarea.width = in->Xsize;
|
||||
trn.iarea.height = in->Ysize;
|
||||
|
||||
trn.oarea.left = ox;
|
||||
trn.oarea.top = oy;
|
||||
trn.oarea.width = ow;
|
||||
trn.oarea.height = oh;
|
||||
|
||||
trn.a = a;
|
||||
trn.b = b;
|
||||
trn.c = c;
|
||||
trn.d = d;
|
||||
trn.dx = dx;
|
||||
trn.dy = dy;
|
||||
|
||||
return( im__affinei( in, out, interpolate, &trn ) );
|
||||
}
|
||||
|
||||
int
|
||||
im_affinei_all( VipsImage *in, VipsImage *out, VipsInterpolate *interpolate,
|
||||
double a, double b, double c, double d, double dx, double dy )
|
||||
{
|
||||
VipsTransformation trn;
|
||||
|
||||
trn.iarea.left = 0;
|
||||
trn.iarea.top = 0;
|
||||
trn.iarea.width = in->Xsize;
|
||||
trn.iarea.height = in->Ysize;
|
||||
trn.a = a;
|
||||
trn.b = b;
|
||||
trn.c = c;
|
||||
trn.d = d;
|
||||
trn.dx = dx;
|
||||
trn.dy = dy;
|
||||
|
||||
vips__transform_set_area( &trn );
|
||||
|
||||
return( im__affinei( in, out, interpolate, &trn ) );
|
||||
}
|
||||
|
||||
/* Still needed by some parts of mosaic.
|
||||
*/
|
||||
int
|
||||
vips__affine( VipsImage *in, VipsImage *out, VipsTransformation *trn )
|
||||
{
|
||||
return( im__affinei( in, out,
|
||||
vips_interpolate_bilinear_static(), trn ) );
|
||||
}
|
||||
|
@ -30,25 +30,13 @@
|
||||
|
||||
*/
|
||||
|
||||
#ifndef IM_RESAMPLE_H
|
||||
#define IM_RESAMPLE_H
|
||||
#ifndef VIPS_RESAMPLE_H
|
||||
#define VIPS_RESAMPLE_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
int im_affinei( VipsImage *in, VipsImage *out,
|
||||
VipsInterpolate *interpolate,
|
||||
double a, double b, double c, double d, double dx, double dy,
|
||||
int ox, int oy, int ow, int oh );
|
||||
int im_affinei_all( VipsImage *in, VipsImage *out, VipsInterpolate *interpolate,
|
||||
double a, double b, double c, double d, double dx, double dy ) ;
|
||||
|
||||
int vips_quadratic( VipsImage *in, VipsImage **out, VipsImage *coeff, ... );
|
||||
|
||||
int im_rightshift_size( VipsImage *in, VipsImage *out,
|
||||
int xshift, int yshift, int band_fmt );
|
||||
|
||||
int im_match_linear( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
int xr1, int yr1, int xs1, int ys1,
|
||||
int xr2, int yr2, int xs2, int ys2 );
|
||||
@ -59,13 +47,17 @@ int im_match_linear_search( VipsImage *ref, VipsImage *sec, VipsImage *out,
|
||||
|
||||
|
||||
|
||||
|
||||
int vips_quadratic( VipsImage *in, VipsImage **out, VipsImage *coeff, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_shrink( VipsImage *in, VipsImage **out,
|
||||
double xshrink, double yshrink, ... )
|
||||
__attribute__((sentinel));
|
||||
int vips_affine( VipsImage *in, VipsImage **out,
|
||||
double a, double b, double c, double d, ... )
|
||||
__attribute__((sentinel));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
#endif /*IM_RESAMPLE_H*/
|
||||
#endif /*VIPS_RESAMPLE_H*/
|
||||
|
@ -27,6 +27,13 @@
|
||||
|
||||
*/
|
||||
|
||||
#ifndef VIPS_TRANSFORM_H
|
||||
#define VIPS_TRANSFORM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
/* Params for an affine transformation.
|
||||
*/
|
||||
typedef struct {
|
||||
@ -46,24 +53,31 @@ typedef struct {
|
||||
double dx, dy;
|
||||
|
||||
double ia, ib, ic, id; /* Inverse of matrix abcd */
|
||||
} Transformation;
|
||||
} VipsTransformation;
|
||||
|
||||
void im__transform_init( Transformation *trn );
|
||||
int im__transform_calc_inverse( Transformation *trn );
|
||||
int im__transform_isidentity( const Transformation *trn );
|
||||
int im__transform_add( const Transformation *in1, const Transformation *in2,
|
||||
Transformation *out );
|
||||
void im__transform_print( const Transformation *trn );
|
||||
void vips__transform_init( VipsTransformation *trn );
|
||||
int vips__transform_calc_inverse( VipsTransformation *trn );
|
||||
int vips__transform_isidentity( const VipsTransformation *trn );
|
||||
int vips__transform_add( const VipsTransformation *in1,
|
||||
const VipsTransformation *in2,
|
||||
VipsTransformation *out );
|
||||
void vips__transform_print( const VipsTransformation *trn );
|
||||
|
||||
void im__transform_forward_point( const Transformation *trn,
|
||||
void vips__transform_forward_point( const VipsTransformation *trn,
|
||||
const double x, const double y, double *ox, double *oy );
|
||||
void im__transform_invert_point( const Transformation *trn,
|
||||
void vips__transform_invert_point( const VipsTransformation *trn,
|
||||
const double x, const double y, double *ox, double *oy );
|
||||
void im__transform_forward_rect( const Transformation *trn,
|
||||
void vips__transform_forward_rect( const VipsTransformation *trn,
|
||||
const VipsRect *in, VipsRect *out );
|
||||
void im__transform_invert_rect( const Transformation *trn,
|
||||
void vips__transform_invert_rect( const VipsTransformation *trn,
|
||||
const VipsRect *in, VipsRect *out );
|
||||
|
||||
void im__transform_set_area( Transformation * );
|
||||
void vips__transform_set_area( VipsTransformation * );
|
||||
|
||||
int im__affine( VipsImage *in, VipsImage *out, Transformation *trn );
|
||||
int vips__affine( VipsImage *in, VipsImage *out, VipsTransformation *trn );
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /*__cplusplus*/
|
||||
|
||||
#endif /*VIPS_TRANSFORM_H*/
|
||||
|
@ -730,6 +730,14 @@ int im_recomb( VipsImage *in, VipsImage *out, DOUBLEMASK *recomb );
|
||||
int im_argb2rgba( VipsImage *in, VipsImage *out );
|
||||
|
||||
int im_shrink( VipsImage *in, VipsImage *out, double xshrink, double yshrink );
|
||||
int im_affinei( VipsImage *in, VipsImage *out,
|
||||
VipsInterpolate *interpolate,
|
||||
double a, double b, double c, double d, double dx, double dy,
|
||||
int ox, int oy, int ow, int oh );
|
||||
int im_affinei_all( VipsImage *in, VipsImage *out, VipsInterpolate *interpolate,
|
||||
double a, double b, double c, double d, double dx, double dy ) ;
|
||||
int im_rightshift_size( VipsImage *in, VipsImage *out,
|
||||
int xshift, int yshift, int band_fmt );
|
||||
|
||||
int im_Lab2XYZ_temp( IMAGE *in, IMAGE *out, double X0, double Y0, double Z0 );
|
||||
int im_Lab2XYZ( IMAGE *in, IMAGE *out );
|
||||
|
@ -214,7 +214,7 @@ build_node( SymbolTable *st, char *name )
|
||||
node->dirty = 0;
|
||||
node->mwidth = -2;
|
||||
node->st = st;
|
||||
im__transform_init( &node->cumtrn );
|
||||
vips__transform_init( &node->cumtrn );
|
||||
node->trnim = NULL;
|
||||
node->arg1 = NULL;
|
||||
node->arg2 = NULL;
|
||||
@ -407,7 +407,7 @@ calc_geometry( JoinNode *node )
|
||||
node->cumtrn.iarea.top = 0;
|
||||
node->cumtrn.iarea.width = um.width;
|
||||
node->cumtrn.iarea.height = um.height;
|
||||
im__transform_set_area( &node->cumtrn );
|
||||
vips__transform_set_area( &node->cumtrn );
|
||||
break;
|
||||
|
||||
case JOIN_CP:
|
||||
@ -424,7 +424,7 @@ calc_geometry( JoinNode *node )
|
||||
node->cumtrn.iarea.top = 0;
|
||||
node->cumtrn.iarea.width = node->im->Xsize;
|
||||
node->cumtrn.iarea.height = node->im->Ysize;
|
||||
im__transform_set_area( &node->cumtrn );
|
||||
vips__transform_set_area( &node->cumtrn );
|
||||
}
|
||||
break;
|
||||
|
||||
@ -440,7 +440,7 @@ calc_geometry( JoinNode *node )
|
||||
* have circularity.
|
||||
*/
|
||||
static int
|
||||
propogate_transform( JoinNode *node, Transformation *trn )
|
||||
propogate_transform( JoinNode *node, VipsTransformation *trn )
|
||||
{
|
||||
if( !node )
|
||||
return( 0 );
|
||||
@ -460,7 +460,7 @@ propogate_transform( JoinNode *node, Transformation *trn )
|
||||
|
||||
/* Transform us, and recalculate our position and size.
|
||||
*/
|
||||
im__transform_add( &node->cumtrn, trn, &node->cumtrn );
|
||||
vips__transform_add( &node->cumtrn, trn, &node->cumtrn );
|
||||
calc_geometry( node );
|
||||
|
||||
return( 0 );
|
||||
@ -475,7 +475,7 @@ make_join( SymbolTable *st, JoinType type,
|
||||
JoinNode *arg1, JoinNode *arg2, JoinNode *out,
|
||||
double a, double b, double dx, double dy, int mwidth )
|
||||
{
|
||||
Transformation trn;
|
||||
VipsTransformation trn;
|
||||
|
||||
/* Check output is ok.
|
||||
*/
|
||||
@ -1528,13 +1528,13 @@ generate_trn_leaves( JoinNode *node, SymbolTable *st )
|
||||
/* Special case: if this is an untransformed leaf (there will
|
||||
* always be at least one), then skip the affine.
|
||||
*/
|
||||
if( im__transform_isidentity( &node->cumtrn ) )
|
||||
if( vips__transform_isidentity( &node->cumtrn ) )
|
||||
node->trnim = node->im;
|
||||
else
|
||||
if( !(node->trnim =
|
||||
im_open_local( node->st->im,
|
||||
"trnleaf:1", "p" )) ||
|
||||
im__affine( node->im, node->trnim,
|
||||
vips__affine( node->im, node->trnim,
|
||||
&node->cumtrn ) )
|
||||
return( node );
|
||||
}
|
||||
|
@ -83,13 +83,13 @@ struct _JoinNode {
|
||||
* cumtrn.area is position and size of us, thistrn.area is pos and
|
||||
* size of arg2.
|
||||
*/
|
||||
Transformation cumtrn;
|
||||
VipsTransformation cumtrn;
|
||||
|
||||
/* X-tras for LR/TB. thistrn is what we do to arg2.
|
||||
*/
|
||||
JoinNode *arg1; /* Left or up thing to join */
|
||||
JoinNode *arg2; /* Right or down thing to join */
|
||||
Transformation thistrn; /* Transformation for arg2 */
|
||||
VipsTransformation thistrn; /* Transformation for arg2 */
|
||||
|
||||
/* Special for leaves: all the join_nodes we overlap with, the
|
||||
* IMAGE for that file, and the index.
|
||||
|
@ -69,7 +69,7 @@
|
||||
/* Like im_similarity(), but return the transform we generated.
|
||||
*/
|
||||
static int
|
||||
apply_similarity( Transformation *trn, IMAGE *in, IMAGE *out,
|
||||
apply_similarity( VipsTransformation *trn, IMAGE *in, IMAGE *out,
|
||||
double a, double b, double dx, double dy )
|
||||
{
|
||||
trn->iarea.left = 0;
|
||||
@ -82,11 +82,11 @@ apply_similarity( Transformation *trn, IMAGE *in, IMAGE *out,
|
||||
trn->d = a;
|
||||
trn->dx = dx;
|
||||
trn->dy = dy;
|
||||
im__transform_set_area( trn );
|
||||
if( im__transform_calc_inverse( trn ) )
|
||||
vips__transform_set_area( trn );
|
||||
if( vips__transform_calc_inverse( trn ) )
|
||||
return( -1 );
|
||||
|
||||
if( im__affine( in, out, trn ) )
|
||||
if( vips__affine( in, out, trn ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
@ -103,7 +103,7 @@ int
|
||||
im__lrmerge1( IMAGE *ref, IMAGE *sec, IMAGE *out,
|
||||
double a, double b, double dx, double dy, int mwidth )
|
||||
{
|
||||
Transformation trn;
|
||||
VipsTransformation trn;
|
||||
IMAGE *t1 = im_open_local( out, "im_lrmosaic1:1", "p" );
|
||||
VipsBuf buf;
|
||||
char text[1024];
|
||||
@ -145,7 +145,7 @@ int
|
||||
im__tbmerge1( IMAGE *ref, IMAGE *sec, IMAGE *out,
|
||||
double a, double b, double dx, double dy, int mwidth )
|
||||
{
|
||||
Transformation trn;
|
||||
VipsTransformation trn;
|
||||
IMAGE *t1 = im_open_local( out, "im_lrmosaic1:2", "p" );
|
||||
VipsBuf buf;
|
||||
char text[1024];
|
||||
@ -316,7 +316,7 @@ rotjoin_search( IMAGE *ref, IMAGE *sec, IMAGE *out, joinfn jfn,
|
||||
int balancetype,
|
||||
int mwidth )
|
||||
{
|
||||
Transformation trn;
|
||||
VipsTransformation trn;
|
||||
double cor1, cor2;
|
||||
double a, b, dx, dy;
|
||||
double xs3, ys3;
|
||||
@ -357,11 +357,11 @@ rotjoin_search( IMAGE *ref, IMAGE *sec, IMAGE *out, joinfn jfn,
|
||||
|
||||
/* Map points on sec to rotated image.
|
||||
*/
|
||||
im__transform_forward_point( &trn, xs1, ys1, &xs3, &ys3 );
|
||||
im__transform_forward_point( &trn, xs2, ys2, &xs4, &ys4 );
|
||||
vips__transform_forward_point( &trn, xs1, ys1, &xs3, &ys3 );
|
||||
vips__transform_forward_point( &trn, xs2, ys2, &xs4, &ys4 );
|
||||
|
||||
/* Refine tie-points on rotated image. Remember the clip
|
||||
* im__transform_set_area() has set, and move the sec tie-points
|
||||
* vips__transform_set_area() has set, and move the sec tie-points
|
||||
* accordingly.
|
||||
*/
|
||||
if( im_correl( t[0], t[2], xr1, yr1,
|
||||
@ -391,8 +391,8 @@ rotjoin_search( IMAGE *ref, IMAGE *sec, IMAGE *out, joinfn jfn,
|
||||
|
||||
/* ... and now back to input space again.
|
||||
*/
|
||||
im__transform_invert_point( &trn, xs5, ys5, &xs7, &ys7 );
|
||||
im__transform_invert_point( &trn, xs6, ys6, &xs8, &ys8 );
|
||||
vips__transform_invert_point( &trn, xs5, ys5, &xs7, &ys7 );
|
||||
vips__transform_invert_point( &trn, xs6, ys6, &xs8, &ys8 );
|
||||
|
||||
/* Recalc the transform using the refined points.
|
||||
*/
|
||||
@ -548,7 +548,7 @@ old_lrmosaic1( IMAGE *ref, IMAGE *sec, IMAGE *out,
|
||||
int balancetype,
|
||||
int mwidth )
|
||||
{
|
||||
Transformation trn1, trn2;
|
||||
VipsTransformation trn1, trn2;
|
||||
int dx0, dy0;
|
||||
double a, b, dx, dy;
|
||||
double a1, b1, dx1, dy1;
|
||||
|
@ -5,11 +5,11 @@
|
||||
if ENABLE_CXX
|
||||
|
||||
libresample_la_SOURCES = \
|
||||
affine.c \
|
||||
quadratic.c \
|
||||
resample.c \
|
||||
resample.h \
|
||||
shrink.c \
|
||||
im_affine.c \
|
||||
interpolate.c \
|
||||
transform.c \
|
||||
resample_dispatch.c \
|
||||
|
@ -76,6 +76,8 @@
|
||||
* interpolate.c
|
||||
* 2/2/11
|
||||
* - gtk-doc
|
||||
* 14/12/12
|
||||
* - redone as a class
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -121,9 +123,31 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include <vips/vips.h>
|
||||
#include <vips/debug.h>
|
||||
#include <vips/internal.h>
|
||||
#include <vips/transform.h>
|
||||
|
||||
#include "resample.h"
|
||||
|
||||
typedef struct _VipsAffine {
|
||||
VipsResample parent_instance;
|
||||
|
||||
VipsArea *matrix;
|
||||
VipsInterpolate *interpolate;
|
||||
VipsArea *oarea;
|
||||
double odx;
|
||||
double ody;
|
||||
double idx;
|
||||
double idy;
|
||||
|
||||
VipsTransformation trn;
|
||||
|
||||
} VipsAffine;
|
||||
|
||||
typedef VipsResampleClass VipsAffineClass;
|
||||
|
||||
G_DEFINE_TYPE( VipsAffine, vips_affine, VIPS_TYPE_RESAMPLE );
|
||||
|
||||
/*
|
||||
* FAST_PSEUDO_FLOOR is a floor and floorf replacement which has been
|
||||
* found to be faster on several linux boxes than the library
|
||||
@ -147,23 +171,6 @@
|
||||
*/
|
||||
#define FAST_PSEUDO_FLOOR(x) ( (int)(x) - ( (x) < 0. ) )
|
||||
|
||||
/* Per-call state.
|
||||
*/
|
||||
typedef struct _Affine {
|
||||
VipsImage *in;
|
||||
VipsImage *out;
|
||||
VipsInterpolate *interpolate;
|
||||
Transformation trn;
|
||||
} Affine;
|
||||
|
||||
static int
|
||||
affine_free( Affine *affine )
|
||||
{
|
||||
VIPS_FREEF( g_object_unref, affine->interpolate );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* We have five (!!) coordinate systems. Working forward through them, these
|
||||
* are:
|
||||
*
|
||||
@ -171,7 +178,7 @@ affine_free( Affine *affine )
|
||||
*
|
||||
* 2. This is embedded in a larger image to provide borders for the
|
||||
* interpolator. iarea->left/top give the offset. These are the coordinates we
|
||||
* pass to VIPS_REGION_ADDR()/im_prepare() for the input image.
|
||||
* pass to VIPS_REGION_ADDR()/vips_region_prepare() for the input image.
|
||||
*
|
||||
* The borders are sized by the interpolator's window_size property and offset
|
||||
* by the interpolator's window_offset property. For example,
|
||||
@ -189,17 +196,17 @@ affine_free( Affine *affine )
|
||||
* 4. Output transform space. This is the where the transform maps to. Pixels
|
||||
* can be negative, since a rotated image can go up and left of the origin.
|
||||
*
|
||||
* 5. Output image space. This is the wh of the xywh passed to im_affine()
|
||||
* 5. Output image space. This is the wh of the xywh passed to vips_affine()
|
||||
* below. These are the coordinates we pass to VIPS_REGION_ADDR() for the
|
||||
* output image, and that affinei_gen() is asked for.
|
||||
*/
|
||||
|
||||
static int
|
||||
affinei_gen( VipsRegion *or, void *seq, void *a, void *b )
|
||||
vips_affine_gen( VipsRegion *or, void *seq, void *a, void *b, gboolean *stop )
|
||||
{
|
||||
VipsRegion *ir = (VipsRegion *) seq;
|
||||
const VipsAffine *affine = (VipsAffine *) b;
|
||||
const VipsImage *in = (VipsImage *) a;
|
||||
const Affine *affine = (Affine *) b;
|
||||
const int window_size =
|
||||
vips_interpolate_get_window_size( affine->interpolate );
|
||||
const int window_offset =
|
||||
@ -209,19 +216,19 @@ affinei_gen( VipsRegion *or, void *seq, void *a, void *b )
|
||||
|
||||
/* Area we generate in the output image.
|
||||
*/
|
||||
const Rect *r = &or->valid;
|
||||
const VipsRect *r = &or->valid;
|
||||
const int le = r->left;
|
||||
const int ri = VIPS_RECT_RIGHT( r );
|
||||
const int to = r->top;
|
||||
const int bo = VIPS_RECT_BOTTOM( r );
|
||||
|
||||
const Rect *iarea = &affine->trn.iarea;
|
||||
const Rect *oarea = &affine->trn.oarea;
|
||||
const VipsRect *iarea = &affine->trn.iarea;
|
||||
const VipsRect *oarea = &affine->trn.oarea;
|
||||
|
||||
int ps = VIPS_IMAGE_SIZEOF_PEL( in );
|
||||
int x, y, z;
|
||||
|
||||
Rect image, want, need, clipped;
|
||||
VipsRect image, want, need, clipped;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf( "affine: generating left=%d, top=%d, width=%d, height=%d\n",
|
||||
@ -239,7 +246,7 @@ affinei_gen( VipsRegion *or, void *seq, void *a, void *b )
|
||||
|
||||
/* Find the area of the input image we need.
|
||||
*/
|
||||
im__transform_invert_rect( &affine->trn, &want, &need );
|
||||
vips__transform_invert_rect( &affine->trn, &want, &need );
|
||||
|
||||
/* That does round-to-nearest, because it has to stop rounding errors
|
||||
* growing images unexpectedly. We need round-down, so we must
|
||||
@ -248,7 +255,7 @@ affinei_gen( VipsRegion *or, void *seq, void *a, void *b )
|
||||
*
|
||||
* Add an extra line along the right and bottom as well, for rounding.
|
||||
*/
|
||||
im_rect_marginadjust( &need, 1 );
|
||||
vips_rect_marginadjust( &need, 1 );
|
||||
|
||||
/* Now go to space (2) above.
|
||||
*/
|
||||
@ -268,19 +275,19 @@ affinei_gen( VipsRegion *or, void *seq, void *a, void *b )
|
||||
image.top = 0;
|
||||
image.width = in->Xsize;
|
||||
image.height = in->Ysize;
|
||||
im_rect_intersectrect( &need, &image, &clipped );
|
||||
vips_rect_intersectrect( &need, &image, &clipped );
|
||||
|
||||
/* Outside input image? All black.
|
||||
*/
|
||||
if( im_rect_isempty( &clipped ) ) {
|
||||
im_region_black( or );
|
||||
if( vips_rect_isempty( &clipped ) ) {
|
||||
vips_region_black( or );
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* We do need some pixels from the input image to make our output -
|
||||
* ask for them.
|
||||
*/
|
||||
if( im_prepare( ir, &clipped ) )
|
||||
if( vips_region_prepare( ir, &clipped ) )
|
||||
return( -1 );
|
||||
|
||||
#ifdef DEBUG
|
||||
@ -355,50 +362,74 @@ affinei_gen( VipsRegion *or, void *seq, void *a, void *b )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static int
|
||||
affinei( VipsImage *in, VipsImage *out,
|
||||
VipsInterpolate *interpolate, Transformation *trn )
|
||||
static int
|
||||
vips_affine_build( VipsObject *object )
|
||||
{
|
||||
Affine *affine;
|
||||
VipsObjectClass *class = VIPS_OBJECT_GET_CLASS( object );
|
||||
VipsResample *resample = VIPS_RESAMPLE( object );
|
||||
VipsAffine *affine = (VipsAffine *) object;
|
||||
|
||||
VipsImage **t = (VipsImage **)
|
||||
vips_object_local_array( object, 4 );
|
||||
|
||||
VipsImage *in;
|
||||
gboolean repack;
|
||||
int window_size;
|
||||
int window_offset;
|
||||
double edge;
|
||||
|
||||
/* Make output image.
|
||||
if( VIPS_OBJECT_CLASS( vips_affine_parent_class )->build( object ) )
|
||||
return( -1 );
|
||||
|
||||
if( vips_check_coding_noneorlabq( class->nickname, in ) )
|
||||
return( -1 );
|
||||
if( vips_check_vector_length( class->nickname,
|
||||
affine->matrix->n, 4 ) )
|
||||
return( -1 );
|
||||
if( vips_object_argument_isset( object, "oarea" ) &&
|
||||
vips_check_vector_length( class->nickname,
|
||||
affine->oarea->n, 4 ) )
|
||||
return( -1 );
|
||||
|
||||
in = resample->in;
|
||||
|
||||
/* Set up transform.
|
||||
*/
|
||||
if( im_piocheck( in, out ) ||
|
||||
im_cp_desc( out, in ) )
|
||||
return( -1 );
|
||||
|
||||
/* Need a copy of the params for the lifetime of out.
|
||||
*/
|
||||
if( !(affine = VIPS_NEW( out, Affine )) )
|
||||
return( -1 );
|
||||
affine->interpolate = NULL;
|
||||
if( im_add_close_callback( out,
|
||||
(im_callback_fn) affine_free, affine, NULL ) )
|
||||
return( -1 );
|
||||
affine->in = in;
|
||||
affine->out = out;
|
||||
affine->interpolate = interpolate;
|
||||
g_object_ref( interpolate );
|
||||
affine->trn = *trn;
|
||||
window_size = vips_interpolate_get_window_size( affine->interpolate );
|
||||
window_offset =
|
||||
vips_interpolate_get_window_offset( affine->interpolate );
|
||||
|
||||
if( im__transform_calc_inverse( &affine->trn ) )
|
||||
return( -1 );
|
||||
affine->trn.iarea.left = window_offset;
|
||||
affine->trn.iarea.top = window_offset;
|
||||
affine->trn.iarea.width = in->Xsize;
|
||||
affine->trn.iarea.height = in->Ysize;
|
||||
affine->trn.a = ((double *) affine->matrix->data)[0];
|
||||
affine->trn.b = ((double *) affine->matrix->data)[1];
|
||||
affine->trn.c = ((double *) affine->matrix->data)[2];
|
||||
affine->trn.d = ((double *) affine->matrix->data)[3];
|
||||
affine->trn.dx = 0;
|
||||
affine->trn.dy = 0;
|
||||
|
||||
out->Xsize = affine->trn.oarea.width;
|
||||
out->Ysize = affine->trn.oarea.height;
|
||||
|
||||
/* Normally SMALLTILE ... except if this is a size up/down affine.
|
||||
*/
|
||||
if( affine->trn.b == 0.0 && affine->trn.c == 0.0 ) {
|
||||
if( im_demand_hint( out, VIPS_DEMAND_STYLE_FATSTRIP, in, NULL ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
if( im_demand_hint( out, VIPS_DEMAND_STYLE_SMALLTILE, in, NULL ) )
|
||||
return( -1 );
|
||||
vips__transform_set_area( &affine->trn );
|
||||
if( vips_object_argument_isset( object, "oarea" ) ) {
|
||||
affine->trn.oarea.left = ((int *) affine->oarea->data)[0];
|
||||
affine->trn.oarea.top = ((int *) affine->oarea->data)[1];
|
||||
affine->trn.oarea.width = ((int *) affine->oarea->data)[2];
|
||||
affine->trn.oarea.height = ((int *) affine->oarea->data)[3];
|
||||
}
|
||||
|
||||
if( vips_object_argument_isset( object, "odx" ) )
|
||||
affine->trn.dx = affine->odx;
|
||||
if( vips_object_argument_isset( object, "ody" ) )
|
||||
affine->trn.dx = affine->ody;
|
||||
|
||||
if( vips__transform_calc_inverse( &affine->trn ) )
|
||||
return( -1 );
|
||||
|
||||
resample->out->Xsize = affine->trn.oarea.width;
|
||||
resample->out->Ysize = affine->trn.oarea.height;
|
||||
|
||||
/* Check for coordinate overflow ... we want to be able to hold the
|
||||
* output space inside INT_MAX / TRANSFORM_SCALE.
|
||||
*/
|
||||
@ -406,186 +437,189 @@ affinei( VipsImage *in, VipsImage *out,
|
||||
if( affine->trn.oarea.left < -edge || affine->trn.oarea.top < -edge ||
|
||||
VIPS_RECT_RIGHT( &affine->trn.oarea ) > edge ||
|
||||
VIPS_RECT_BOTTOM( &affine->trn.oarea ) > edge ) {
|
||||
im_error( "im_affinei",
|
||||
vips_error( class->nickname,
|
||||
"%s", _( "output coordinates out of range" ) );
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* Generate!
|
||||
/* Unpack labq for processing ... we repack after, see below.
|
||||
*/
|
||||
if( im_generate( out,
|
||||
im_start_one, affinei_gen, im_stop_one, in, affine ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* As above, but do VIPS_CODING_LABQ too. And embed the input.
|
||||
*/
|
||||
static int
|
||||
im__affinei( VipsImage *in, VipsImage *out,
|
||||
VipsInterpolate *interpolate, Transformation *trn )
|
||||
{
|
||||
VipsImage *t3 = im_open_local( out, "im_affine:3", "p" );
|
||||
const int window_size =
|
||||
vips_interpolate_get_window_size( interpolate );
|
||||
const int window_offset =
|
||||
vips_interpolate_get_window_offset( interpolate );
|
||||
Transformation trn2;
|
||||
repack = FALSE;
|
||||
if( in->Coding == VIPS_CODING_LABQ ) {
|
||||
if( vips_LabQ2LabS( in, &t[0], NULL ) )
|
||||
return( -1 );
|
||||
repack = TRUE;
|
||||
in = t[0];
|
||||
}
|
||||
|
||||
/* Add new pixels around the input so we can interpolate at the edges.
|
||||
*/
|
||||
if( !t3 ||
|
||||
im_embed( in, t3, 1,
|
||||
window_offset, window_offset,
|
||||
in->Xsize + window_size, in->Ysize + window_size ) )
|
||||
if( vips_embed( in, &t[1], 1,
|
||||
window_offset, window_offset,
|
||||
in->Xsize + window_size, in->Ysize + window_size,
|
||||
"extend", VIPS_EXTEND_COPY,
|
||||
NULL ) )
|
||||
return( -1 );
|
||||
in = t[1];
|
||||
|
||||
/* Set iarea so we know what part of the input we can take.
|
||||
/* Normally SMALLTILE ... except if this is a size up/down affine.
|
||||
*/
|
||||
trn2 = *trn;
|
||||
trn2.iarea.left += window_offset;
|
||||
trn2.iarea.top += window_offset;
|
||||
if( affine->trn.b == 0.0 &&
|
||||
affine->trn.c == 0.0 )
|
||||
vips_demand_hint( resample->out,
|
||||
VIPS_DEMAND_STYLE_FATSTRIP, resample->in, NULL );
|
||||
else
|
||||
vips_demand_hint( resample->out,
|
||||
VIPS_DEMAND_STYLE_SMALLTILE, resample->in, NULL );
|
||||
|
||||
#ifdef DEBUG_GEOMETRY
|
||||
printf( "im__affinei: %s\n", in->filename );
|
||||
im__transform_print( &trn2 );
|
||||
#endif /*DEBUG_GEOMETRY*/
|
||||
|
||||
if( in->Coding == VIPS_CODING_LABQ ) {
|
||||
VipsImage *t[2];
|
||||
|
||||
if( im_open_local_array( out, t, 2, "im_affine:2", "p" ) ||
|
||||
im_LabQ2LabS( t3, t[0] ) ||
|
||||
affinei( t[0], t[1], interpolate, &trn2 ) ||
|
||||
im_LabS2LabQ( t[1], out ) )
|
||||
return( -1 );
|
||||
}
|
||||
else if( in->Coding == VIPS_CODING_NONE ) {
|
||||
if( affinei( t3, out, interpolate, &trn2 ) )
|
||||
return( -1 );
|
||||
}
|
||||
else {
|
||||
im_error( "im_affinei", "%s", _( "unknown coding type" ) );
|
||||
/* Generate!
|
||||
*/
|
||||
if( vips_image_generate( resample->out,
|
||||
vips_start_one, vips_affine_gen, vips_stop_one,
|
||||
resample->in, affine ) )
|
||||
return( -1 );
|
||||
}
|
||||
|
||||
/* Finally: can now set Xoffset/Yoffset.
|
||||
*/
|
||||
out->Xoffset = trn->dx - trn->oarea.left;
|
||||
out->Yoffset = trn->dy - trn->oarea.top;
|
||||
resample->out->Xoffset = affine->trn.dx - affine->trn.oarea.left;
|
||||
resample->out->Yoffset = affine->trn.dy - affine->trn.oarea.top;
|
||||
|
||||
if( repack ) {
|
||||
if( vips_LabS2LabQ( resample->out, &t[2], NULL ) )
|
||||
return( -1 );
|
||||
resample->out = t[2];
|
||||
}
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_affine_class_init( VipsAffineClass *class )
|
||||
{
|
||||
GObjectClass *gobject_class = G_OBJECT_CLASS( class );
|
||||
VipsObjectClass *vobject_class = VIPS_OBJECT_CLASS( class );
|
||||
VipsOperationClass *operation_class = VIPS_OPERATION_CLASS( class );
|
||||
|
||||
VIPS_DEBUG_MSG( "vips_affine_class_init\n" );
|
||||
|
||||
gobject_class->set_property = vips_object_set_property;
|
||||
gobject_class->get_property = vips_object_get_property;
|
||||
|
||||
vobject_class->nickname = "affine";
|
||||
vobject_class->description = _( "affine transform of an image" );
|
||||
vobject_class->build = vips_affine_build;
|
||||
|
||||
VIPS_ARG_BOXED( class, "matrix", 110,
|
||||
_( "Matrix" ),
|
||||
_( "Transformation matrix" ),
|
||||
VIPS_ARGUMENT_REQUIRED_INPUT,
|
||||
G_STRUCT_OFFSET( VipsAffine, matrix ),
|
||||
VIPS_TYPE_ARRAY_DOUBLE );
|
||||
|
||||
VIPS_ARG_INTERPOLATE( class, "interpolate", 2,
|
||||
_( "Interpolate" ),
|
||||
_( "Interpolate pixels with this" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsAffine, interpolate ) );
|
||||
|
||||
VIPS_ARG_BOXED( class, "oarea", 111,
|
||||
_( "Output rect" ),
|
||||
_( "Area of output to generate" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsAffine, oarea ),
|
||||
VIPS_TYPE_ARRAY_INT );
|
||||
|
||||
VIPS_ARG_DOUBLE( class, "odx", 112,
|
||||
_( "Output offset" ),
|
||||
_( "Horizontal output displacement" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsAffine, odx ),
|
||||
0, 10000000, 0 );
|
||||
|
||||
VIPS_ARG_DOUBLE( class, "ody", 113,
|
||||
_( "Output offset" ),
|
||||
_( "Vertical output displacement" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsAffine, ody ),
|
||||
0, 10000000, 0 );
|
||||
|
||||
VIPS_ARG_DOUBLE( class, "idx", 112,
|
||||
_( "Input offset" ),
|
||||
_( "Horizontal input displacement" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsAffine, idx ),
|
||||
0, 10000000, 0 );
|
||||
|
||||
VIPS_ARG_DOUBLE( class, "idy", 113,
|
||||
_( "Input offset" ),
|
||||
_( "Vertical input displacement" ),
|
||||
VIPS_ARGUMENT_OPTIONAL_INPUT,
|
||||
G_STRUCT_OFFSET( VipsAffine, idy ),
|
||||
0, 10000000, 0 );
|
||||
}
|
||||
|
||||
static void
|
||||
vips_affine_init( VipsAffine *affine )
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* im_affinei:
|
||||
* vips_affine:
|
||||
* @in: input image
|
||||
* @out: output image
|
||||
* @interpolate: interpolation method
|
||||
* @a: transformation matrix
|
||||
* @b: transformation matrix
|
||||
* @c: transformation matrix
|
||||
* @d: transformation matrix
|
||||
* @dx: output offset
|
||||
* @dy: output offset
|
||||
* @ox: output region
|
||||
* @oy: output region
|
||||
* @ow: output region
|
||||
* @oh: output region
|
||||
* @a: transformation matrix coefficient
|
||||
* @b: transformation matrix coefficient
|
||||
* @c: transformation matrix coefficient
|
||||
* @d: transformation matrix coefficient
|
||||
*
|
||||
* Optional arguments:
|
||||
*
|
||||
* @interpolate: interpolate pixels with this
|
||||
* @oarea: output rectangle
|
||||
* @idx: input horizontal offset
|
||||
* @idy: input vertical offset
|
||||
* @odx: output horizontal offset
|
||||
* @ody: output vertical offset
|
||||
*
|
||||
* This operator performs an affine transform on an image using @interpolate.
|
||||
*
|
||||
* The transform is:
|
||||
*
|
||||
* X = @a * x + @b * y + @dx
|
||||
* Y = @c * x + @d * y + @dy
|
||||
* X = @a * (x + @idx) + @b * (y + @idy) + @odx
|
||||
* Y = @c * (x + @idx) + @d * (y + @idy) + @doy
|
||||
*
|
||||
* x and y are the coordinates in input image.
|
||||
* X and Y are the coordinates in output image.
|
||||
* (0,0) is the upper left corner.
|
||||
*
|
||||
* The section of the output space defined by @ox, @oy, @ow, @oh is written to
|
||||
* @out. See im_affinei_all() for a function which outputs all the transformed
|
||||
* pixels.
|
||||
* The section of the output space defined by @oarea is written to
|
||||
* @out. @oarea is a four-element int array of left, top, width, height.
|
||||
* By default @oarea is just large enough to cover the whole of the
|
||||
* transformed input image.
|
||||
*
|
||||
* See also: im_affinei_all(), #VipsInterpolate.
|
||||
* @interpolate defaults to bilinear.
|
||||
*
|
||||
* @idx, @idy, @odx, @ody default to zero.
|
||||
*
|
||||
* See also: vips_shrink(), #VipsInterpolate.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
im_affinei( VipsImage *in, VipsImage *out, VipsInterpolate *interpolate,
|
||||
double a, double b, double c, double d, double dx, double dy,
|
||||
int ox, int oy, int ow, int oh )
|
||||
int
|
||||
vips_affine( VipsImage *in, VipsImage **out,
|
||||
double a, double b, double c, double d, ... )
|
||||
{
|
||||
Transformation trn;
|
||||
va_list ap;
|
||||
VipsArea *matrix;
|
||||
int result;
|
||||
|
||||
trn.iarea.left = 0;
|
||||
trn.iarea.top = 0;
|
||||
trn.iarea.width = in->Xsize;
|
||||
trn.iarea.height = in->Ysize;
|
||||
matrix = (VipsArea *) vips_array_double_newv( 4, a, b, c, d );
|
||||
|
||||
trn.oarea.left = ox;
|
||||
trn.oarea.top = oy;
|
||||
trn.oarea.width = ow;
|
||||
trn.oarea.height = oh;
|
||||
va_start( ap, d );
|
||||
result = vips_call_split( "shrink", ap, in, out, matrix );
|
||||
va_end( ap );
|
||||
|
||||
trn.a = a;
|
||||
trn.b = b;
|
||||
trn.c = c;
|
||||
trn.d = d;
|
||||
trn.dx = dx;
|
||||
trn.dy = dy;
|
||||
vips_area_unref( matrix );
|
||||
|
||||
return( im__affinei( in, out, interpolate, &trn ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* im_affinei_all:
|
||||
* @in: input image
|
||||
* @out: output image
|
||||
* @interpolate: interpolation method
|
||||
* @a: transformation matrix
|
||||
* @b: transformation matrix
|
||||
* @c: transformation matrix
|
||||
* @d: transformation matrix
|
||||
* @dx: output offset
|
||||
* @dy: output offset
|
||||
*
|
||||
* As im_affinei(), but the entire image is output.
|
||||
*
|
||||
* See also: im_affinei(), #VipsInterpolate.
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
int
|
||||
im_affinei_all( VipsImage *in, VipsImage *out, VipsInterpolate *interpolate,
|
||||
double a, double b, double c, double d, double dx, double dy )
|
||||
{
|
||||
Transformation trn;
|
||||
|
||||
trn.iarea.left = 0;
|
||||
trn.iarea.top = 0;
|
||||
trn.iarea.width = in->Xsize;
|
||||
trn.iarea.height = in->Ysize;
|
||||
trn.a = a;
|
||||
trn.b = b;
|
||||
trn.c = c;
|
||||
trn.d = d;
|
||||
trn.dx = dx;
|
||||
trn.dy = dy;
|
||||
|
||||
im__transform_set_area( &trn );
|
||||
|
||||
return( im__affinei( in, out, interpolate, &trn ) );
|
||||
}
|
||||
|
||||
/* Still needed by some parts of mosaic.
|
||||
*/
|
||||
int
|
||||
im__affine( VipsImage *in, VipsImage *out, Transformation *trn )
|
||||
{
|
||||
return( im__affinei( in, out,
|
||||
vips_interpolate_bilinear_static(), trn ) );
|
||||
return( result );
|
||||
}
|
@ -115,8 +115,10 @@ vips_resample_operation_init( void )
|
||||
{
|
||||
extern GType vips_shrink_get_type( void );
|
||||
extern GType vips_quadratic_get_type( void );
|
||||
extern GType vips_affine_get_type( void );
|
||||
|
||||
vips_shrink_get_type();
|
||||
vips_quadratic_get_type();
|
||||
vips_affine_get_type();
|
||||
}
|
||||
|
||||
|
@ -307,7 +307,7 @@ vips_shrink_build( VipsObject *object )
|
||||
shrink->mh = ceil( shrink->yshrink );
|
||||
shrink->np = shrink->mw * shrink->mh;
|
||||
|
||||
if( im_check_noncomplex( class->nickname, resample->in ) )
|
||||
if( vips_check_noncomplex( class->nickname, resample->in ) )
|
||||
return( -1 );
|
||||
|
||||
if( shrink->xshrink < 1.0 ||
|
||||
@ -327,9 +327,6 @@ vips_shrink_build( VipsObject *object )
|
||||
shrink->yshrink == 1.0 )
|
||||
return( vips_image_write( resample->in, resample->out ) );
|
||||
|
||||
if( vips_image_copy_fields( resample->out, resample->in ) )
|
||||
return( -1 );
|
||||
|
||||
/* THINSTRIP will work, FATSTRIP will break seq mode. If you combine
|
||||
* shrink with conv you'll need to use a line cache to maintain
|
||||
* sequentiality.
|
||||
@ -410,10 +407,10 @@ vips_shrink_init( VipsShrink *shrink )
|
||||
*
|
||||
* You will get aliasing for non-integer shrinks. In this case, shrink with
|
||||
* this function to the nearest integer size above the target shrink, then
|
||||
* downsample to the exact size with im_affinei() and your choice of
|
||||
* downsample to the exact size with vips_affine() and your choice of
|
||||
* interpolator.
|
||||
*
|
||||
* See also: im_affinei().
|
||||
* See also: vips_affine().
|
||||
*
|
||||
* Returns: 0 on success, -1 on error
|
||||
*/
|
||||
|
@ -49,7 +49,7 @@
|
||||
/* Calculate the inverse transformation.
|
||||
*/
|
||||
int
|
||||
im__transform_calc_inverse( Transformation *trn )
|
||||
vips__transform_calc_inverse( VipsTransformation *trn )
|
||||
{
|
||||
DOUBLEMASK *msk, *msk2;
|
||||
|
||||
@ -70,10 +70,10 @@ im__transform_calc_inverse( Transformation *trn )
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
/* Init a Transform.
|
||||
/* Init a VipsTransform.
|
||||
*/
|
||||
void
|
||||
im__transform_init( Transformation *trn )
|
||||
vips__transform_init( VipsTransformation *trn )
|
||||
{
|
||||
trn->oarea.left = 0;
|
||||
trn->oarea.top = 0;
|
||||
@ -90,13 +90,13 @@ im__transform_init( Transformation *trn )
|
||||
trn->dx = 0.0;
|
||||
trn->dy = 0.0;
|
||||
|
||||
(void) im__transform_calc_inverse( trn );
|
||||
(void) vips__transform_calc_inverse( trn );
|
||||
}
|
||||
|
||||
/* Test for transform is identity function.
|
||||
*/
|
||||
int
|
||||
im__transform_isidentity( const Transformation *trn )
|
||||
vips__transform_isidentity( const VipsTransformation *trn )
|
||||
{
|
||||
if( trn->a == 1.0 && trn->b == 0.0 && trn->c == 0.0 &&
|
||||
trn->d == 1.0 && trn->dx == 0.0 && trn->dy == 0.0 )
|
||||
@ -108,8 +108,8 @@ im__transform_isidentity( const Transformation *trn )
|
||||
/* Combine two transformations. out can be one of the ins.
|
||||
*/
|
||||
int
|
||||
im__transform_add( const Transformation *in1, const Transformation *in2,
|
||||
Transformation *out )
|
||||
vips__transform_add( const VipsTransformation *in1,
|
||||
const VipsTransformation *in2, VipsTransformation *out )
|
||||
{
|
||||
out->a = in1->a * in2->a + in1->c * in2->b;
|
||||
out->b = in1->b * in2->a + in1->d * in2->b;
|
||||
@ -119,16 +119,16 @@ im__transform_add( const Transformation *in1, const Transformation *in2,
|
||||
out->dx = in1->dx * in2->a + in1->dy * in2->b + in2->dx;
|
||||
out->dy = in1->dx * in2->c + in1->dy * in2->d + in2->dy;
|
||||
|
||||
if( im__transform_calc_inverse( out ) )
|
||||
if( vips__transform_calc_inverse( out ) )
|
||||
return( -1 );
|
||||
|
||||
return( 0 );
|
||||
}
|
||||
|
||||
void
|
||||
im__transform_print( const Transformation *trn )
|
||||
vips__transform_print( const VipsTransformation *trn )
|
||||
{
|
||||
printf( "im__transform_print:\n" );
|
||||
printf( "vips__transform_print:\n" );
|
||||
printf( " iarea: left=%d, top=%d, width=%d, height=%d\n",
|
||||
trn->iarea.left,
|
||||
trn->iarea.top,
|
||||
@ -148,9 +148,9 @@ im__transform_print( const Transformation *trn )
|
||||
/* Map a pixel coordinate through the transform.
|
||||
*/
|
||||
void
|
||||
im__transform_forward_point( const Transformation *trn,
|
||||
vips__transform_forward_point( const VipsTransformation *trn,
|
||||
const double x, const double y, /* In input space */
|
||||
double *ox, double *oy ) /* In output space */
|
||||
double *ox, double *oy ) /* In output space */
|
||||
{
|
||||
*ox = trn->a * x + trn->b * y + trn->dx;
|
||||
*oy = trn->c * x + trn->d * y + trn->dy;
|
||||
@ -159,9 +159,9 @@ im__transform_forward_point( const Transformation *trn,
|
||||
/* Map a pixel coordinate through the inverse transform.
|
||||
*/
|
||||
void
|
||||
im__transform_invert_point( const Transformation *trn,
|
||||
vips__transform_invert_point( const VipsTransformation *trn,
|
||||
const double x, const double y, /* In output space */
|
||||
double *ox, double *oy ) /* In input space */
|
||||
double *ox, double *oy ) /* In input space */
|
||||
{
|
||||
double mx = x - trn->dx;
|
||||
double my = y - trn->dy;
|
||||
@ -170,13 +170,13 @@ im__transform_invert_point( const Transformation *trn,
|
||||
*oy = trn->ic * mx + trn->id * my;
|
||||
}
|
||||
|
||||
typedef void (*transform_fn)( const Transformation *,
|
||||
typedef void (*transform_fn)( const VipsTransformation *,
|
||||
const double, const double, double*, double* );
|
||||
|
||||
/* Transform a rect using a point transformer.
|
||||
*/
|
||||
static void
|
||||
transform_rect( const Transformation *trn, transform_fn transform,
|
||||
transform_rect( const VipsTransformation *trn, transform_fn transform,
|
||||
const Rect *in, /* In input space */
|
||||
Rect *out ) /* In output space */
|
||||
{
|
||||
@ -211,28 +211,28 @@ transform_rect( const Transformation *trn, transform_fn transform,
|
||||
* pixels in the output image.
|
||||
*/
|
||||
void
|
||||
im__transform_forward_rect( const Transformation *trn,
|
||||
vips__transform_forward_rect( const VipsTransformation *trn,
|
||||
const Rect *in, /* In input space */
|
||||
Rect *out ) /* In output space */
|
||||
{
|
||||
transform_rect( trn, im__transform_forward_point, in, out );
|
||||
transform_rect( trn, vips__transform_forward_point, in, out );
|
||||
}
|
||||
|
||||
/* Given an area in the output image, calculate the bounding box for the
|
||||
* corresponding pixels in the input image.
|
||||
*/
|
||||
void
|
||||
im__transform_invert_rect( const Transformation *trn,
|
||||
vips__transform_invert_rect( const VipsTransformation *trn,
|
||||
const Rect *in, /* In output space */
|
||||
Rect *out ) /* In input space */
|
||||
{
|
||||
transform_rect( trn, im__transform_invert_point, in, out );
|
||||
transform_rect( trn, vips__transform_invert_point, in, out );
|
||||
}
|
||||
|
||||
/* Set output area of trn so that it just holds all of our input pels.
|
||||
*/
|
||||
void
|
||||
im__transform_set_area( Transformation *trn )
|
||||
vips__transform_set_area( VipsTransformation *trn )
|
||||
{
|
||||
im__transform_forward_rect( trn, &trn->iarea, &trn->oarea );
|
||||
vips__transform_forward_rect( trn, &trn->iarea, &trn->oarea );
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user