From 1aea6a13471737415f7405bba6f3b495b3490b59 Mon Sep 17 00:00:00 2001 From: John Cupitt Date: Tue, 25 Jan 2011 13:12:22 +0000 Subject: [PATCH] gtkdoc for mosaicing --- ChangeLog | 4 + TODO | 3 + doc/reference/libvips-docs.sgml.in | 2 +- doc/src/packages.tex | 2 +- libvips/arithmetic/im_maxpos.c | 3 +- libvips/conversion/im_insert.c | 5 +- libvips/include/vips/internal.h | 2 + libvips/include/vips/mosaicing.h | 16 +- libvips/mosaicing/global_balance.c | 61 ++++- libvips/mosaicing/im_align_bands.c | 14 ++ libvips/mosaicing/im_chkpair.c | 66 +++--- libvips/mosaicing/im_lrmerge.c | 106 +++++---- libvips/mosaicing/im_lrmosaic.c | 315 +++++++------------------ libvips/mosaicing/im_maxpos_subpel.c | 76 +++--- libvips/mosaicing/im_remosaic.c | 22 ++ libvips/mosaicing/im_tbmerge.c | 61 +++-- libvips/mosaicing/im_tbmosaic.c | 176 +++++++------- libvips/mosaicing/match.c | 66 +++++- libvips/mosaicing/merge.h | 4 +- libvips/mosaicing/mosaic1.c | 187 ++++++++++++++- libvips/mosaicing/mosaicing_dispatch.c | 36 ++- 21 files changed, 732 insertions(+), 495 deletions(-) diff --git a/ChangeLog b/ChangeLog index b8aa8b6c..c219caf2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,10 @@ Nicolas Robidoux) - no tables for uchar either, about a 15% speedup (thanks Nicolas) - dmask write was broken +- lr/tbmerge() cast images to match, like im_insert() +- lr/tbmosaic() work for any mix of image formats / bands +- removed ancient balance stuff from im_lr/tbmosaic() +- gtk-doc for mosaicing 30/11/10 started 7.24.0 - bump for new stable diff --git a/TODO b/TODO index 3dac8f03..19e21888 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,8 @@ +- half-way thorough making fits read lazy + + - im__open_write() should take a mode (text / binary) diff --git a/doc/reference/libvips-docs.sgml.in b/doc/reference/libvips-docs.sgml.in index 6dc0e3cf..f53ebe1c 100644 --- a/doc/reference/libvips-docs.sgml.in +++ b/doc/reference/libvips-docs.sgml.in @@ -44,12 +44,12 @@ + VIPS operation API by section (no gtkdoc comments yet) - diff --git a/doc/src/packages.tex b/doc/src/packages.tex index c2a2c1e1..8748078a 100644 --- a/doc/src/packages.tex +++ b/doc/src/packages.tex @@ -767,7 +767,7 @@ im_tbmerge1 - first-order top-bottom merge of in1 and in2 im_tbmosaic - top-bottom mosaic of in1 and in2 im_tbmosaic1 - first-order top-bottom mosaic of ref and sec \end{verbatim} -\caption{Mosaic functions} +caption{Mosaic functions} \label{fg:mosaicing} \end{fig2} diff --git a/libvips/arithmetic/im_maxpos.c b/libvips/arithmetic/im_maxpos.c index a7d98a80..ace42f5d 100644 --- a/libvips/arithmetic/im_maxpos.c +++ b/libvips/arithmetic/im_maxpos.c @@ -197,7 +197,8 @@ maxpos_scan( REGION *reg, void *seq, void *a, void *b ) * image type. Returns a double and the location of max. For complex images, * finds the pixel with the highest modulus. * - * See also: im_minpos(), im_min(), im_stats(), im_maxpos_avg(). + * See also: im_minpos(), im_min(), im_stats(), im_maxpos_avg(), + * im_maxpos_subpel(), im_maxpos_vec(). * * Returns: 0 on success, -1 on error */ diff --git a/libvips/conversion/im_insert.c b/libvips/conversion/im_insert.c index 1651ab7c..17462071 100644 --- a/libvips/conversion/im_insert.c +++ b/libvips/conversion/im_insert.c @@ -76,10 +76,9 @@ * - cast in1 and in2 up to a common format * - equalise bands * - make an input array - * - run the supplied area operation passing one of the up-banded, - * up-casted and up-sized inputs as the first param + * - return the matched images in vec[0] and vec[1] */ -static IMAGE ** +IMAGE ** im__insert_base( const char *domain, IMAGE *in1, IMAGE *in2, IMAGE *out ) { diff --git a/libvips/include/vips/internal.h b/libvips/include/vips/internal.h index 43cf6047..b4597985 100644 --- a/libvips/include/vips/internal.h +++ b/libvips/include/vips/internal.h @@ -177,6 +177,8 @@ int im__colour_difference( const char *domain, int im__colour_unary( const char *domain, IMAGE *in, IMAGE *out, VipsType type, im_wrapone_fn buffer_fn, void *a, void *b ); +IMAGE **im__insert_base( const char *domain, + IMAGE *in1, IMAGE *in2, IMAGE *out ); /* Structure for holding the lookup tables for XYZ<=>rgb conversion. * Also holds the luminance to XYZ matrix and the inverse one. diff --git a/libvips/include/vips/mosaicing.h b/libvips/include/vips/mosaicing.h index 44f487d8..0495053a 100644 --- a/libvips/include/vips/mosaicing.h +++ b/libvips/include/vips/mosaicing.h @@ -54,28 +54,28 @@ int im_tbmerge1( IMAGE *ref, IMAGE *sec, IMAGE *out, int im_lrmosaic( IMAGE *ref, IMAGE *sec, IMAGE *out, int bandno, int xref, int yref, int xsec, int ysec, - int halfcorrelation, int halfarea, + int hwindowsize, int hsearchsize, int balancetype, int mwidth ); -int im_tbmosaic( IMAGE *ref, IMAGE *sec, IMAGE *out, +int im_tbmosaic( IMAGE *ref, IMAGE *sec, IMAGE *out, int bandno, - int xref, int yref, int xsec, int ysec, - int halfcorrelation, int halfarea, + int xref, int yref, int xsec, int ysec, + int hwindowsize, int hsearchsize, int balancetype, int mwidth ); -int im_lrmosaic1( IMAGE *ref, IMAGE *sec, IMAGE *out, +int im_lrmosaic1( IMAGE *ref, IMAGE *sec, IMAGE *out, int bandno, - int xr1, int yr1, int xs1, int ys1, + int xr1, int yr1, int xs1, int ys1, int xr2, int yr2, int xs2, int ys2, - int halfcorrelation, int halfarea, + int hwindowsize, int hsearchsize, int balancetype, int mwidth ); 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 halfcorrelation, int halfarea, + int hwindowsize, int hsearchsize, int balancetype, int mwidth ); diff --git a/libvips/mosaicing/global_balance.c b/libvips/mosaicing/global_balance.c index ed7862e2..f1ad17b0 100644 --- a/libvips/mosaicing/global_balance.c +++ b/libvips/mosaicing/global_balance.c @@ -53,6 +53,8 @@ * - weed out overlaps which contain only transparent pixels * 4/1/07 * - switch to new history thing, switch im_errormsg() too + * 24/1/11 + * - gtk-doc */ /* @@ -167,9 +169,8 @@ im__global_open_image( SymbolTable *st, char *name ) { IMAGE *im; - if( (im = im_open_local( st->im, name, "r" )) ) - return( im ); - if( (im = im_open_local( st->im, im_skip_dir( name ), "r" )) ) + if( (im = im_open_local( st->im, name, "r" )) || + (im = im_open_local( st->im, im_skip_dir( name ), "r" )) ) return( im ); return( NULL ); @@ -296,9 +297,8 @@ im__build_symtab( IMAGE *out, int sz ) SymbolTable *st = IM_NEW( out, SymbolTable ); int i; - if( !st ) - return( NULL ); - if( !(st->table = IM_ARRAY( out, sz, GSList * )) ) + if( !st || + !(st->table = IM_ARRAY( out, sz, GSList * )) ) return( NULL ); st->sz = sz; st->im = out; @@ -1699,7 +1699,38 @@ transformf( JoinNode *node, double *gamma ) return( out ); } -/* Balance mosaic, outputting in the original format. +/** + * im_global_balance: + * @in: mosaic to rebuild + * @out: output image + * @gamma: gamma of source images + * + * im_global_balance() can be used to remove contrast differences in + * an assembled mosaic. + * + * It reads the History field attached to @in and builds a list of the source + * images that were used to make the mosaic and the position that each ended + * up at in the final image. + * + * It opens each of the source images in turn and extracts all parts which + * overlap with any of the other images. It finds the average values in the + * overlap areas and uses least-mean-square to find a set of correction + * factors which will minimise overlap differences. It uses @gamma to + * gamma-correct the source images before calculating the factors. A value of + * 1.0 will stop this. + * + * Each of the source images is transformed with the appropriate correction + * factor, then the mosaic is reassembled. @out always has the same #BandFmt + * as @in. Use im_global_balancef() to get float output and avoid clipping. + * + * There are some conditions that must be met before this operation can work: + * the source images must all be present under the filenames recorded in the + * history on @in, and the mosaic must have been built using only operations in + * this package. + * + * See also: im_global_balancef(), im_remosaic(). + * + * Returns: 0 on success, -1 on error */ int im_global_balance( IMAGE *in, IMAGE *out, double gamma ) @@ -1715,9 +1746,19 @@ im_global_balance( IMAGE *in, IMAGE *out, double gamma ) return( 0 ); } -/* Balance mosaic, outputting as float. This is useful if the automatic - * selection of balance range fails - our caller can search the output for the - * min and max, and rescale to prevent burn-out. +/** + * im_global_balancef: + * @in: mosaic to rebuild + * @out: output image + * @gamma: gamma of source images + * + * Just as im_global_balance(), but the output image is always float. This + * stops overflow or underflow in the case of an extremely unbalanced image + * mosaic. + * + * See also: im_global_balance(), im_remosaic(). + * + * Returns: 0 on success, -1 on error */ int im_global_balancef( IMAGE *in, IMAGE *out, double gamma ) diff --git a/libvips/mosaicing/im_align_bands.c b/libvips/mosaicing/im_align_bands.c index 64cfe821..63694c07 100644 --- a/libvips/mosaicing/im_align_bands.c +++ b/libvips/mosaicing/im_align_bands.c @@ -43,6 +43,20 @@ #include #endif /*WITH_DMALLOC*/ +/** + * im_align_bands: + * @in: image to align + * @out: output image + * + * This operation uses im_phasecor_fft() to find an integer displacement to + * align all image bands band 0. It is very slow and not very accurate. + * + * Use im_estpar() in preference: it's fast and accurate. + * + * See also: im_global_balancef(), im_remosaic(). + * + * Returns: 0 on success, -1 on error + */ int im_align_bands( IMAGE *in, IMAGE *out ){ #define FUNCTION_NAME "im_align_bands" if( im_piocheck( in, out )) diff --git a/libvips/mosaicing/im_chkpair.c b/libvips/mosaicing/im_chkpair.c index 2630ce44..14070d41 100644 --- a/libvips/mosaicing/im_chkpair.c +++ b/libvips/mosaicing/im_chkpair.c @@ -1,33 +1,4 @@ -/* @(#) Functions which improve the selection of two ttie points pairs in two - * @(#) images, by estimating the correlation coefficient given in page 426 - * @(#) 2nd edn of the book Digital Image processing Gonzalez and Wintz - * @(#) The function works as follows: - * @(#) It expects to receive nopoints pairs (coordinates) of points - * @(#) corresponding to ref and sec. - * @(#) The coordinates of the pairs are in arrays x1,y1 and x2,y2 - * @(#) After that the program reads a region of 2*halfcorsize +1 pels centered - * @(#) at point (x1, y1) and looks around - * @(#) an area 2*halfareasize+1 centered at point (x2, y2). - * @(#) For each point in this 2*halfareasize+1, - * @(#) the program reads the corresponding - * @(#) image2 values in a region of 2*halfcorsize+1 pels centered at this point - * @(#) and calculates the corresponding correlation coefficients. - * @(#) The result is stored in a the array - * @(#) corcoef[(2*halfareasize+1)(2*halfareasize+1)]. Within this window, the - * @(#) max correlation coefficient is estimated and its corresponding - * @(#) (x, y) coordinates are returned in (x2, y2). - * @(#) The purpose of this function is to improve the selection of - * @(#) control points entered in (x1, y1) - * @(#) Both input images should are either memory mapped or in a buffer. - * @(#) The variable bandno should be between 1 and ref->Bands - * @(#) The program fills the dx[] and dy[] arrays before returning. - * @(#) - * @(#) int im__chkpair( ref, sec, bandno, points ) - * @(#) IMAGE *ref, *sec; - * @(#) int bandno; - * @(#) TIE_POINTS *points; - * @(#) - * @(#) Returns 0 on sucess and -1 on error. +/* find image overlaps * * Copyright: 1990, N. Dessipris. * @@ -42,6 +13,8 @@ * - now uses im_spcor() * 13/8/96 JC * - order of args changed to help C++ API + * 24/1/11 + * - gtk-doc */ /* @@ -87,13 +60,36 @@ #include #endif /*WITH_DMALLOC*/ -/* Find position of sec within ref. Search around point xsec, ysec for the - * best match for the area around xref, yref. Search an area of size - * hsearchsize for an of size hwindowsize. +/** + * im_correl: + * @ref: reference image + * @sec: secondary image + * @xref: position in reference image + * @yref: position in reference image + * @xsec: position in secondary image + * @ysec: position in secondary image + * @hwindowsize: half window size + * @hsearchsize: half search size + * @correlation: return detected correlation + * @x: return found position + * @y: return found position * - * Return a new value for xsec, ysec and the correlation at that point. + * This operation finds the position of @sec within @ref. + * + * The area around + * (@xsec, @ysec) is searched for the best match to the area around (@xref, + * @yref). It searches an area of size @hsearchsize for a + * match of size @hwindowsize. The position of the best match is + * returned, together with the correlation at that point. + * + * Only the first band of each image is correlated. @ref and @sec may be + * very large --- the function extracts and generates just the + * parts needed. Correlation is done with im_spcor(); the position of + * the maximum is found with im_maxpos(). * - * Also used by im_match_linear(), im_match_linear_search(), etc. + * See also: im_match_linear(), im_match_linear_search(), im_lrmosaic(). + * + * Returns: 0 on success, -1 on error */ int im_correl( IMAGE *ref, IMAGE *sec, diff --git a/libvips/mosaicing/im_lrmerge.c b/libvips/mosaicing/im_lrmerge.c index 516908df..362f19e4 100644 --- a/libvips/mosaicing/im_lrmerge.c +++ b/libvips/mosaicing/im_lrmerge.c @@ -1,14 +1,4 @@ -/* Merge two images left-right. dx, dy is the offset needed to get from sec - * (secondary image) to ref (reference image). - * - * Usage: - * - * int - * im_lrmerge( ref, sec, out, dx, dy ) - * IMAGE *ref, *sec, *out; - * int dx, dy; - * - * Returns 0 on success and -1 on error +/* Merge two images left-right. * * Copyright: 1990, 1991 N. Dessipris * Author: N. Dessipris @@ -88,6 +78,9 @@ * 20/6/05 * - now requires all bands == 0 for transparency (used to just check * band 0) + * 24/1/11 + * - gtk-doc + * - match formats and bands automatically */ /* @@ -700,22 +693,23 @@ lock_free( GMutex *lock ) * im_tbmerge, so not static. */ Overlapping * -im__build_mergestate( IMAGE *ref, IMAGE *sec, IMAGE *out, - int dx, int dy, int mwidth ) +im__build_mergestate( const char *domain, + IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) { - Overlapping *ovlap = IM_NEW( out, Overlapping ); + IMAGE **vec; + Overlapping *ovlap; int x; - if( !ovlap ) + if( !(vec = im__insert_base( domain, ref, sec, out )) || + !(ovlap = IM_NEW( out, Overlapping )) ) return( NULL ); if( mwidth < -1 ) { - im_error( "im_lr/tbmerge", - "%s", _( "mwidth must be -1 or >= 0" ) ); + im_error( domain, "%s", _( "mwidth must be -1 or >= 0" ) ); return( NULL ); } - ovlap->ref = ref; - ovlap->sec = sec; + ovlap->ref = vec[0]; + ovlap->sec = vec[1]; ovlap->out = out; ovlap->dx = dx; ovlap->dy = dy; @@ -725,21 +719,21 @@ im__build_mergestate( IMAGE *ref, IMAGE *sec, IMAGE *out, */ ovlap->rarea.left = 0; ovlap->rarea.top = 0; - ovlap->rarea.width = ref->Xsize; - ovlap->rarea.height = ref->Ysize; + ovlap->rarea.width = ovlap->ref->Xsize; + ovlap->rarea.height = ovlap->ref->Ysize; /* Area occupied by sec image. */ ovlap->sarea.left = -dx; ovlap->sarea.top = -dy; - ovlap->sarea.width = sec->Xsize; - ovlap->sarea.height = sec->Ysize; + ovlap->sarea.width = ovlap->sec->Xsize; + ovlap->sarea.height = ovlap->sec->Ysize; /* Compute overlap. */ im_rect_intersectrect( &ovlap->rarea, &ovlap->sarea, &ovlap->overlap ); if( im_rect_isempty( &ovlap->overlap ) ) { - im_error( "im_lr/tbmerge", "%s", _( "no overlap" ) ); + im_error( domain, "%s", _( "no overlap" ) ); return( NULL ); } @@ -794,12 +788,13 @@ build_lrstate( IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) { Overlapping *ovlap; - if( !(ovlap = im__build_mergestate( ref, sec, out, dx, dy, mwidth )) ) + if( !(ovlap = im__build_mergestate( "im_lrmerge", + ref, sec, out, dx, dy, mwidth )) ) return( NULL ); /* Select blender. */ - switch( ref->Coding ) { + switch( ovlap->ref->Coding ) { case IM_CODING_LABQ: ovlap->blend = lr_blend_labpack; break; @@ -1040,7 +1035,7 @@ im__start_merge( IMAGE *out, void *a, void *b ) int im__lrmerge( IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) -{ +{ Overlapping *ovlap; #ifdef DEBUG @@ -1051,20 +1046,6 @@ im__lrmerge( IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) printf( "sec is %d x %d pixels\n", sec->Xsize, sec->Ysize ); #endif - /* Check IMAGEs parameters - */ - if( ref->Bands != sec->Bands || - ref->BandFmt != sec->BandFmt || - ref->Coding != sec->Coding ) { - im_error( "im_lrmerge", - "%s", _( "input images incompatible" ) ); - return( -1 ); - } - if( ref->Coding != IM_CODING_NONE && ref->Coding != IM_CODING_LABQ ) { - im_error( "im_lrmerge", - "%s", _( "inputs not uncoded or IM_CODING_LABQ" ) ); - return( -1 ); - } if( dx > 0 || dx < 1 - ref->Xsize ) { #ifdef DEBUG printf( "im__lrmerge: no overlap, using insert\n" ); @@ -1079,8 +1060,6 @@ im__lrmerge( IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) return( 0 ); } - if( im_piocheck( ref, out ) || im_piocheck( sec, out ) ) - return( -1 ); /* Build state for this join. */ @@ -1089,7 +1068,7 @@ im__lrmerge( IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) /* Prepare the output IMAGE. */ - if( im_cp_descv( out, ref, sec, NULL ) ) + if( im_cp_descv( out, ovlap->ref, ovlap->sec, NULL ) ) return( -1 ); out->Xsize = ovlap->oarea.width; out->Ysize = ovlap->oarea.height; @@ -1098,7 +1077,7 @@ im__lrmerge( IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) /* Set demand hints. */ - if( im_demand_hint( out, IM_THINSTRIP, ref, sec, NULL ) ) + if( im_demand_hint( out, IM_THINSTRIP, ovlap->ref, ovlap->sec, NULL ) ) return( -1 ); /* Generate! @@ -1110,6 +1089,43 @@ im__lrmerge( IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) return ( 0 ); } +/** + * im_lrmerge: + * @ref: reference image + * @sec: secondary image + * @out: output image + * @dx: displacement of ref from sec + * @dy: displacement of ref from sec + * @mwidth: maximum seam width + * + * This operation joins two images left-right (with @ref on the left) with a + * smooth seam. + * + * 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). + * + * @dx and @dy give the displacement of @sec relative to @ref, in other words, + * the vector to get from the origin of @sec to the origin of @ref, in other + * words, @dx will generally be a negative number. + * + * @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. + * + * See also: im_lrmosaic(), im_tbmerge(), im_match_linear(), im_insert(). + * + * Returns: 0 on success, -1 on error + */ int im_lrmerge( IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) { diff --git a/libvips/mosaicing/im_lrmosaic.c b/libvips/mosaicing/im_lrmosaic.c index 0bca95c8..e11471b1 100644 --- a/libvips/mosaicing/im_lrmosaic.c +++ b/libvips/mosaicing/im_lrmosaic.c @@ -1,16 +1,4 @@ -/* @(#) Program to calculate the best possible tie points - * @(#) in the overlapping part between the primary and the secondary picture - * @(#) - * @(#) Right call: - * @(#) int im_lrmosaic( reference, secondary, out, bandno, - * @(#) xref, yref, xsec, ysec, halfcorrelation, halfarea ) - * @(#) IMAGE *reference, *secondary, *out; - * @(#) int bandno; - * @(#) int xref, yref, xsec, ysec; - * @(#) int halfcorrelation, halfarea; - * @(#) - * @(#) Returns 0 on success and -1 on error - * @(#) +/* join left-right with an approximate overlap * * Copyright: 1990, N. Dessipris. * @@ -32,6 +20,11 @@ * - added tunable max blend width * 24/2/05 * - im_scale() makes it work for any image type + * 25/1/11 + * - gtk-doc + * - remove balance stuff + * - any mix of types and bands + * - cleanups */ /* @@ -109,23 +102,14 @@ im__find_lroverlap( IMAGE *ref_in, IMAGE *sec_in, IMAGE *out, int *dx0, int *dy0, double *scale1, double *angle1, double *dx1, double *dy1 ) { + Rect left, right, overlap; IMAGE *ref, *sec; + IMAGE *t[6]; TIE_POINTS points, *p_points; TIE_POINTS newpoints, *p_newpoints; int dx, dy; int i; - Rect left, right, overlap; - - /* Check ref and sec are compatible. - */ - if( ref_in->Bands != sec_in->Bands || - ref_in->BandFmt != sec_in->BandFmt || - ref_in->Coding != sec_in->Coding ) { - im_error( "im_lrmosaic", "%s", _( "input images incompatible" ) ); - return( -1 ); - } - /* Test cor and area. */ if( halfcorrelation < 0 || halfarea < 0 || @@ -148,68 +132,39 @@ im__find_lroverlap( IMAGE *ref_in, IMAGE *sec_in, IMAGE *out, /* Find overlap. */ im_rect_intersectrect( &left, &right, &overlap ); - if( overlap.width < 2*halfarea + 1 || - overlap.height < 2*halfarea + 1 ) { - im_error( "im_lrmosaic", "%s", _( "overlap too small for search" ) ); + if( overlap.width < 2 * halfarea + 1 || + overlap.height < 2 * halfarea + 1 ) { + im_error( "im_lrmosaic", + "%s", _( "overlap too small for search" ) ); return( -1 ); } - /* Extract overlaps. + /* Extract overlaps as 8-bit, 1 band. */ - ref = im_open_local( out, "temp_one", "t" ); - sec = im_open_local( out, "temp_two", "t" ); - if( !ref || !sec ) - return( -1 ); - if( ref_in->Coding == IM_CODING_LABQ ) { - IMAGE *t1 = im_open_local( out, "temp:3", "p" ); - IMAGE *t2 = im_open_local( out, "temp:4", "p" ); - IMAGE *t3 = im_open_local( out, "temp:5", "p" ); - IMAGE *t4 = im_open_local( out, "temp:6", "p" ); - IMAGE *t5 = im_open_local( out, "temp:7", "p" ); - IMAGE *t6 = im_open_local( out, "temp:8", "p" ); - - if( !t1 || !t2 || !t3 || !t4 || !t5 || !t6 ) - return( -1 ); - if( im_extract_area( ref_in, t1, + if( !(ref = im_open_local( out, "temp_one", "t" )) || + !(sec = im_open_local( out, "temp_two", "t" )) || + im_open_local_array( out, t, 6, "im_lrmosaic", "p" ) || + im_extract_area( ref_in, t[0], overlap.left, overlap.top, - overlap.width, overlap.height ) ) - return( -1 ); - if( im_extract_area( sec_in, t2, + overlap.width, overlap.height ) || + im_extract_area( sec_in, t[1], overlap.left - right.left, overlap.top - right.top, overlap.width, overlap.height ) ) - return( -1 ); - if( im_LabQ2Lab( t1, t3 ) || im_LabQ2Lab( t2, t4 ) || - im_Lab2disp( t3, t5, im_col_displays( 1 ) ) || - im_Lab2disp( t4, t6, im_col_displays( 1 ) ) ) - return( -1 ); - - /* Extract the green. - */ - if( im_extract_band( t5, ref, 1 ) || - im_extract_band( t6, sec, 1 ) ) + return( -1 ); + if( ref_in->Coding == IM_CODING_LABQ ) { + if( im_LabQ2Lab( t[0], t[2] ) || + im_LabQ2Lab( t[1], t[3] ) || + im_Lab2disp( t[2], t[4], im_col_displays( 1 ) ) || + im_Lab2disp( t[3], t[5], im_col_displays( 1 ) ) || + im_extract_band( t[4], ref, 1 ) || + im_extract_band( t[5], sec, 1 ) ) return( -1 ); } else if( ref_in->Coding == IM_CODING_NONE ) { - IMAGE *t1 = im_open_local( out, "temp:9", "p" ); - IMAGE *t2 = im_open_local( out, "temp:10", "p" ); - IMAGE *t3 = im_open_local( out, "temp:11", "p" ); - IMAGE *t4 = im_open_local( out, "temp:12", "p" ); - - if( !t1 || !t2 || !t3 || !t4 ) - return( -1 ); - if( im_extract_area( ref_in, t1, - overlap.left, overlap.top, - overlap.width, overlap.height ) ) - return( -1 ); - if( im_extract_area( sec_in, t2, - overlap.left - right.left, overlap.top - right.top, - overlap.width, overlap.height ) ) - return( -1 ); - if( im_extract_band( t1, t3, bandno_in ) || - im_extract_band( t2, t4, bandno_in ) ) - return( -1 ); - if( im_scale( t3, ref ) || - im_scale( t4, sec ) ) + if( im_extract_band( t[0], t[2], bandno_in ) || + im_extract_band( t[1], t[3], bandno_in ) || + im_scale( t[2], ref ) || + im_scale( t[3], sec ) ) return( -1 ); } else { @@ -286,161 +241,68 @@ im__find_lroverlap( IMAGE *ref_in, IMAGE *sec_in, IMAGE *out, return( 0 ); } -/* Scale im by fac with a lut. +/** + * im_lrmosaic: + * @ref: reference image + * @sec: secondary image + * @out: output image + * @bandno: band to search for features + * @xref: position in reference image + * @yref: position in reference image + * @xsec: position in secondary image + * @ysec: position in secondary image + * @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 overlap. + * + * @sec is positioned so that the pixel (@xsec, @ysec) lies on top of the + * pixel in @ref at (@xref, @yref). The overlap area is divided into three + * sections, 20 high-contrast points in band @bandno of image @ref are found + * in each, and each high-contrast point is searched for in @sec using + * @hwindowsize and @hsearchsize (see im_correl()). + * + * A linear model is fitted to the 60 tie-points, points a long way from the + * fit are discarded, and the model refitted until either too few points + * remain or the model reaches good agreement. + * + * The detected displacement is used with im_lrmerge() to join the two images + * together. + * + * @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_lrmerge(), im_tbmosaic(), im_insert(), im_global_balance(). + * + * Returns: 0 on success, -1 on error */ -static IMAGE * -transform( IMAGE *out, IMAGE *im, double fac ) -{ - IMAGE *t1 = im_open_local( out, "transform:1", "p" ); - IMAGE *t2 = im_open_local( out, "transform:2", "p" ); - IMAGE *t3 = im_open_local( out, "transform:3", "p" ); - IMAGE *t4 = im_open_local( out, "transform:4", "p" ); - - if( !t1 || !t2 || !t3 || !t4 ) - return( NULL ); - - if( fac == 1.0 ) - /* Easy! - */ - return( im ); - - if( im_identity( t1, 1 ) || - im_lintra( fac, t1, 0.0, t2 ) || - im_clip2fmt( t2, t3, IM_BANDFMT_UCHAR ) || - im_maplut( im, t4, t3 ) ) - return( NULL ); - - return( t4 ); -} - -/* Balance two images. dx, dy parameters as for im_??merge, etc. - */ -int -im__balance( IMAGE *ref, IMAGE *sec, IMAGE *out, - IMAGE **ref_out, IMAGE **sec_out, int dx, int dy, int balancetype ) -{ - double lavg, ravg; - double lfac, rfac; - Rect left, right, overlap; - IMAGE *t1, *t2; - - /* Test balancetype. - */ - if( balancetype < 0 || balancetype > 3 ) { - im_error( "im_mosaic", "%s", _( "bad balancetype parameter" ) ); - return( -1 ); - } - - /* No balance - easy! - */ - if( balancetype == 0 ) { - *ref_out = ref; - *sec_out = sec; - - return( 0 ); - } - - /* Must be uchar uncoded. - */ - if( ref->Coding != IM_CODING_NONE || - ref->BandFmt != IM_BANDFMT_UCHAR ) { - im_error( "im_mosaic", "%s", _( "uncoded uchar only for balancing" ) ); - return( -1 ); - } - - /* Set positions of left and right. - */ - left.left = 0; - left.top = 0; - left.width = ref->Xsize; - left.height = ref->Ysize; - right.left = -dx; - right.top = -dy; - right.width = sec->Xsize; - right.height = sec->Ysize; - - /* Find overlap. - */ - im_rect_intersectrect( &left, &right, &overlap ); - - /* Extract overlaps. - */ - t1 = im_open_local( out, "temp_one", "p" ); - t2 = im_open_local( out, "temp_two", "p" ); - if( !t1 || !t2 ) - return( -1 ); - - if( im_extract_area( ref, t1, - overlap.left, overlap.top, - overlap.width, overlap.height ) ) - return( -1 ); - if( im_extract_area( sec, t2, - overlap.left - right.left, overlap.top - right.top, - overlap.width, overlap.height ) ) - return( -1 ); - - /* And find the average. - */ - if( im_avg( t1, &lavg ) || im_avg( t2, &ravg ) ) - return( -1 ); - - /* Compute scale factors. - */ - switch( balancetype ) { - case 1: - /* Ajust left. - */ - rfac = 1.0; - lfac = ravg / lavg; - break; - - case 2: - /* Adjust right. - */ - lfac = 1.0; - rfac = lavg / ravg; - break; - - case 3: - { - /* Adjust both to weighted average. - */ - double ltot = (double) ref->Xsize * ref->Ysize; - double rtot = (double) sec->Xsize * sec->Ysize; - double rat = ltot / (ltot + rtot); - double navg = rat * (lavg - ravg) + ravg; - - lfac = navg / lavg; - rfac = navg / ravg; - } - break; - - default: - error_exit( "internal error #897624395" ); - return( -1 ); - } - - /* Transform the left and right images. - */ - if( !(*ref_out = transform( out, ref, lfac )) ) - return( -1 ); - if( !(*sec_out = transform( out, sec, rfac )) ) - return( -1 ); - - return( 0 ); -} - int im_lrmosaic( IMAGE *ref, IMAGE *sec, IMAGE *out, int bandno, int xref, int yref, int xsec, int ysec, - int halfcorrelation, int halfarea, + int hwindowsize, int hsearchsize, int balancetype, int mwidth ) { int dx0, dy0; double scale1, angle1, dx1, dy1; - IMAGE *ref2, *sec2; IMAGE *dummy; /* Correct overlap. dummy is just a placeholder used to ensure that @@ -451,7 +313,7 @@ im_lrmosaic( IMAGE *ref, IMAGE *sec, IMAGE *out, if( im__find_lroverlap( ref, sec, dummy, bandno, xref, yref, xsec, ysec, - halfcorrelation, halfarea, + hwindowsize, hsearchsize, &dx0, &dy0, &scale1, &angle1, &dx1, &dy1 ) ) { im_close( dummy ); @@ -459,16 +321,9 @@ im_lrmosaic( IMAGE *ref, IMAGE *sec, IMAGE *out, } im_close( dummy ); - /* Balance. - */ - if( im__balance( ref, sec, out, - &ref2, &sec2, - dx0, dy0, balancetype ) ) - return( -1 ); - /* Merge left right. */ - if( im_lrmerge( ref2, sec2, out, dx0, dy0, mwidth ) ) + if( im_lrmerge( ref, sec, out, dx0, dy0, mwidth ) ) return( -1 ); return( 0 ); diff --git a/libvips/mosaicing/im_maxpos_subpel.c b/libvips/mosaicing/im_maxpos_subpel.c index 51c0c5fc..fc64abd6 100644 --- a/libvips/mosaicing/im_maxpos_subpel.c +++ b/libvips/mosaicing/im_maxpos_subpel.c @@ -1,38 +1,11 @@ -/* This function implements: - * "Extension of Phase Correlation to Subpixel Registration" - * by H. Foroosh, from IEEE trans. Im. Proc. 11(3), 2002. - * - * If the best three matches in the correlation are aranged: - * - * 02 or 01 - * 1 2 - * - * then we return a subpixel match using the ratio of correlations in the - * vertical and horizontal dimension. - * - * ( xs[0], ys[0] ) is the best integer alignment - * ( xs[ use_x ], ys[ use_x ] ) is equal in y and (+/-)1 off in x - * ( xs[ use_y ], ys[ use_y ] ) is equal in x and (+/-)1 off in y - * - * - * Alternatively if the best four matches in the correlation are aranged in - * a square: - * - * 01 or 03 or 02 or 03 - * 32 12 31 21 - * - * then we return a subpixel match weighting with the sum the two on each - * side over the sum of all four, but only if all four of them are very - * close to the best, and the fifth is nowhere near. - * - * This alternative method is not described by Foroosh, but is often the - * case where the match is close to n-and-a-half pixels in both dimensions. +/* find position of maximum, subpixel estimation * * Copyright: 2008, Nottingham Trent University - * * Author: Tom Vajzovic - * * Written on: 2008-02-07 + * + * 25/1/11 + * - gtk-doc */ /* @@ -77,6 +50,47 @@ #define MOST_OF( A, B ) ( (A) > 0.9 * (B) ) #define LITTLE_OF( A, B ) ( (B) < 0.1 * (B) ) +/** + * im_maxpos_subpel: + * @in: input image + * @x: output position of maximum + * @y: output position of maximum + * + * This function implements: + * + * "Extension of Phase Correlation to Subpixel Registration" + * by H. Foroosh, from IEEE trans. Im. Proc. 11(3), 2002. + * + * If the best three matches in the correlation are aranged: + * + * 02 or 01 + * 1 2 + * + * then we return a subpixel match using the ratio of correlations in the + * vertical and horizontal dimension. + * + * ( xs[0], ys[0] ) is the best integer alignment + * ( xs[ use_x ], ys[ use_x ] ) is equal in y and (+/-)1 off in x + * ( xs[ use_y ], ys[ use_y ] ) is equal in x and (+/-)1 off in y + * + * Alternatively if the best four matches in the correlation are aranged in + * a square: + * + * 01 or 03 or 02 or 03 + * 32 12 31 21 + * + * then we return a subpixel match weighting with the sum the two on each + * side over the sum of all four, but only if all four of them are very + * close to the best, and the fifth is nowhere near. + * + * This alternative method is not described by Foroosh, but is often the + * case where the match is close to n-and-a-half pixels in both dimensions. + * + * See also: im_maxpos(), im_min(), im_stats(). + * + * Returns: 0 on success, -1 on error + */ + int im_maxpos_subpel( IMAGE *in, double *x, double *y ){ #define FUNCTION_NAME "im_maxpos_subpel" diff --git a/libvips/mosaicing/im_remosaic.c b/libvips/mosaicing/im_remosaic.c index 6bbf86e8..8ef2d168 100644 --- a/libvips/mosaicing/im_remosaic.c +++ b/libvips/mosaicing/im_remosaic.c @@ -114,6 +114,28 @@ remosaic( JoinNode *node, RemosaicData *rd ) return( out ); } +/** + * im_remosaic: + * @in: mosaic to rebuild + * @out: output image + * @old_str: gamma of source images + * @new_str: gamma of source images + * + * im_remosaic() works rather as im_global_balance(). It takes apart the + * mosaiced image in and rebuilds it, substituting images. + * + * Unlike im_global_balance(), images are substituted based on their file‐ + * names. The rightmost occurence of the string @old_str is swapped + * for @new_str, that file is opened, and that image substituted for + * the old image. + * + * It's convenient for multispectral images. You can mosaic one band, then + * use that mosaic as a template for mosaicing the others automatically. + * + * See also: im_lrmosaic(), im_global_balance(). + * + * Returns: 0 on success, -1 on error + */ int im_remosaic( IMAGE *in, IMAGE *out, const char *old_str, const char *new_str ) { diff --git a/libvips/mosaicing/im_tbmerge.c b/libvips/mosaicing/im_tbmerge.c index 00f384fa..bfddd0db 100644 --- a/libvips/mosaicing/im_tbmerge.c +++ b/libvips/mosaicing/im_tbmerge.c @@ -68,6 +68,9 @@ * 20/6/05 * - now requires all bands == 0 for transparency (used to just check * band 0) + * 24/1/11 + * - gtk-doc + * - match formats and bands automatically */ /* @@ -616,12 +619,13 @@ build_tbstate( IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) { Overlapping *ovlap; - if( !(ovlap = im__build_mergestate( ref, sec, out, dx, dy, mwidth )) ) + if( !(ovlap = im__build_mergestate( "im_tbmerge", + ref, sec, out, dx, dy, mwidth )) ) return( NULL ); /* Select blender. */ - switch( ref->Coding ) { + switch( ovlap->ref->Coding ) { case IM_CODING_LABQ: ovlap->blend = tb_blend_labpack; break; @@ -665,20 +669,6 @@ im__tbmerge( IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) { Overlapping *ovlap; - /* Check IMAGEs parameters - */ - if( ref->Bands != sec->Bands || - ref->BandFmt != sec->BandFmt || - ref->Coding != sec->Coding ) { - im_error( "im_tbmerge", - "%s", _( "input images incompatible" ) ); - return( -1 ); - } - if( ref->Coding != IM_CODING_NONE && ref->Coding != IM_CODING_LABQ ) { - im_error( "im_tbmerge", - "%s", _( "inputs not uncoded or IM_CODING_LABQ" ) ); - return( -1 ); - } if( dy > 0 || dy < 1 - ref->Ysize ) { /* No overlap, use insert instead. */ @@ -689,8 +679,6 @@ im__tbmerge( IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) return( 0 ); } - if( im_piocheck( ref, out ) || im_piocheck( sec, out ) ) - return( -1 ); /* Build state for this join. */ @@ -720,6 +708,43 @@ im__tbmerge( IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) return ( 0 ); } +/** + * im_tbmerge: + * @ref: reference image + * @sec: secondary image + * @out: output image + * @dx: displacement of ref from sec + * @dy: displacement of ref from sec + * @mwidth: maximum seam width + * + * This operation joins two images top-bottom (with @ref on the top) with a + * smooth seam. + * + * 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). + * + * @dx and @dy give the displacement of @sec relative to @ref, in other words, + * the vector to get from the origin of @sec to the origin of @ref, in other + * words, @dx will generally be a negative number. + * + * @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. + * + * See also: im_lrmosaic(), im_lrmerge(), im_match_linear(), im_insert(). + * + * Returns: 0 on success, -1 on error + */ int im_tbmerge( IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ) { diff --git a/libvips/mosaicing/im_tbmosaic.c b/libvips/mosaicing/im_tbmosaic.c index d36bd842..67340aa5 100644 --- a/libvips/mosaicing/im_tbmosaic.c +++ b/libvips/mosaicing/im_tbmosaic.c @@ -1,17 +1,4 @@ -/* @(#) Program to calculate the best possible tie points - * @(#) in the overlapping part between the primary and the secondary picture - * @(#) - * @(#) Right call: - * @(#) int im_tbmosaic( reference, secondary, out, bandno, - * @(#) xref, yref, xsec, ysec, halfcorrelation, halfarea, balancetype ) - * @(#) IMAGE *reference, *secondary, *out; - * @(#) int bandno; - * @(#) int xref, yref, xsec, ysec; - * @(#) int halfcorrelation, halfarea; - * @(#) int balancetype; - * @(#) - * @(#) Returns 0 on success and -1 on error - * @(#) +/* join top-bottom with an approximate overlap * * Copyright: 1990, N. Dessipris. * @@ -33,6 +20,11 @@ * - added tunable max blend width * 24/2/05 * - im_scale() makes it work for any image type + * 25/1/11 + * - gtk-doc + * - remove balance stuff + * - any mix of types and bands + * - cleanups */ /* @@ -86,23 +78,14 @@ im__find_tboverlap( IMAGE *ref_in, IMAGE *sec_in, IMAGE *out, int *dx0, int *dy0, double *scale1, double *angle1, double *dx1, double *dy1 ) { + Rect top, bottom, overlap; IMAGE *ref, *sec; + IMAGE *t[6]; TIE_POINTS points, *p_points; /* defined in mosaic.h */ TIE_POINTS newpoints, *p_newpoints; int i; int dx, dy; - Rect top, bottom, overlap; - - /* Check ref and sec are compatible. - */ - if( ref_in->Bands != sec_in->Bands || - ref_in->BandFmt != sec_in->BandFmt || - ref_in->Coding != sec_in->Coding ) { - im_error( "im_tbmosaic", "%s", _( "input images incompatible" ) ); - return( -1 ); - } - /* Test cor and area. */ if( halfcorrelation < 0 || halfarea < 0 || @@ -125,68 +108,39 @@ im__find_tboverlap( IMAGE *ref_in, IMAGE *sec_in, IMAGE *out, /* Find overlap. */ im_rect_intersectrect( &top, &bottom, &overlap ); - if( overlap.width < 2*halfarea + 1 || - overlap.height < 2*halfarea + 1 ) { - im_error( "im_tbmosaic", "%s", _( "overlap too small for search" ) ); + if( overlap.width < 2 * halfarea + 1 || + overlap.height < 2 * halfarea + 1 ) { + im_error( "im_tbmosaic", "%s", + _( "overlap too small for search" ) ); return( -1 ); } - /* Extract overlaps. + /* Extract overlaps as 8-bit, 1 band. */ - ref = im_open_local( out, "temp_one", "t" ); - sec = im_open_local( out, "temp_two", "t" ); - if( !ref || !sec ) - return( -1 ); - if( ref_in->Coding == IM_CODING_LABQ ) { - IMAGE *t1 = im_open_local( out, "temp:3", "p" ); - IMAGE *t2 = im_open_local( out, "temp:4", "p" ); - IMAGE *t3 = im_open_local( out, "temp:5", "p" ); - IMAGE *t4 = im_open_local( out, "temp:6", "p" ); - IMAGE *t5 = im_open_local( out, "temp:7", "p" ); - IMAGE *t6 = im_open_local( out, "temp:8", "p" ); - - if( !t1 || !t2 || !t3 || !t4 || !t5 || !t6 ) - return( -1 ); - if( im_extract_area( ref_in, t1, + if( !(ref = im_open_local( out, "temp_one", "t" )) || + !(sec = im_open_local( out, "temp_two", "t" )) || + im_open_local_array( out, t, 6, "im_tbmosaic", "p" ) || + im_extract_area( ref_in, t[0], overlap.left, overlap.top, - overlap.width, overlap.height ) ) - return( -1 ); - if( im_extract_area( sec_in, t2, + overlap.width, overlap.height ) || + im_extract_area( sec_in, t[1], overlap.left - bottom.left, overlap.top - bottom.top, overlap.width, overlap.height ) ) - return( -1 ); - if( im_LabQ2Lab( t1, t3 ) || im_LabQ2Lab( t2, t4 ) || - im_Lab2disp( t3, t5, im_col_displays( 1 ) ) || - im_Lab2disp( t4, t6, im_col_displays( 1 ) ) ) - return( -1 ); - - /* Extract the green. - */ - if( im_extract_band( t5, ref, 1 ) || - im_extract_band( t6, sec, 1 ) ) + return( -1 ); + if( ref_in->Coding == IM_CODING_LABQ ) { + if( im_LabQ2Lab( t[0], t[2] ) || + im_LabQ2Lab( t[1], t[3] ) || + im_Lab2disp( t[2], t[4], im_col_displays( 1 ) ) || + im_Lab2disp( t[3], t[5], im_col_displays( 1 ) ) || + im_extract_band( t[4], ref, 1 ) || + im_extract_band( t[5], sec, 1 ) ) return( -1 ); } else if( ref_in->Coding == IM_CODING_NONE ) { - IMAGE *t1 = im_open_local( out, "temp:9", "p" ); - IMAGE *t2 = im_open_local( out, "temp:10", "p" ); - IMAGE *t3 = im_open_local( out, "temp:11", "p" ); - IMAGE *t4 = im_open_local( out, "temp:12", "p" ); - - if( !t1 || !t2 || !t3 || !t4 ) - return( -1 ); - if( im_extract_area( ref_in, t1, - overlap.left, overlap.top, - overlap.width, overlap.height ) ) - return( -1 ); - if( im_extract_area( sec_in, t2, - overlap.left - bottom.left, overlap.top - bottom.top, - overlap.width, overlap.height ) ) - return( -1 ); - if( im_extract_band( t1, t3, bandno_in ) || - im_extract_band( t2, t4, bandno_in ) ) - return( -1 ); - if( im_scale( t3, ref ) || - im_scale( t4, sec ) ) + if( im_extract_band( t[0], t[2], bandno_in ) || + im_extract_band( t[1], t[3], bandno_in ) || + im_scale( t[2], ref ) || + im_scale( t[3], sec ) ) return( -1 ); } else { @@ -263,17 +217,68 @@ im__find_tboverlap( IMAGE *ref_in, IMAGE *sec_in, IMAGE *out, return( 0 ); } +/** + * im_tbmosaic: + * @ref: reference image + * @sec: secondary image + * @out: output image + * @bandno: band to search for features + * @xref: position in reference image + * @yref: position in reference image + * @xsec: position in secondary image + * @ysec: position in secondary image + * @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 overlap. + * + * @sec is positioned so that the pixel (@xsec, @ysec) lies on top of the + * pixel in @ref at (@xref, @yref). The overlap area is divided into three + * sections, 20 high-contrast points in band @bandno of image @ref are found + * in each, and each high-contrast point is searched for in @sec using + * @hwindowsize and @hsearchsize (see im_correl()). + * + * A linear model is fitted to the 60 tie-points, points a long way from the + * fit are discarded, and the model refitted until either too few points + * remain or the model reaches good agreement. + * + * The detected displacement is used with im_tbmerge() to join the two images + * together. + * + * @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_tbmerge(), im_lrmosaic(), im_insert(), im_global_balance(). + * + * Returns: 0 on success, -1 on error + */ int im_tbmosaic( IMAGE *ref, IMAGE *sec, IMAGE *out, - int bandno, + int bandno, int xref, int yref, int xsec, int ysec, - int halfcorrelation, int halfarea, + int hwindowsize, int hsearchsize, int balancetype, int mwidth ) { int dx0, dy0; double scale1, angle1, dx1, dy1; - IMAGE *ref2, *sec2; IMAGE *dummy; /* Correct overlap. dummy is just a placeholder used to ensure that @@ -284,7 +289,7 @@ im_tbmosaic( IMAGE *ref, IMAGE *sec, IMAGE *out, if( im__find_tboverlap( ref, sec, dummy, bandno, xref, yref, xsec, ysec, - halfcorrelation, halfarea, + hwindowsize, hsearchsize, &dx0, &dy0, &scale1, &angle1, &dx1, &dy1 ) ) { im_close( dummy ); @@ -292,16 +297,9 @@ im_tbmosaic( IMAGE *ref, IMAGE *sec, IMAGE *out, } im_close( dummy ); - /* Balance. - */ - if( im__balance( ref, sec, out, - &ref2, &sec2, - dx0, dy0, balancetype ) ) - return( -1 ); - /* Merge top-bottom. */ - if( im_tbmerge( ref2, sec2, out, dx0, dy0, mwidth ) ) + if( im_tbmerge( ref, sec, out, dx0, dy0, mwidth ) ) return( -1 ); return( 0 ); diff --git a/libvips/mosaicing/match.c b/libvips/mosaicing/match.c index 32bb3e7a..82b1547f 100644 --- a/libvips/mosaicing/match.c +++ b/libvips/mosaicing/match.c @@ -93,6 +93,26 @@ im__coeff( int xr1, int yr1, int xs1, int ys1, return( 0 ); } +/** + * im_match_linear: + * @ref: reference image + * @sec: secondary image + * @out: output image + * @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 + * + * Scale, rotate and translate @sec so that the tie-points line up. + * + * See also: im_match_linear_search(). + * + * Returns: 0 on success, -1 on error + */ int im_match_linear( IMAGE *ref, IMAGE *sec, IMAGE *out, int xr1, int yr1, int xs1, int ys1, @@ -123,6 +143,35 @@ im_match_linear( IMAGE *ref, IMAGE *sec, IMAGE *out, return( 0 ); } + +/** + * im_match_linear_search: + * @ref: reference image + * @sec: secondary image + * @out: output image + * @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 + * + * Scale, rotate and translate @sec so that the tie-points line up. + * + * Before performing the transformation, the tie-points are improved by + * searching an area of @sec of size @hsearchsize for a + * match of size @hwindowsize to @ref. + * + * This function will only work well for small rotates and scales. + * + * See also: im_match_linear(). + * + * Returns: 0 on success, -1 on error + */ int im_match_linear_search( IMAGE *ref, IMAGE *sec, IMAGE *out, int xr1, int yr1, int xs1, int ys1, @@ -133,19 +182,12 @@ im_match_linear_search( IMAGE *ref, IMAGE *sec, IMAGE *out, int xs4, ys4; double cor1, cor2; - /* Search for new tie-points. - */ if( im_correl( ref, sec, xr1, yr1, xs1, ys1, - hwindowsize, hsearchsize, &cor1, &xs3, &ys3 ) ) - return( -1 ); - if( im_correl( ref, sec, xr2, yr2, xs2, ys2, - hwindowsize, hsearchsize, &cor2, &xs4, &ys4 ) ) - return( -1 ); - - /* ... and match_linear. - */ - if( im_match_linear( ref, sec, out, - xr1, yr1, xs3, ys3, xr2, yr2, xs4, ys4 ) ) + hwindowsize, hsearchsize, &cor1, &xs3, &ys3 ) || + im_correl( ref, sec, xr2, yr2, xs2, ys2, + hwindowsize, hsearchsize, &cor2, &xs4, &ys4 ) || + im_match_linear( ref, sec, out, + xr1, yr1, xs3, ys3, xr2, yr2, xs4, ys4 ) ) return( -1 ); return( 0 ); diff --git a/libvips/mosaicing/merge.h b/libvips/mosaicing/merge.h index bf980d51..7783df67 100644 --- a/libvips/mosaicing/merge.h +++ b/libvips/mosaicing/merge.h @@ -93,8 +93,8 @@ int im__make_blend_luts(); int im__attach_input( REGION *or, REGION *ir, Rect *area ); int im__copy_input( REGION *or, REGION *ir, Rect *area, Rect *reg ); -Overlapping *im__build_mergestate( IMAGE *ref, IMAGE *sec, IMAGE *out, - int dx, int dy, int mwidth ); +Overlapping *im__build_mergestate( const char *domain, + IMAGE *ref, IMAGE *sec, IMAGE *out, int dx, int dy, int mwidth ); void *im__start_merge( IMAGE *out, void *, void * ); int im__merge_gen( REGION *or, void *seq, void *a, void * ); int im__stop_merge( void *seq, void *, void * ); diff --git a/libvips/mosaicing/mosaic1.c b/libvips/mosaicing/mosaic1.c index 5215c9c1..bfa82de3 100644 --- a/libvips/mosaicing/mosaic1.c +++ b/libvips/mosaicing/mosaic1.c @@ -1,4 +1,5 @@ /* 1st order mosaic functions + * * 31/7/97 JC * - done! * 12/9/97 JC @@ -12,6 +13,8 @@ * - better mosaic1 calcs ... was a bit broken * 14/12/04 * - works for LABQ as well + * 25/1/11 + * - gtk-doc */ /* @@ -206,7 +209,45 @@ rotjoin( IMAGE *ref, IMAGE *sec, IMAGE *out, joinfn jfn, return( 0 ); } -/* 1st order left-right merge. +/** + * im_lrmerge1: + * @ref: reference image + * @sec: secondary image + * @out: output image + * @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 + * @mwidth: maximum blend width + * + * This operation joins two images left-right (with @ref on the left) + * given a pair of tie-points. @sec is scaled and rotated as + * necessary before the join. + * + * @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_tbmerge1(), im_lrmerge(), im_insert(), im_global_balance(). + * + * Returns: 0 on success, -1 on error */ int im_lrmerge1( IMAGE *ref, IMAGE *sec, IMAGE *out, @@ -218,7 +259,45 @@ im_lrmerge1( IMAGE *ref, IMAGE *sec, IMAGE *out, xr1, yr1, xs1, ys1, xr2, yr2, xs2, ys2, mwidth ) ); } -/* 1st order top-bottom merge. +/** + * im_tbmerge1: + * @ref: reference image + * @sec: secondary image + * @out: output image + * @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 + * @mwidth: maximum blend width + * + * This operation joins two images top-bottom (with @ref on the top) + * given a pair of tie-points. @sec is scaled and rotated as + * necessary before the join. + * + * @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_lrmerge1(), im_tbmerge(), im_insert(), im_global_balance(). + * + * Returns: 0 on success, -1 on error */ int im_tbmerge1( IMAGE *ref, IMAGE *sec, IMAGE *out, @@ -333,39 +412,131 @@ rotjoin_search( IMAGE *ref, IMAGE *sec, IMAGE *out, joinfn jfn, return( 0 ); } -/* 1st order lr mosaic. +/** + * 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 halfcorrelation, int halfarea, + 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, - halfcorrelation, halfarea, balancetype, + hwindowsize, hsearchsize, balancetype, mwidth ) ); } -/* 1st order tb mosaic. +/** + * 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 halfcorrelation, int halfarea, + 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, - halfcorrelation, halfarea, balancetype, mwidth ) ); + hwindowsize, hsearchsize, balancetype, mwidth ) ); } #ifdef OLD diff --git a/libvips/mosaicing/mosaicing_dispatch.c b/libvips/mosaicing/mosaicing_dispatch.c index 754c66ed..1c8cdc7e 100644 --- a/libvips/mosaicing/mosaicing_dispatch.c +++ b/libvips/mosaicing/mosaicing_dispatch.c @@ -52,7 +52,41 @@ * @stability: Stable * @include: vips/vips.h * - * A set of operations for assembling large image mosaics. + * These functions are useful for joining many small images together to make + * one large image. They can cope with unstable contrast and arbitary sub-image + * layout, but will not do any geometric correction. Geometric errors should + * be removed before using these functions. + * + * The mosaicing functions can be grouped into layers: + * + * The lowest level functions are im_correl(), im_lrmerge() and im_tbmerge(). + * im_correl() + * searches a large image for a small sub-image, returning + * the position of the best sub-image match. im_lrmerge() and im_tbmerge() + * join two images together + * left-right or up-down with a smooth seam. + * + * Next, im_lrmosaic() and im_tbmosaic() use the + * search function plus the two low-level merge operations to join two images + * given just an approximate overlap as a start point. + * + * The functions im_lrmosaic1() and im_tbmosaic1() are + * first-order + * analogues of the basic mosaic functions: they take two approximate + * tie-points and use + * them to rotate and scale the right-hand or bottom image before starting to + * join. + * + * Finally, im_global_balance() can be used to remove contrast differences in + * a mosaic + * which has been assembled with these functions. It takes the mosaic apart, + * measures image contrast differences along the seams, finds a set of + * correction factors which will minimise these differences, and reassembles + * the mosaic. + * im_remosaic() uses the + * same + * techniques, but will reassemble the image from a different set of source + * images. * */