| /* @(#) 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 <config.h> |
| #endif /*HAVE_CONFIG_H*/ |
| #include <vips/intl.h> |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <math.h> |
| |
| #include <vips/vips.h> |
| |
| #include "mosaic.h" |
| |
| #ifdef WITH_DMALLOC |
| #include <dmalloc.h> |
| #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_error( "im__lrcalcon", "%s", |
| _( "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_error( "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_error( "im__lrcalcon", "%s", _( "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 ); |
| } |