| /* Join together images |
| * |
| * mergeup x y file_name output_dir <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 .. |
| * |
| * |
| * Tries to generate optimal join sequence. Does not require any intermidiate |
| * files for temporary storage. |
| * 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., 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 <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 |
| |
| static int xoverlap; |
| static int yoverlap; |
| |
| 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 ]; |
| |
| |
| static int |
| im_phmerge( Rect *larea, Rect *rarea, Rect *outarea ) |
| { |
| |
| Rect overlap; |
| |
| |
| /* Compute overlap. |
| */ |
| im_rect_intersectrect( larea, rarea, &overlap ); |
| |
| outarea->width = rarea->left + rarea->width; |
| outarea->height = overlap.height; |
| outarea->top = overlap.top; |
| outarea->left = larea->left; |
| |
| return( 0 ); |
| } |
| |
| |
| static int |
| im_pvmerge( Rect *tarea, Rect *barea, Rect *outarea ) |
| { |
| |
| Rect overlap; |
| |
| |
| /* Compute overlap. |
| */ |
| im_rect_intersectrect( tarea, barea, &overlap ); |
| |
| outarea->width = overlap.width; |
| outarea->height = barea->top + barea->height ; |
| outarea->left = overlap.left; |
| outarea->top = tarea->top; |
| |
| return( 0 ); |
| } |
| |
| |
| |
| |
| static int |
| merge_analysis(int width,int height,IMAGE **in,int xoff, |
| int yoff,int *vxdisp,int *vydisp,int *hxdisp, |
| int *hydisp,Rect *hrect,Rect *vrect) |
| { |
| int i,j; |
| int curr_im,offset; |
| int curr_x, curr_y; |
| Rect larea, rarea, barea; |
| |
| |
| |
| curr_im = -1; |
| curr_x = -1; |
| curr_y = -1; |
| for(i=0; i<=height; i++){ |
| for(j=0; j<=width; j++){ |
| ++curr_im; |
| if( width == 0 ){ |
| ++curr_x; |
| hrect[curr_x].width = in[curr_im]->Xsize; |
| hrect[curr_x].height= in[curr_im]->Ysize; |
| hrect[curr_x].top = 0; |
| hrect[curr_x].left = 0; |
| } |
| else{ |
| if( j == 0){ |
| ++curr_x; |
| |
| /* Area occupied by left image. |
| */ |
| larea.left = 0; |
| larea.top = 0; |
| larea.height = in[curr_im]->Ysize; |
| larea.width = in[curr_im]->Xsize; |
| /* Area occupied by right image. |
| */ |
| if( in[curr_im]->Xsize < xoff ) |
| offset = 0; |
| else |
| offset =xoff; |
| rarea.left = in[curr_im]->Xsize - (offset + hxdisp[curr_x]) ; |
| rarea.top = hydisp[curr_x]; |
| rarea.width = in[curr_im+1]->Xsize; |
| rarea.height = in[curr_im+1]->Ysize; |
| im_phmerge( &larea, &rarea, &hrect[curr_x] ); |
| } |
| else if( j < width ){ |
| ++curr_x; |
| |
| /* Area occupied by right image. |
| */ |
| if( in[curr_im+1]->Xsize < xoff ) |
| offset = 0; |
| else |
| offset =xoff; |
| |
| rarea.left = hrect[curr_x -1].width - (offset + hxdisp[curr_x]) ; |
| rarea.top = hydisp[curr_x]; |
| rarea.width = in[curr_im+1]->Xsize; |
| rarea.height = in[curr_im+1]->Ysize; |
| im_phmerge( &hrect[curr_x -1], &rarea, &hrect[curr_x] ); |
| } |
| } |
| } |
| if( i > 0 ){ |
| ++curr_y; |
| |
| /* Area occupied by bottom image in output. |
| */ |
| barea.left = vxdisp[curr_y]; |
| barea.width = hrect[curr_x].width; |
| barea.height = hrect[curr_x].height; |
| if( in[curr_x - width]->Ysize < yoff ) |
| offset = 0; |
| else |
| offset = yoff; |
| if( i == 1){ |
| barea.top = hrect[curr_x - width].height - offset - vydisp[curr_y] ; |
| im_pvmerge( &hrect[curr_x - width], &barea, &vrect[curr_y] ); |
| } |
| else{ |
| barea.top = vrect[curr_y - 1].height - yoff - vydisp[curr_y] ; |
| im_pvmerge( &vrect[curr_y -1], &barea, &vrect[curr_y] ); |
| } |
| } |
| } |
| |
| |
| return( 0 ); |
| } |
| |
| /* 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 ); |
| } |
| |
| |
| |
| |
| |
| |
| /* Join two frames left-right. Have to open them and find their sizes. |
| */ |
| static int |
| join_leftright(IMAGE *left, IMAGE *right, IMAGE *out, int dx, int dy ) |
| { |
| |
| if (im_lrmerge(left, right, out, dx, dy, 20) == -1) |
| return( -1 ); |
| return( 0 ); |
| } |
| |
| |
| /* Join two frames up-down. Have to open them and find their sizes. |
| */ |
| static int |
| join_updown( IMAGE *top, IMAGE *bottom, IMAGE *out, int dx, int dy ) |
| { |
| if (im_tbmerge(top, bottom, out, dx, dy, 20) == -1) |
| return( -1 ); |
| |
| return( 0 ); |
| } |
| |
| |
| static int |
| merge_up( int width, int height, IMAGE **inp, IMAGE *outp, int xoff, int yoff, |
| int *hxdisp, int *hydisp, Rect *vrect ) |
| { |
| int dx,dy,first_row; |
| int i, j, partial_no, in_no; |
| IMAGE **p_img; |
| char name[29]; |
| int v_no, h_no; |
| |
| |
| |
| p_img = (IMAGE **) malloc(1 + 3 * width * height * sizeof(IMAGE *)); |
| if( p_img == NULL ){ |
| im_error( "mergeup", "%s", _( "allocation failure in mergeup") ); |
| return( -1 ); |
| } |
| partial_no = 0; |
| v_no = 0; |
| h_no = 0; |
| in_no = 0; |
| first_row = 0; |
| |
| if( (width == 0 ) && (height == 0 ) ){ |
| im_error( "mergeup", "%s", _( "Need more than one image") ); |
| return( -1 ); |
| } |
| |
| |
| for(i=0; i<=height; i++){ |
| for(j=0; j<=width; j++){ |
| p_img[partial_no] = inp[in_no]; |
| ++partial_no; |
| if( j != 0 ){ |
| im_snprintf( name, 29, "partial_img.%d.v",partial_no ); |
| if( !( p_img[partial_no] = im_open( name, "p" )) ){ |
| free(p_img); |
| return( -1 ); |
| } |
| ++partial_no; |
| dy = hydisp[h_no ] ; |
| dx = -p_img[partial_no-3]->Xsize + hxdisp[h_no] + xoff ; |
| |
| if( (height == 0) && ( j == width) ) |
| join_leftright( p_img[partial_no-3], |
| p_img[partial_no-2],outp,dx,dy ); |
| else |
| join_leftright( p_img[partial_no-3], |
| p_img[partial_no-2],p_img[partial_no-1],dx,dy ); |
| ++h_no; |
| } |
| ++in_no; |
| } |
| |
| if( first_row == 0) |
| first_row = partial_no - 1; |
| |
| if( ( i > 0 ) || ( height == 0) ){ |
| if( i < height ){ |
| im_snprintf( name, 29, "partial_img.%d.v", partial_no ); |
| if( !( p_img[partial_no] = im_open( name, "p" )) ){ |
| free(p_img); |
| return( -1 ); |
| } |
| ++partial_no; |
| |
| dy = -( vrect[v_no].height - p_img[partial_no-2]->Ysize ); |
| dx = vrect[v_no].left ; |
| |
| ++v_no; |
| join_updown( p_img[first_row], |
| p_img[partial_no-2], p_img[partial_no-1],dx,dy ); |
| first_row = partial_no-1; |
| } |
| else{ |
| dy = -( vrect[v_no].height - p_img[partial_no-1]->Ysize ); |
| dx = vrect[v_no].left ; |
| |
| join_updown( p_img[first_row], p_img[partial_no-1],outp,dx,dy ); |
| } |
| } |
| } |
| 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] ; |
| Rect hrect[NUM_FILES]; |
| Rect vrect[NUM_FILES]; |
| |
| 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 output_dir " |
| "<root>.0x0.v <root>.0x1.v ..." ); |
| xoverlap = atoi(argv[1]); |
| yoverlap = atoi(argv[2]); |
| fp = fopen( argv[3] , "r" ); |
| |
| for( i = 5; 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. |
| */ |
| im_snprintf( name, 1000, "%s/paint.hr.v", argv[4] ); |
| if( !(out = im_open( name, "w" )) ) |
| 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, 1000, "%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; |
| |
| } |
| |
| k = 0; |
| for( i=0; i<height; i++ ){ |
| for( j=0; j<width; j++ ){ |
| if(fscanf(fp,"%d %d ", &hxdisp[k] , &hydisp[k])!=2) |
| error_exit("argh"); |
| k++; |
| } |
| if(fscanf(fp,"\n")!=0) |
| error_exit("argh3"); |
| } |
| |
| for( i=0; i<height; i++ ) |
| if(fscanf(fp,"%d %d\n", &vxdisp[i] , &vydisp[i])!=2) |
| error_exit("argh2"); |
| |
| merge_analysis(width,height,in,xoverlap,yoverlap,vxdisp,vydisp,hxdisp,hydisp,hrect,vrect); |
| merge_up( width, height, in, out, xoverlap, yoverlap, hxdisp, hydisp, vrect ); |
| |
| 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 "); |
| |
| return( 0 ); |
| } |