blob: 298da344b68b03163e09931e094ebd77bffc80e3 [file] [log] [blame]
/* @(#) 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 );
}