diff --git a/ChangeLog b/ChangeLog index e9b28b22..b5755822 100644 --- a/ChangeLog +++ b/ChangeLog @@ -33,8 +33,8 @@ - added im_tile_cache_random() to help nip2 - added hough_circle() to vips7 C++ API - added Travis CI config, thanks Lovell -- im_*merge(), im_*mosaic(), im_match*(), im_global_balance*(), im_remosaic() - redone as classes +- im_*merge(), im_*mosaic(), im_match*(), im_global_balance*(), im_remosaic(), + im_*mosaic1() redone as classes 6/3/14 started 7.38.6 - grey ramp minimum was wrong diff --git a/TODO b/TODO index 14d3b7e2..d0d2a475 100644 --- a/TODO +++ b/TODO @@ -1,7 +1,7 @@ - more mosaicing? - im_lrmerge1(), im_tbmerge1() - im_lrmosaic1(), im_tbmosaic1() + im_lrmosaic1(), im_tbmosaic1() done + im_lrmerge1(), im_tbmerge1() im_correl im_align_bands() im_maxpos_subpel() diff --git a/libvips/deprecated/vips7compat.c b/libvips/deprecated/vips7compat.c index 6fc4b27a..ed05a29f 100644 --- a/libvips/deprecated/vips7compat.c +++ b/libvips/deprecated/vips7compat.c @@ -5151,3 +5151,59 @@ im_remosaic( IMAGE *in, IMAGE *out, const char *old_str, const char *new_str ) return( 0 ); } + +int +im_lrmosaic1( IMAGE *ref, IMAGE *sec, IMAGE *out, + int bandno, + int xr1, int yr1, int xs1, int ys1, + int xr2, int yr2, int xs2, int ys2, + int hwindowsize, int hsearchsize, + int balancetype, + int mwidth ) +{ + VipsImage *x; + + if( vips_mosaic1( ref, sec, &x, VIPS_DIRECTION_HORIZONTAL, + xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, + "bandno", bandno, + "hwindow", hwindowsize, + "harea", hsearchsize, + "mblend", mwidth, + NULL ) ) + return( -1 ); + if( im_copy( x, out ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); + + return( 0 ); +} + +int +im_tbmosaic1( IMAGE *ref, IMAGE *sec, IMAGE *out, + int bandno, + int xr1, int yr1, int xs1, int ys1, + int xr2, int yr2, int xs2, int ys2, + int hwindowsize, int hsearchsize, + int balancetype, + int mwidth ) +{ + VipsImage *x; + + if( vips_mosaic1( ref, sec, &x, VIPS_DIRECTION_VERTICAL, + xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, + "bandno", bandno, + "hwindow", hwindowsize, + "harea", hsearchsize, + "mblend", mwidth, + NULL ) ) + return( -1 ); + if( im_copy( x, out ) ) { + g_object_unref( x ); + return( -1 ); + } + g_object_unref( x ); + + return( 0 ); +} diff --git a/libvips/include/vips/mosaicing.h b/libvips/include/vips/mosaicing.h index 380fe9e5..247e25eb 100644 --- a/libvips/include/vips/mosaicing.h +++ b/libvips/include/vips/mosaicing.h @@ -44,6 +44,11 @@ int vips_merge( VipsImage *ref, VipsImage *sec, VipsImage **out, int vips_mosaic( VipsImage *ref, VipsImage *sec, VipsImage **out, VipsDirection direction, int xref, int yref, int xsec, int ysec, ... ) __attribute__((sentinel)); +int vips_mosaic1( VipsImage *ref, VipsImage *sec, VipsImage **out, + VipsDirection direction, + int xr1, int yr1, int xs1, int ys1, + int xr2, int yr2, int xs2, int ys2, ... ) + __attribute__((sentinel)); int vips_match( VipsImage *ref, VipsImage *sec, VipsImage **out, int xr1, int yr1, int xs1, int ys1, @@ -68,21 +73,6 @@ int im_tbmerge1( VipsImage *ref, VipsImage *sec, VipsImage *out, int xr2, int yr2, int xs2, int ys2, int mwidth ); -int im_lrmosaic1( VipsImage *ref, VipsImage *sec, VipsImage *out, - int bandno, - int xr1, int yr1, int xs1, int ys1, - int xr2, int yr2, int xs2, int ys2, - int hwindowsize, int hsearchsize, - int balancetype, - int mwidth ); -int im_tbmosaic1( VipsImage *ref, VipsImage *sec, VipsImage *out, - int bandno, - int xr1, int yr1, int xs1, int ys1, - int xr2, int yr2, int xs2, int ys2, - int hwindowsize, int hsearchsize, - int balancetype, - int mwidth ); - int im_correl( VipsImage *ref, VipsImage *sec, int xref, int yref, int xsec, int ysec, int hwindowsize, int hsearchsize, diff --git a/libvips/include/vips/vips7compat.h b/libvips/include/vips/vips7compat.h index 3b1018f6..0c113b97 100644 --- a/libvips/include/vips/vips7compat.h +++ b/libvips/include/vips/vips7compat.h @@ -1067,6 +1067,21 @@ int im_global_balancef( VipsImage *in, VipsImage *out, double gamma ); int im_remosaic( VipsImage *in, VipsImage *out, const char *old_str, const char *new_str ); +int im_lrmosaic1( VipsImage *ref, VipsImage *sec, VipsImage *out, + int bandno, + int xr1, int yr1, int xs1, int ys1, + int xr2, int yr2, int xs2, int ys2, + int hwindowsize, int hsearchsize, + int balancetype, + int mwidth ); +int im_tbmosaic1( VipsImage *ref, VipsImage *sec, VipsImage *out, + int bandno, + int xr1, int yr1, int xs1, int ys1, + int xr2, int yr2, int xs2, int ys2, + int hwindowsize, int hsearchsize, + int balancetype, + int mwidth ); + #ifdef __cplusplus } #endif /*__cplusplus*/ diff --git a/libvips/mosaicing/match.c b/libvips/mosaicing/match.c index 6cdec911..218c9806 100644 --- a/libvips/mosaicing/match.c +++ b/libvips/mosaicing/match.c @@ -288,14 +288,14 @@ vips_match_class_init( VipsMatchClass *class ) G_STRUCT_OFFSET( VipsMatch, harea ), 0, 1000000000, 1 ); - VIPS_ARG_BOOL( class, "search", 13, + VIPS_ARG_BOOL( class, "search", 15, _( "search" ), _( "Search to improve tie-points" ), VIPS_ARGUMENT_OPTIONAL_INPUT, G_STRUCT_OFFSET( VipsMatch, search ), FALSE ); - VIPS_ARG_INTERPOLATE( class, "interpolate", 2, + VIPS_ARG_INTERPOLATE( class, "interpolate", 16, _( "Interpolate" ), _( "Interpolate pixels with this" ), VIPS_ARGUMENT_OPTIONAL_INPUT, diff --git a/libvips/mosaicing/mosaic1.c b/libvips/mosaicing/mosaic1.c index f90ee89d..3cc49fb8 100644 --- a/libvips/mosaicing/mosaic1.c +++ b/libvips/mosaicing/mosaic1.c @@ -410,133 +410,6 @@ rotjoin_search( IMAGE *ref, IMAGE *sec, IMAGE *out, joinfn jfn, return( 0 ); } -/** - * im_lrmosaic1: - * @ref: reference image - * @sec: secondary image - * @out: output image - * @bandno: band to search for features - * @xr1: first reference tie-point - * @yr1: first reference tie-point - * @xs1: first secondary tie-point - * @ys1: first secondary tie-point - * @xr2: second reference tie-point - * @yr2: second reference tie-point - * @xs2: second secondary tie-point - * @ys2: second secondary tie-point - * @hwindowsize: half window size - * @hsearchsize: half search size - * @balancetype: no longer used - * @mwidth: maximum blend width - * - * This operation joins two images left-right (with @ref on the left) - * given an approximate pair of tie-points. @sec is scaled and rotated as - * necessary before the join. - * - * Before performing the transformation, the tie-points are improved by - * searching band @bandno in an area of @sec of size @hsearchsize for a - * match of size @hwindowsize to @ref. - * - * @mwidth limits the maximum width of the - * blend area. A value of "-1" means "unlimited". The two images are blended - * with a raised cosine. - * - * Pixels with all bands equal to zero are "transparent", that - * is, zero pixels in the overlap area do not contribute to the merge. - * This makes it possible to join non-rectangular images. - * - * If the number of bands differs, one of the images - * must have one band. In this case, an n-band image is formed from the - * one-band image by joining n copies of the one-band image together, and then - * the two n-band images are operated upon. - * - * The two input images are cast up to the smallest common type (see table - * Smallest common format in - * arithmetic). - * - * See also: im_tbmosaic1(), im_lrmerge(), im_insert(), im_global_balance(). - * - * Returns: 0 on success, -1 on error - */ -int -im_lrmosaic1( IMAGE *ref, IMAGE *sec, IMAGE *out, - int bandno, - int xr1, int yr1, int xs1, int ys1, - int xr2, int yr2, int xs2, int ys2, - int hwindowsize, int hsearchsize, - int balancetype, - int mwidth ) -{ - return( rotjoin_search( ref, sec, out, im__lrmerge1, - bandno, - xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, - hwindowsize, hsearchsize, balancetype, - mwidth ) ); -} - -/** - * im_tbmosaic1: - * @ref: reference image - * @sec: secondary image - * @out: output image - * @bandno: band to search for features - * @xr1: first reference tie-point - * @yr1: first reference tie-point - * @xs1: first secondary tie-point - * @ys1: first secondary tie-point - * @xr2: second reference tie-point - * @yr2: second reference tie-point - * @xs2: second secondary tie-point - * @ys2: second secondary tie-point - * @hwindowsize: half window size - * @hsearchsize: half search size - * @balancetype: no longer used - * @mwidth: maximum blend width - * - * This operation joins two images top-bottom (with @ref on the top) - * given an approximate pair of tie-points. @sec is scaled and rotated as - * necessary before the join. - * - * Before performing the transformation, the tie-points are improved by - * searching band @bandno in an area of @sec of size @hsearchsize for a - * match of size @hwindowsize to @ref. - * - * @mwidth limits the maximum height of the - * blend area. A value of "-1" means "unlimited". The two images are blended - * with a raised cosine. - * - * Pixels with all bands equal to zero are "transparent", that - * is, zero pixels in the overlap area do not contribute to the merge. - * This makes it possible to join non-rectangular images. - * - * If the number of bands differs, one of the images - * must have one band. In this case, an n-band image is formed from the - * one-band image by joining n copies of the one-band image together, and then - * the two n-band images are operated upon. - * - * The two input images are cast up to the smallest common type (see table - * Smallest common format in - * arithmetic). - * - * See also: im_lrmosaic1(), im_tbmerge(), im_insert(), im_global_balance(). - * - * Returns: 0 on success, -1 on error - */ -int -im_tbmosaic1( IMAGE *ref, IMAGE *sec, IMAGE *out, - int bandno, - int xr1, int yr1, int xs1, int ys1, - int xr2, int yr2, int xs2, int ys2, - int hwindowsize, int hsearchsize, - int balancetype, - int mwidth ) -{ - return( rotjoin_search( ref, sec, out, im__tbmerge1, - bandno, - xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, - hwindowsize, hsearchsize, balancetype, mwidth ) ); -} - #ifdef OLD /* 1st order mosaic using im__find_lroverlap() ... does not work too well :( * Look at im__find_lroverlap() for problem? @@ -623,3 +496,292 @@ old_lrmosaic1( IMAGE *ref, IMAGE *sec, IMAGE *out, return( 0 ); } #endif /*OLD*/ + +typedef struct { + VipsOperation parent_instance; + + VipsImage *ref; + VipsImage *sec; + VipsImage *out; + VipsDirection direction; + int xr1; + int yr1; + int xs1; + int ys1; + int xr2; + int yr2; + int xs2; + int ys2; + int hwindow; + int harea; + gboolean search; + VipsInterpolate *interpolate; + int mblend; + int bandno; + +} VipsMosaic1; + +typedef VipsOperationClass VipsMosaic1Class; + +G_DEFINE_TYPE( VipsMosaic1, vips_mosaic1, VIPS_TYPE_OPERATION ); + +static int +vips_mosaic1_build( VipsObject *object ) +{ + VipsMosaic1 *mosaic1 = (VipsMosaic1 *) object; + + joinfn jfn; + + g_object_set( mosaic1, "out", vips_image_new(), NULL ); + + if( VIPS_OBJECT_CLASS( vips_mosaic1_parent_class )->build( object ) ) + return( -1 ); + + if( !mosaic1->interpolate ) + mosaic1->interpolate = vips_interpolate_new( "bilinear" ); + + jfn = mosaic1->direction == VIPS_DIRECTION_HORIZONTAL ? + im__lrmerge1 : im__tbmerge1; + + if( mosaic1->search ) { + if( rotjoin_search( mosaic1->ref, mosaic1->sec, mosaic1->out, + jfn, + mosaic1->bandno, + mosaic1->xr1, mosaic1->yr1, mosaic1->xs1, mosaic1->ys1, + mosaic1->xr2, mosaic1->yr2, mosaic1->xs2, mosaic1->ys2, + mosaic1->hwindow, mosaic1->harea, + 0, + mosaic1->mblend ) ) + return( -1 ); + } + else { + if( rotjoin( mosaic1->ref, mosaic1->sec, mosaic1->out, + jfn, + mosaic1->xr1, mosaic1->yr1, mosaic1->xs1, mosaic1->ys1, + mosaic1->xr2, mosaic1->yr2, mosaic1->xs2, mosaic1->ys2, + mosaic1->mblend ) ) + return( -1 ); + } + + return( 0 ); +} + +static void +vips_mosaic1_class_init( VipsMosaic1Class *class ) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS( class ); + VipsObjectClass *object_class = (VipsObjectClass *) class; + + gobject_class->set_property = vips_object_set_property; + gobject_class->get_property = vips_object_get_property; + + object_class->nickname = "mosaic1"; + object_class->description = _( "first-order mosaic of two images" ); + object_class->build = vips_mosaic1_build; + + VIPS_ARG_IMAGE( class, "ref", 1, + _( "Reference" ), + _( "Reference image" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, ref ) ); + + VIPS_ARG_IMAGE( class, "sec", 2, + _( "Secondary" ), + _( "Secondary image" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, sec ) ); + + VIPS_ARG_IMAGE( class, "out", 3, + _( "Output" ), + _( "Output image" ), + VIPS_ARGUMENT_REQUIRED_OUTPUT, + G_STRUCT_OFFSET( VipsMosaic1, out ) ); + + VIPS_ARG_ENUM( class, "direction", 4, + _( "Direction" ), + _( "Horizontal or vertcial mosaic" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, direction ), + VIPS_TYPE_DIRECTION, VIPS_DIRECTION_HORIZONTAL ); + + VIPS_ARG_INT( class, "xr1", 5, + _( "xr1" ), + _( "Position of first reference tie-point" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, xr1 ), + -1000000000, 1000000000, 1 ); + + VIPS_ARG_INT( class, "yr1", 6, + _( "yr1" ), + _( "Position of first reference tie-point" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, yr1 ), + -1000000000, 1000000000, 1 ); + + VIPS_ARG_INT( class, "xs1", 7, + _( "xs1" ), + _( "Position of first secondary tie-point" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, xs1 ), + -1000000000, 1000000000, 1 ); + + VIPS_ARG_INT( class, "ys1", 8, + _( "ys1" ), + _( "Position of first secondary tie-point" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, ys1 ), + -1000000000, 1000000000, 1 ); + + VIPS_ARG_INT( class, "xr2", 9, + _( "xr2" ), + _( "Position of second reference tie-point" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, xr2 ), + -1000000000, 1000000000, 1 ); + + VIPS_ARG_INT( class, "yr2", 10, + _( "yr2" ), + _( "Position of second reference tie-point" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, yr2 ), + -1000000000, 1000000000, 1 ); + + VIPS_ARG_INT( class, "xs2", 11, + _( "xs2" ), + _( "Position of second secondary tie-point" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, xs2 ), + -1000000000, 1000000000, 1 ); + + VIPS_ARG_INT( class, "ys2", 12, + _( "ys2" ), + _( "Position of second secondary tie-point" ), + VIPS_ARGUMENT_REQUIRED_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, ys2 ), + -1000000000, 1000000000, 1 ); + + VIPS_ARG_INT( class, "hwindow", 13, + _( "hwindow" ), + _( "Half window size" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, hwindow ), + 0, 1000000000, 1 ); + + VIPS_ARG_INT( class, "harea", 14, + _( "harea" ), + _( "Half area size" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, harea ), + 0, 1000000000, 1 ); + + VIPS_ARG_BOOL( class, "search", 13, + _( "search" ), + _( "Search to improve tie-points" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, search ), + FALSE ); + + VIPS_ARG_INTERPOLATE( class, "interpolate", 14, + _( "Interpolate" ), + _( "Interpolate pixels with this" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, interpolate ) ); + + VIPS_ARG_INT( class, "mblend", 15, + _( "Max blend" ), + _( "Maximum blend size" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, mblend ), + 0, 10000, 10 ); + + VIPS_ARG_INT( class, "bandno", 16, + _( "Search band" ), + _( "Band to search for features on" ), + VIPS_ARGUMENT_OPTIONAL_INPUT, + G_STRUCT_OFFSET( VipsMosaic1, bandno ), + 0, 10000, 0 ); + +} + +static void +vips_mosaic1_init( VipsMosaic1 *mosaic1 ) +{ + mosaic1->hwindow = 5; + mosaic1->harea = 15; + mosaic1->mblend = 10; +} + +/** + * vips_mosaic1: + * @ref: reference image + * @sec: secondary image + * @out: output image + * @direction: horizontal or vertical join + * @xr1: first reference tie-point + * @yr1: first reference tie-point + * @xs1: first secondary tie-point + * @ys1: first secondary tie-point + * @xr2: second reference tie-point + * @yr2: second reference tie-point + * @xs2: second secondary tie-point + * @ys2: second secondary tie-point + * + * Optional arguments: + * + * @search: search to improve tie-points + * @hwindow: half window size + * @harea: half search size + * @interpolate: interpolate pixels with this + * @mblend: maximum blend size + * @bandno: band to search for features + * + * This operation joins two images top-bottom (with @sec on the right) + * or left-right (with @sec at the bottom) + * given an approximate pair of tie-points. @sec is scaled and rotated as + * necessary before the join. + * + * Before performing the transformation, the tie-points are improved by + * searching band @bandno in an area of @sec of size @hsearchsize for a + * match of size @hwindowsize to @ref. + * + * If @search is %TRUE, before performing the transformation, the tie-points + * are improved by searching an area of @sec of size @harea for a + * mosaic1 of size @hwindow to @ref. + * + * @mblend limits the maximum size of the + * blend area. A value of "-1" means "unlimited". The two images are blended + * with a raised cosine. + * + * Pixels with all bands equal to zero are "transparent", that + * is, zero pixels in the overlap area do not contribute to the merge. + * This makes it possible to join non-rectangular images. + * + * If the number of bands differs, one of the images + * must have one band. In this case, an n-band image is formed from the + * one-band image by joining n copies of the one-band image together, and then + * the two n-band images are operated upon. + * + * The two input images are cast up to the smallest common type (see table + * Smallest common format in + * arithmetic). + * + * See also: vips_merge(), vips_insert(), vips_globalbalance(). + * + * Returns: 0 on success, -1 on error + */ +int +vips_mosaic1( VipsImage *ref, VipsImage *sec, VipsImage **out, + VipsDirection direction, + int xr1, int yr1, int xs1, int ys1, + int xr2, int yr2, int xs2, int ys2, ... ) +{ + va_list ap; + int result; + + va_start( ap, ys2 ); + result = vips_call_split( "mosaic1", ap, ref, sec, out, direction, + xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2 ); + va_end( ap ); + + return( result ); +} diff --git a/libvips/mosaicing/mosaicing.c b/libvips/mosaicing/mosaicing.c index b183ef20..0e03430b 100644 --- a/libvips/mosaicing/mosaicing.c +++ b/libvips/mosaicing/mosaicing.c @@ -97,11 +97,13 @@ vips_mosaicing_operation_init( void ) { extern int vips_merge_get_type( void ); extern int vips_mosaic_get_type( void ); + extern int vips_mosaic1_get_type( void ); extern int vips_match_get_type( void ); extern int vips_globalbalance_get_type( void ); vips_merge_get_type(); vips_mosaic_get_type(); + vips_mosaic1_get_type(); vips_match_get_type(); vips_globalbalance_get_type(); }