#See perldoc at end of script for help use strict; # This hash contains reasonable guesses of the number of images_per_row for # any given total number of images...add more as necessary %main::guessHash = ("2", [2], "3", [3], "4", [4, 2], "5", [5], "6", [6, 3], "7", [7], "8", [8, 4], "9", [9, 3], "10", [10, 5], "11", [11], "12", [6, 4, 3], "13", [13], "14", [14, 7], "15", [5], "16", [8, 4], "17", [17], "18", [9, 6], "19", [19], "20", [10, 5, 4], "21", [7], "22", [11], "23", [23], "24", [12, 8], "25", [5], "26", [13], "27", [9], "28", [14, 7], "29", [29], "30", [15, 10], "31", [31], "32", [16, 8], "33", [33], "34", [17], "35", [35], "36", [18, 9, 6], "49", [7] ); sub getImagesFromProjectFile() { my $ptp_file = $_[0]; my @file_list; my $a_file; open PTP, $ptp_file or die "Cant open $ptp_file: $!\n"; #match lines like this one: ##-imgfile 2048 3072 "IMG_2336.JPG" while () { if (/-imgfile.*\"(.*)\"/i) { $a_file = $1; push @file_list, $a_file; } } close PTP; return @file_list; } sub guessImagesPerRow() { my ($totalImages, $guess_idx) = @_; my $ary_ref = $main::guessHash{$totalImages}; my @guess_ary = @{$ary_ref}; return $guess_ary[$guess_idx]; } sub process() { my ($images_per_row, $left_to_right, $bottom_to_top, $file_list_ref) = @_; my ($width, $height, $col_ctr, $row_ctr) = (0,0,0,0); my ($firstImageName, $lastImageName, $outputName, $cmd, $files, $anImage, $arrayRef); my (@aRow, @allImages, @anArray); my @file_list = @{$file_list_ref}; my $direction = $left_to_right; #get first and last images in sequence $firstImageName = $file_list[0]; $lastImageName = $file_list[$#file_list]; foreach (@file_list) { #assume all images are the same dimensions...check only once if ($width == 0 || $height == 0) { ($width, $height) = split /\|/, `identify -format \"%w|%h" \"$_\"`; $width = sprintf ("%d", $width/20); $height = sprintf ("%d", $height/20) } if ($direction == 1) {push @aRow, $_;} else {unshift @aRow, $_;} $col_ctr++; if ($col_ctr == $images_per_row) { $row_ctr++; $col_ctr = 0; #alternate direction for next row $direction = ($direction==1) ? 0 : 1; if ($bottom_to_top) {unshift @allImages, [@aRow];} else {push @allImages, [@aRow];} @aRow = (); } } #create outputname @anArray = split /[\\\/\.]/, $firstImageName; $outputName = @anArray[$#anArray-1]; @anArray = split /[\\\/\.]/, $lastImageName; $outputName .= "_" . @anArray[$#anArray-1]; $outputName .= "_" . $images_per_row ."x". $row_ctr; $outputName .= ($left_to_right==1) ? "_L2R" : "_R2L"; $outputName .= "_components.jpg"; #create the input images in the correct order for montage.exe foreach $arrayRef (@allImages) { @anArray = @{$arrayRef}; foreach $anImage (@anArray) {$files .= "\"$anImage\" ";} } #now create the final image montage table $cmd = "montage -geometry $width" ."x" . $height . "+3+3 -tile ". $images_per_row ."x". $row_ctr . " $files $outputName"; print "$cmd\n\n"; system($cmd); } sub main() { my $images_per_row = defined($ARGV[0]) ? $ARGV[0] : 3; my $left_to_right = defined($ARGV[1]) ? $ARGV[1] : 1; my $bottom_to_top = defined($ARGV[2]) ? $ARGV[2] : 0; my (@file_list, @stdin); my $file; undef @ARGV; #read all files @stdin = (<>); #iterate and process foreach $file (@stdin) { chomp $file; print "File: " . $file . "\n"; if ($file =~ /\.pt[ps]$/i) { @file_list = &getImagesFromProjectFile($file); my $guess_ctr = 0; while () { $images_per_row = &guessImagesPerRow($#file_list + 1, $guess_ctr); $guess_ctr++; last if ($images_per_row <= 0); #do left-to-right, and right-to-left... &process($images_per_row, 1, $bottom_to_top, [@file_list]); &process($images_per_row, 0, $bottom_to_top, [@file_list]); } @file_list = (); } else { push @file_list, $file; } } if ($#file_list >= 0) { &process($images_per_row, $left_to_right, $bottom_to_top, [@file_list]); } } &main(); exit; __END__ =head1 makePanoMosaic.pl Author: Max Lyons (maxlyons@tawbaware.com) Date: October 2003 Description: This script constructs an "image table" showing the sequence of individual images used to create a panoramic/mosaic image. This script assumes that you take your images in a similar fashion to me...starting at a (top) corner, photographing one row, moving the camera down and a row and photographing the next row in the opposite direction. Repeat until complete. The sequence should look something like this: ------------------- | 1 | 2 | 3 | ------------------- | 6 | 5 | 4 | ------------------- | 7 | 8 | 9 | ------------------- If not, then this script probably won't work without modification. This script expects a list of image names or a list of PTAssembler project files as STDIN. This script also expects three arguments. Requirements: This script requires ImageMagick (www.imagemagick.org) to be installed and available on the system path. Usage: STDIN | perl makePanoMosaic.pl [arg1] [arg2] [arg3] The script reads a list of files from standard input. The easiest way to feed the appropriate list is using the "pipe" symbol (|) like this: dir /b *.jpg | perl makePanoMosaic.pl [arg1] [arg2] [arg3] dir /b *.ptp | perl makePanoMosaic.pl If processing a list of images (i.e. not PTAssembler project files), this script expects three arguments: Arg 1 (required): Number of images in each row (e.g. "3") Arg 2 (optional): "1" if started at top left (default), 0 if top right Arg 3 (optional): "1" if started at bottom, 0 if started at top (default) If processing a list of PTAssembler project files (i.e. not image files), this script ignores the first and second arguments, but does use the third. When processing PTAssembler project files, this script produces multiple output images for each script...guessing as to the appropriate number of images per row and image sequence direction (left to right, or right to left). It does not read the yaw, pitch or roll values from the PTAssembler scripts, because it is intended to be used on "blank" projects for which these values have not yet been set. Examples: dir /b *.jpg | perl -S makePanoMosaic.pl 3 1 0 dir /b *.ptp | perl -S makePanoMosaic.pl License: This script is freeware, but provided with no support or warranty. The Author disclaims any and all resposibility for any consequences that result for the use of this script.