8cc76a6ba3
Also update LGPLv2.1 license text from the copy currently on the GNU website.
444 lines
11 KiB
C
444 lines
11 KiB
C
/* Join together images.
|
|
*
|
|
* find_mosaic x y file_name <root>.0x0.v <root>.0x1.v ...
|
|
*
|
|
* Where the image has been take with patches named as
|
|
*
|
|
* . .
|
|
* . .
|
|
* <root>.0x1.v <root>.1x1.v ..
|
|
* <root>.0x0.v <root>.1x0.v ..
|
|
*
|
|
* Uses im__find_lroverlap and im__find_tboverlap routines to make <root>.v.
|
|
*
|
|
* It stores the tie points between patches in a data_file.
|
|
*
|
|
* It uses partials on all IO by including tbmerge / lrmerge programs.
|
|
*
|
|
*
|
|
* Copyright (C) Feb./1995, Ahmed. Abbood
|
|
* National Gallery. London
|
|
*
|
|
*/
|
|
|
|
/*
|
|
|
|
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., 51 Franklin Street, Fifth Floor, Boston, MA
|
|
02110-1301 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 <stdarg.h>
|
|
|
|
#include <string.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <fcntl.h>
|
|
#include <locale.h>
|
|
|
|
#include <vips/vips.h>
|
|
|
|
#define NUM_FILES 1000
|
|
#define MAXPOINTS 60
|
|
int xoverlap;
|
|
int yoverlap;
|
|
|
|
extern int im_lrmerge();
|
|
extern int im_merge_analysis();
|
|
extern int im__find_lroverlap();
|
|
extern int im__find_tboverlap();
|
|
static int file_ptr = 0;
|
|
static IMAGE *in[ NUM_FILES ];
|
|
|
|
|
|
|
|
/* Strategy: build a tree describing the sequence of joins we want. Walk the
|
|
* tree assigning temporary file names, compile the tree into a linear
|
|
* sequence of join commands.
|
|
*/
|
|
|
|
|
|
|
|
/* Decoded file name info.
|
|
*/
|
|
static char *file_root = NULL;
|
|
static char *output_file = NULL;
|
|
static int width = 0; /* Number of frames across */
|
|
static int height = 0; /* Number of frames down */
|
|
|
|
static int file_list[ NUM_FILES ];
|
|
|
|
|
|
|
|
|
|
/* Find the root name of a file name. Return new, shorter, string.
|
|
*/
|
|
static char *
|
|
find_root( name )
|
|
char *name;
|
|
{ char *out = strdup( name );
|
|
char *p;
|
|
|
|
/* Chop off '.v'.
|
|
*/
|
|
if( !(p = strrchr( out, '.' )) ) {
|
|
im_error( "find_mosaic",
|
|
_( "bad file name format '%s'" ), name );
|
|
free( out );
|
|
return( NULL );
|
|
}
|
|
*p = '\0';
|
|
|
|
/* Chop off nxn.
|
|
*/
|
|
if( !(p = strrchr( out, '.' )) ) {
|
|
im_error( "find_mosaic",
|
|
_( "bad file name format '%s'" ), name );
|
|
free( out );
|
|
return( NULL );
|
|
}
|
|
*p = '\0';
|
|
|
|
return( out );
|
|
}
|
|
|
|
/* Find the x position of a file name (extract n from <root>.nxm.v).
|
|
*/
|
|
static int
|
|
find_x( name )
|
|
char *name;
|
|
{ int n;
|
|
char *p;
|
|
char *out = strdup( name );
|
|
|
|
/* Chop off '.v'.
|
|
*/
|
|
if( !(p = strrchr( out, '.' )) ) {
|
|
im_error( "find_mosaic",
|
|
_( "bad file name format '%s'" ), name );
|
|
free( out );
|
|
return( -1 );
|
|
}
|
|
*p = '\0';
|
|
|
|
/* Find '.nxm'.
|
|
*/
|
|
if( !(p = strrchr( out, '.' )) ) {
|
|
im_error( "find_mosaic",
|
|
_( "bad file name format '%s'" ), name );
|
|
free( out );
|
|
return( -1 );
|
|
}
|
|
|
|
/* Read out x posn.
|
|
*/
|
|
if( sscanf( p, ".%dx%*d", &n ) != 1 ) {
|
|
im_error( "find_mosaic",
|
|
_( "bad file name format '%s'" ), name );
|
|
free( out );
|
|
return( -1 );
|
|
}
|
|
|
|
return( n );
|
|
}
|
|
|
|
/* Find the y position of a file name (extract m from <root>.nxm.v).
|
|
*/
|
|
static int
|
|
find_y( name )
|
|
char *name;
|
|
{ int m;
|
|
char *p;
|
|
char *out = strdup( name );
|
|
|
|
/* Chop off '.v'.
|
|
*/
|
|
if( !(p = strrchr( out, '.' )) ) {
|
|
im_error( "find_mosaic",
|
|
_( "bad file name format '%s'" ), name );
|
|
free( out );
|
|
return( -1 );
|
|
}
|
|
*p = '\0';
|
|
|
|
/* Find '.nxm'.
|
|
*/
|
|
if( !(p = strrchr( out, '.' )) ) {
|
|
im_error( "find_mosaic",
|
|
_( "bad file name format '%s'" ), name );
|
|
free( out );
|
|
return( -1 );
|
|
}
|
|
|
|
/* Read out y posn.
|
|
*/
|
|
if( sscanf( p, ".%*dx%d", &m ) != 1 ) {
|
|
im_error( "find_mosaic",
|
|
_( "bad file name format '%s'" ), name );
|
|
free( out );
|
|
return( -1 );
|
|
}
|
|
|
|
free( out );
|
|
return( m );
|
|
}
|
|
|
|
|
|
|
|
|
|
static int
|
|
mosaic_analysis(int width, int height,IMAGE **inp, IMAGE *out,
|
|
int xoff, int yoff, int *vxdisp, int *vydisp,int *hxdisp, int *hydisp) {
|
|
|
|
|
|
|
|
int i, j, dx, dy, curr_im, fx, fy;
|
|
int halfcorsize, halfareasize;
|
|
int mincorsize, minareasize;
|
|
int prev_row, curr_row, curr_disp_x, curr_disp_y;
|
|
double scale1, angle1, dx1, dy1;
|
|
|
|
|
|
curr_im = -1;
|
|
curr_disp_x = -1;
|
|
curr_disp_y = -1;
|
|
dy = -1;
|
|
for(i=0; i<=height; i++){
|
|
for(j=0; j<=width; j++){
|
|
++curr_im;
|
|
halfcorsize = 5;
|
|
halfareasize = 14;
|
|
dx = xoff - inp[curr_im]->Xsize;
|
|
dy = yoff - inp[curr_im]->Ysize;
|
|
|
|
if( ( j < width ) && ( width > 0 ) ){
|
|
if( dx < 0 ){
|
|
mincorsize = (int)(inp[curr_im]->Xsize + dx - 1)/6;
|
|
minareasize = (int)(inp[curr_im]->Xsize + dx
|
|
- 3*halfcorsize -1)/2 - mincorsize;
|
|
if(mincorsize > halfcorsize)
|
|
mincorsize = halfcorsize;
|
|
if( minareasize > 0 ){
|
|
if( minareasize < halfareasize ){
|
|
if( minareasize >
|
|
(int)(halfcorsize +(int)(halfcorsize/2 + 1))){
|
|
halfareasize = minareasize;
|
|
}
|
|
else if(mincorsize > 2){
|
|
halfcorsize=mincorsize;
|
|
halfareasize=(int)(mincorsize+mincorsize/2 +1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if( ( inp[curr_im]->Xsize < xoff ) || ( inp[curr_im+1]->Xsize < xoff ) ||
|
|
( inp[curr_im]->Ysize < yoff ) || ( inp[curr_im]->Ysize < yoff) ){
|
|
++curr_disp_x;
|
|
hxdisp[curr_disp_x] = 0;
|
|
hydisp[curr_disp_x] = 0;
|
|
}
|
|
else{
|
|
if ( im__find_lroverlap(inp[curr_im], inp[curr_im+1],
|
|
out, 0,
|
|
(int)(inp[curr_im]->Xsize -xoff/2),
|
|
(int)(inp[curr_im]->Ysize /2),
|
|
(int)(xoff/2), (int)(inp[curr_im+1]->Ysize /2),
|
|
halfcorsize, halfareasize , &fx, &fy,
|
|
&scale1, &angle1, &dx1, &dy1 ) == -1 )
|
|
error_exit("Unable to im__find_lroverlap");
|
|
|
|
++curr_disp_x;
|
|
hxdisp[curr_disp_x] = inp[curr_im]->Xsize - xoff + fx;
|
|
hydisp[curr_disp_x] = fy;
|
|
}
|
|
}
|
|
}
|
|
if( ( i < height ) && ( height > 0 ) ){
|
|
curr_row = curr_im+1+(int)(width/2);
|
|
prev_row = curr_im - width+(int)(width/2);
|
|
halfcorsize = 5;
|
|
halfareasize = 14;
|
|
|
|
if( dy < 0){
|
|
mincorsize = (int)(inp[prev_row]->Ysize + dy - 1)/6;
|
|
minareasize = (int)(inp[prev_row]->Ysize + dy
|
|
- 3*halfcorsize -1)/2 - mincorsize;
|
|
if(mincorsize > halfcorsize)
|
|
mincorsize = halfcorsize;
|
|
if( minareasize > 0 ){
|
|
if( minareasize < halfareasize ){
|
|
if( minareasize >
|
|
(int)(halfcorsize +(int)(halfcorsize/2 + 1))){
|
|
halfareasize = minareasize;
|
|
}
|
|
else if(mincorsize > 2){
|
|
halfcorsize=mincorsize;
|
|
halfareasize=(int)(mincorsize+mincorsize/2 +1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if( ( inp[curr_row]->Xsize < xoff ) || ( inp[prev_row]->Xsize < xoff ) ||
|
|
( inp[curr_row]->Ysize < yoff ) || ( inp[prev_row]->Ysize < yoff ) ){
|
|
++curr_disp_y;
|
|
vxdisp[curr_disp_y] = 0;
|
|
vydisp[curr_disp_y] = 0;
|
|
}
|
|
else{
|
|
if ( im__find_tboverlap(inp[prev_row], inp[curr_row],
|
|
out, 0,
|
|
(int)(inp[prev_row]->Xsize/2 ),
|
|
(int)(inp[prev_row]->Ysize - yoff/2 ),
|
|
(int)(inp[curr_row]->Xsize/2 ), (int)(yoff/2),
|
|
halfcorsize, halfareasize, &fx, &fy,
|
|
&scale1, &angle1, &dx1, &dy1 ) == -1 )
|
|
error_exit("Unable to im__find_tboverlap");
|
|
|
|
|
|
++curr_disp_y;
|
|
vxdisp[curr_disp_y] = fx;
|
|
vydisp[curr_disp_y] = inp[prev_row]->Ysize - yoff + fy;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
return ( 0 );
|
|
}
|
|
|
|
|
|
|
|
int
|
|
main( argc, argv )
|
|
int argc;
|
|
char **argv;
|
|
{
|
|
int i, n, j, k;
|
|
char name[ 1000 ];
|
|
FILE *fp;
|
|
char *r;
|
|
IMAGE *out;
|
|
int vxdisp[NUM_FILES + 1] ;
|
|
int vydisp[NUM_FILES + 1] ;
|
|
int hxdisp[NUM_FILES + 1] ;
|
|
int hydisp[NUM_FILES + 1] ;
|
|
|
|
if( im_init_world( argv[0] ) )
|
|
error_exit( "unable to start VIPS" );
|
|
textdomain( GETTEXT_PACKAGE );
|
|
setlocale( LC_ALL, "" );
|
|
|
|
/* Too many?
|
|
*/
|
|
if( argc > NUM_FILES + 1 )
|
|
error_exit( "Too many files to merge" );
|
|
for(i=0; i< NUM_FILES; i++)
|
|
file_list[i] = 0;
|
|
/* Too few?
|
|
*/
|
|
if( argc == 1 )
|
|
error_exit( "usage: xoverlap yoverlap file_name "
|
|
"<root>.0x0.v <root>.0x1.v ..." );
|
|
xoverlap = atoi(argv[1]);
|
|
yoverlap = atoi(argv[2]);
|
|
fp = fopen( argv[3] , "w" );
|
|
|
|
for( i = 4; i < argc; i++ ){
|
|
/* Find/check root.
|
|
*/
|
|
if( !file_root ) {
|
|
file_root = find_root( argv[i] );
|
|
if( !file_root )
|
|
error_exit( "error at file_root" );
|
|
}
|
|
else {
|
|
if( !(r = find_root( argv[i] )) )
|
|
error_exit( "Error in reading parameters" );
|
|
if( strcmp( r, file_root ) != 0 )
|
|
error_exit( "Not all roots identical!" );
|
|
}
|
|
|
|
/* Read out position.
|
|
*/
|
|
if( (n = find_x( argv[i] )) < 0 )
|
|
error_exit( "Error in reading file name" );
|
|
if( n > width - 1 )
|
|
width = n;
|
|
if( (n = find_y( argv[i] )) < 0 )
|
|
error_exit( "Error in reading file name" );
|
|
if( n > height - 1 )
|
|
height = n;
|
|
|
|
file_list[n] +=1;
|
|
}
|
|
|
|
/* Make output name. and store them in an array.
|
|
*/
|
|
if( !(out = im_open( "tmp.v", "t" )) )
|
|
error_exit("unable to open file for output");
|
|
|
|
file_ptr =0;
|
|
for(i=height; i>=0; i--)
|
|
for(j=0; j<file_list[i]; j++){
|
|
im_snprintf( name, 1024, "%s.%dx%d.v", file_root,j,i );
|
|
output_file = strdup( name );
|
|
if( !(in[file_ptr] = im_open( output_file, "r" )) )
|
|
error_exit("unable to open %s for input",output_file);
|
|
++file_ptr;
|
|
|
|
}
|
|
|
|
mosaic_analysis(width,height,in,out,xoverlap,yoverlap,vxdisp,vydisp,hxdisp,hydisp);
|
|
k = 0;
|
|
for( i=0; i<height; i++ ){
|
|
for( j=0; j<width; j++ ){
|
|
fprintf(fp,"%d %d ", hxdisp[k] , hydisp[k] );
|
|
k++;
|
|
}
|
|
fprintf(fp,"\n");
|
|
}
|
|
|
|
for( i=0; i<height; i++ )
|
|
fprintf(fp,"%d %d\n", vxdisp[i] , vydisp[i] );
|
|
|
|
|
|
for(i=0; i<file_ptr; i++)
|
|
if( im_close(in[i]) == -1)
|
|
error_exit("unable to close partial file");
|
|
if( im_close(out) == -1)
|
|
error_exit("unable to close\n ");
|
|
fclose( fp );
|
|
|
|
vips_shutdown();
|
|
|
|
return( 0 );
|
|
}
|