/* @(#) Functions which takes an initial estimate of deltax, deltay * @(#) between reference and secondary images (probably from the scanner), * @(#) and looks in three areas of the overlapping part of the reference image * @(#) corresponding to reference and secondary. For every other halfreasize * @(#) point of the three areas of the reference image * @(#) the contrast is calculated * @(#) an area 2*halfcorsize+1 centered at this point * @(#) Results are saved in the structure points * @(#) The function expects the following valid data in points: * @(#) deltax, deltay, nopoints, halfcorsize, halfareasize * @(#) and fills in the memebers: * @(#) x, y_reference[], contrast and x,y_secondary[], * @(#) based on deltax and deltay * @(#) Input image should are either memory mapped or in a buffer. * @(#) The initial setting checks all points of reference * @(#) in the overlapping area of the images to be mosaiced * @(#) To speed up the procedure the ysize of the box can be reduced * @(#) during the calculation of the ysize * @(#) An easy way is to change FACTOR to 1 2 or 3. * @(#) The calculation of the contrast is carried out based on bandno only. * @(#) The variable bandno should be between 1 and ref->Bands * @(#) * @(#) int im_lrcalcon( ref, sec, bandno, points ) * @(#) IMAGE *ref, *sec; * @(#) int bandno; * @(#) TIE_POINTS *points; see mosaic.h * @(#) * @(#) Returns 0 on sucess and -1 on error. * @(#) * * Copyright: 1990, N. Dessipris. * * Author: Nicos Dessipris * Written on: 20/12/1990 * Modified on : 18/04/1991 * 8/7/93 JC * - now calls im_incheck() * 12/7/95 JC * - reworked * - what a lot of horrible old code there was too * 24/1/97 JC * - now ignores black stuff (all bands zero) when selecting possible tie * points, part of new mosaic policy * 26/9/97 JC * - now skips all-black windows, instead of any-black windows * 11/4/01 JC * - ooops, < 0 should have been <= 0 * 10/3/03 JC * - better error message for overlap too small */ /* This file is part of VIPS. VIPS is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk */ #ifdef HAVE_CONFIG_H #include #endif /*HAVE_CONFIG_H*/ #include #include #include #include #include #include "mosaic.h" #ifdef WITH_DMALLOC #include #endif /*WITH_DMALLOC*/ /* A position and contrast. */ typedef struct { int x, y; int cont; } PosCont; /* Search a window for black pelss ... true if window is all black. * One-band uchar only. */ static int all_black( IMAGE *im, int xpos, int ypos, int winsize ) { const int hwinsize = (winsize - 1)/2; const int left = xpos - hwinsize; const int top = ypos - hwinsize; const int ls = im->Xsize; int x, y; PEL *line; /* Loop over image. */ line = (PEL *) im->data + top*ls + left; for( y = 0; y < winsize; y++ ) { for( x = 0; x < winsize; x++ ) if( line[x] ) /* Not all black. */ return( 0 ); line += ls; } return( -1 ); } /* Calculate a value for 'contrast' within a window * of (odd) size winsize*winsize centered at location (xpos, ypos). * One band uchar only, */ static int calculate_contrast( IMAGE *im, int xpos, int ypos, int winsize ) { const int hwinsize = (winsize - 1)/2; const int left = xpos - hwinsize; const int top = ypos - hwinsize; const int ls = im->Xsize; int x, y; PEL *line, *p; int total; line = (PEL *) im->data + top*ls + left; for( total = 0, y = 0; y < winsize-1; y++ ) { p = line; for( x = 0; x < winsize-1; x++ ) { const int lrd = (int) p[0] - p[1]; const int tbd = (int) p[0] - p[ls]; total += abs( lrd ) + abs( tbd ); p += 1; } line += ls; } return( total ); } /* Compare two PosConts for qsort. */ static int pos_compare( const void *vl, const void *vr ) { PosCont *l = (PosCont *) vl; PosCont *r = (PosCont *) vr; return( r->cont - l->cont ); } /* Search an area for the n best contrast areas. */ int im__find_best_contrast( IMAGE *im, int xpos, int ypos, int xsize, int ysize, int xarray[], int yarray[], int cont[], int nbest, int hcorsize ) { /* Geometry: we test squares of size windowsize, overlapping by * hcorsize. */ const int windowsize = 2 * hcorsize + 1; /* Number of squares we can fit in area. */ const int nacross = (xsize - windowsize + hcorsize) / hcorsize; const int ndown = (ysize - windowsize + hcorsize) / hcorsize; /* Number of squares we search. */ int elms; /* All points in this area. */ PosCont *pc; int x, y, i; if( nacross <= 0 || ndown <= 0 ) { im_errormsg( "im__lrcalcon: mosaicing overlap too small for " "your search size" ); return( -1 ); } /* Malloc space for 3 int arrays, to keep the int coordinates and * the contrast. */ if( !(pc = IM_ARRAY( NULL, nacross * ndown, PosCont )) ) return( -1 ); /* Find contrast for each area. */ for( i = 0, y = 0; y < ndown; y++ ) for( x = 0; x < nacross; x++ ) { const int left = xpos + x * hcorsize; const int top = ypos + y * hcorsize; /* Skip this position if it is all black. */ if( all_black( im, left, top, windowsize ) ) continue; /* Find contrast and note. */ pc[i].x = left; pc[i].y = top; pc[i].cont = calculate_contrast( im, left, top, windowsize ); i++; } /* Note number found. */ elms = i; /* Found enough tie-points? */ if( elms < nbest ) { im_errormsg( "im_mosaic: found %d tie-points, need at least %d", elms, nbest ); im_free( pc ); return( -1 ); } /* Sort areas by contrast. */ qsort( pc, elms, sizeof( PosCont ), pos_compare ); /* Copy the n best into our parent. */ for( i = 0; i < nbest; i++ ) { xarray[i] = pc[i].x; yarray[i] = pc[i].y; cont[i] = pc[i].cont; } im_free( pc ); return( 0 ); } int im__lrcalcon( IMAGE *ref, TIE_POINTS *points ) { /* Geometry: border we must leave around each area. */ const int border = points->halfareasize; /* Height of an area. */ const int aheight = ref->Ysize / AREAS; /* Number of points we find in each area. */ const int len = points->nopoints / AREAS; int i; Rect area; /* Make sure we can read image. */ if( im_incheck( ref ) ) return( -1 ); if( ref->Bands != 1 || ref->BandFmt != IM_BANDFMT_UCHAR ) { im_errormsg( "im__lrcalcon: not 1-band uchar image" ); return( -1 ); } /* Define bits to search for high-contrast areas. Need to be able to * fit at least 1 window in. */ area.height = aheight; area.width = ref->Xsize; area.left = 0; area.top = 0; im_rect_marginadjust( &area, -border ); area.width--; area.height--; /* Loop over areas, finding points. */ for( i = 0; area.top < ref->Ysize; area.top += aheight, i++ ) if( im__find_best_contrast( ref, area.left, area.top, area.width, area.height, points->x_reference + i*len, points->y_reference + i*len, points->contrast + i*len, len, points->halfcorsize ) ) return( -1 ); return( 0 ); }