#!/usr/bin/perl use File::Basename; use File::Copy; use Data::Dumper; use Time::localtime; use Switch; use POSIX qw(strftime); ## the defs chomp($CURRENT_DIR = `pwd`); chomp($BIN_PATH = `dirname $0`); chomp($OS = `uname -o`); chomp($CORES = `ls -d /sys/devices/system/cpu/cpu[[:digit:]]* | wc -w`); require "$BIN_PATH/ccd_defs.pl"; $BIN_PATH = $BIN_PATH."/bin"; my %objectStats = { count => 0, good => 0, bad => 0, minWidth => 0, minHeight => 0, maxWidth => 0, maxHeight => 0 }; my %jobOptions = { resizeTo => 0, srcDir => $CURRENT_DIR }; my %args = {}; $jobOptions{srcDir} = "$CURRENT_DIR"; sub run { system($_[0]); if($? != 0){ die "\n\nquitting cause: \n\t$_[0]\nreturned with code ".$?."\n"; } } sub now { (@date) = localtime; $date[5] += 1900; $date[4]++; print sprintf("%0.2d-%0.2d-%0.4d %0.2d:%0.2d:%0.2d",$date[3],$date[4]++, $date[5], $date[2],$date[1],$date[0]);; } sub parseArgs { ## defaults $args{"--resize-to"} = "1200"; $args{"--start-with"} = "resize"; $args{"--end-with"} = "pmvs"; $args{"--cmvs-maxImages"} = 100; $args{"--pmvs-level"} = 1; $args{"--pmvs-csize"} = 2; $args{"--pmvs-threshold"} = 0.7; $args{"--pmvs-wsize"} = 7; $args{"--pmvs-minImageNum"} = 3; for($i = 0; $i <= $#ARGV; $i++) { if($ARGV[$i] =~ /^--[^a-z\-]*/){ $args{"$ARGV[$i]"} = true; if(!($ARGV[$i+1] =~ /^--[^a-z\-]*/)) { if($ARGV[$i] eq "--resize-to"){ if($ARGV[$i+1] eq "orig" || $ARGV[$i+1] =~ /^[0-9]*$/){ $args{$ARGV[$i]} = $ARGV[$i+1]; } else { die "\n invalid parameter for \"".$ARGV[$i]."\": ".$ARGV[$i+1]; } } if($ARGV[$i] eq "--start-with"){ if($ARGV[$i+1] eq "resize" || $ARGV[$i+1] eq "getKeypoints" || $ARGV[$i+1] eq "match" || $ARGV[$i+1] eq "bundler" || $ARGV[$i+1] eq "cmvs" || $ARGV[$i+1] eq "pmvs"){ $args{$ARGV[$i]} = $ARGV[$i+1]; } else { die "\n invalid parameter for \"".$ARGV[$i]."\": ".$ARGV[$i+1]."\n\t valid values are \"resize\", \"getKeypoints\", \"match\", \"bundler\", \"cmvs\", \"pmvs\""; } } if($ARGV[$i] eq "--end-with"){ if($ARGV[$i+1] eq "resize" || $ARGV[$i+1] eq "getKeypoints" || $ARGV[$i+1] eq "match" || $ARGV[$i+1] eq "bundler" || $ARGV[$i+1] eq "cmvs" || $ARGV[$i+1] eq "pmvs"){ $args{$ARGV[$i]} = $ARGV[$i+1]; } else { die "\n invalid parameter for \"".$ARGV[$i]."\": ".$ARGV[$i+1]."\n\t valid values are \"resize\", \"getKeypoints\", \"match\", \"bundler\", \"cmvs\", \"pmvs\""; } } if($ARGV[$i] eq "--run-only"){ if($ARGV[$i+1] eq "resize" || $ARGV[$i+1] eq "getKeypoints" || $ARGV[$i+1] eq "match" || $ARGV[$i+1] eq "bundler" || $ARGV[$i+1] eq "cmvs" || $ARGV[$i+1] eq "pmvs"){ $args{"--start-with"} = $ARGV[$i+1]; $args{"--end-with"} = $ARGV[$i+1]; } else { die "\n invalid parameter for \"".$ARGV[$i]."\": ".$ARGV[$i+1]."\n\t valid values are \"resize\", \"getKeypoints\", \"match\", \"bundler\", \"cmvs\", \"pmvs\""; } } if($ARGV[$i] eq "--cmvs-maxImages"){ if($ARGV[$i+1] =~ /^[0-9]*$/){ $args{$ARGV[$i]} = $ARGV[$i+1]; } else { die "\n invalid parameter for \"".$ARGV[$i]."\": ".$ARGV[$i+1]; } } if($ARGV[$i] eq "--pmvs-level"){ if($ARGV[$i+1] =~ /^[0-9]*$/){ $args{$ARGV[$i]} = $ARGV[$i+1]; } else { die "\n invalid parameter for \"".$ARGV[$i]."\": ".$ARGV[$i+1]; } } if($ARGV[$i] eq "--pmvs-csize"){ if($ARGV[$i+1] =~ /^[0-9]*$/){ $args{$ARGV[$i]} = $ARGV[$i+1]; } else { die "\n invalid parameter for \"".$ARGV[$i]."\": ".$ARGV[$i+1]; } } if($ARGV[$i] eq "--pmvs-threshold"){ if($ARGV[$i+1] =~ /^-?[0-9]*\.?[0-9]*$/){ $args{$ARGV[$i]} = $ARGV[$i+1]; } else { die "\n invalid parameter for \"".$ARGV[$i]."\": ".$ARGV[$i+1]; } } if($ARGV[$i] eq "--pmvs-wsize"){ if($ARGV[$i+1] =~ /^[0-9]*$/){ $args{$ARGV[$i]} = $ARGV[$i+1]; } else { die "\n invalid parameter for \"".$ARGV[$i]."\": ".$ARGV[$i+1]; } } if($ARGV[$i] eq "--pmvs-minImageNum"){ if($ARGV[$i+1] =~ /^[0-9]*$/){ $args{$ARGV[$i]} = $ARGV[$i+1]; } else { die "\n invalid parameter for \"".$ARGV[$i]."\": ".$ARGV[$i+1]; } } if($ARGV[$i] eq "--force-focal"){ if($ARGV[$i+1] =~ /^[0-9]*\.?[0-9]*$/){ $args{$ARGV[$i]} = $ARGV[$i+1]; } else { die "\n invalid parameter for \"".$ARGV[$i]."\": ".$ARGV[$i+1]; } } if($ARGV[$i] eq "--force-ccd"){ if($ARGV[$i+1] =~ /^[0-9]*\.?[0-9]*$/){ $args{$ARGV[$i]} = $ARGV[$i+1]; } else { die "\n invalid parameter for \"".$ARGV[$i]."\": ".$ARGV[$i+1]; } } } } } if($args{"--help"}){ print "\nusgae: run.pl [options]"; print "\nit should be run from the folder contining the images to which should reconstructed"; print "\n"; print "\noptions:"; print "\n --help: "; print "\n prints this screen"; print "\n"; print "\n --resize-to: "; print "\n default: 1200"; print "\n will resize the images so that the maximum width/height of the images are smaller or equal to the specified number"; print "\n if \"--resize-to orig\" is used it will use the images without resizing"; print "\n"; print "\n --start-with: <\"resize\"|\"getKeypoints\"|\"match\"|\"bundler\"|\"cmvs\"|\"pmvs\">"; print "\n default: resize"; print "\n will start the sript at the specified step"; print "\n"; print "\n --end-with: <\"resize\"|\"getKeypoints\"|\"match\"|\"bundler\"|\"cmvs\"|\"pmvs\">"; print "\n default: pmvs"; print "\n will stop the sript after the specified step"; print "\n"; print "\n --run-only: <\"resize\"|\"getKeypoints\"|\"match\"|\"bundler\"|\"cmvs\"|\"pmvs\">"; print "\n will only execute the specified step"; print "\n equal to --start-with --end-with "; print "\n"; print "\n --force-focal: "; print "\n override the focal length information for the images"; print "\n"; print "\n --force-ccd: "; print "\n override the ccd width information for the images"; print "\n"; print "\n --cmvs-maxImages: "; print "\n default: 100"; print "\n the maximum number of images per cluster"; print "\n"; print "\n --pmvs-level: "; print "\n default: 1"; print "\n --pmvs-csize: "; print "\n default: 2"; print "\n --pmvs-threshold: "; print "\n default: 0.7"; print "\n --pmvs-wsize: "; print "\n default: 7"; print "\n--pmvs-minImageNum: "; print "\n default: 3"; print "\n see http://grail.cs.washington.edu/software/pmvs/documentation.html for an explanation of these parameters"; print "\n"; exit; } print "\n - configuration:"; foreach $args_key (sort keys %args) { if($args{$args_key} ne ""){ print "\n $args_key: $args{$args_key}"; } } print "\n"; print "\n"; } sub prepareObjects { ## get the source list @source_files = `ls -1 | egrep "\.[jJ]{1}[pP]{1}[eE]{0,1}[gG]{1}"`; print "\n - source files - "; now(); print "\n"; foreach $file (@source_files) { chomp($file); chomp($file_make = `jhead $file | grep "Camera make"`); chomp($file_model = `jhead $file | grep "Camera model"`); chomp($file_focal = `jhead $file | grep "Focal length"`); chomp($file_ccd = `jhead $file | grep "CCD width"`); chomp($file_resolution = `jhead $file | grep "Resolution"`); my %fileObject = {}; chomp(($fileObject{src}) = $file); chomp(($fileObject{base}) = $file); $fileObject{base} =~ s/\.[^\.]*$//; chomp(($fileObject{make}) = $file_make =~ /: ([^\n\r]*)/); chomp(($fileObject{model}) = $file_model =~ /: ([^\n\r]*)/); $fileObject{id} = $fileObject{make}." ".$fileObject{model}; ($fileObject{width}, $fileObject{height}) = $file_resolution =~ /: ([0-9]*) x ([0-9]*)/; if(!$args{"--force-focal"}){ ($fileObject{focal}) = $file_focal =~ /:[\ ]*([0-9\.]*)mm/; } else { $fileObject{focal} = $args{"--force-focal"}; } if(!$args{"--force-ccd"}){ ($fileObject{ccd}) = $file_ccd =~ /:[\ ]*([0-9\.]*)mm/; if(!$fileObject{ccd}){; $fileObject{ccd} = $ccdWidths{$fileObject{id}}; } } else { $fileObject{ccd} = $args{"--force-ccd"}; } if($fileObject{ccd} && $fileObject{focal} && $fileObject{width} && $fileObject{height}){ if($fileObject{width} > $fileObject{height}){ $fileObject{focalpx} = $fileObject{width} * ($fileObject{focal} / $fileObject{ccd}); } else { $fileObject{focalpx} = $fileObject{height} * ($fileObject{focal} / $fileObject{ccd}); } $fileObject{isOk} = true; $objectStats{good}++; print "\n using $fileObject{src} dimensions: $fileObject{width}x$fileObject{height} / focal: $fileObject{focal}mm / ccd: $fileObject{ccd}mm"; } else { $fileObject{isOk} = false; $objectStats{bad}++; print "\n no CCD width or focal length found for $fileObject{src}"; } $objectStats{count}++; if($objectStats{minWidth} == 0) { $objectStats{minWidth} = $fileObject{width}; } if($objectStats{minHeight} == 0) { $objectStats{minHeight} = $fileObject{height}; } $objectStats{minWidth} = $objectStats{minWidth} < $fileObject{width} ? $objectStats{minWidth} : $fileObject{width}; $objectStats{minHeight} = $objectStats{minHeight} < $fileObject{height} ? $objectStats{minHeight} : $fileObject{height}; $objectStats{maxWidth} = $objectStats{maxWidth} > $fileObject{width} ? $objectStats{maxWidth} : $fileObject{width}; $objectStats{maxHeight} = $objectStats{maxHeight} > $fileObject{height} ? $objectStats{maxHeight} : $fileObject{height}; push(@objects, \%fileObject); } if(!$objectStats{good}){ print "\n\n found no usable images - quitting\n"; die; } else { print "\n\n found $objectStats{good} usable images"; } print "\n"; $jobOptions{resizeTo} = $args{"--resize-to"}; print "\n using max image size of $jobOptions{resizeTo} x $jobOptions{resizeTo}"; $jobOptions{jobDir} = "$jobOptions{srcDir}/reconstruction-with-image-size-$jobOptions{resizeTo}"; $jobOptions{step_1_convert} = "$jobOptions{jobDir}/_convert.templist.txt"; $jobOptions{step_1_vlsift} = "$jobOptions{jobDir}/_vlsift.templist.txt"; $jobOptions{step_1_gzip} = "$jobOptions{jobDir}/_gzip.templist.txt"; $jobOptions{step_2_filelist} = "$jobOptions{jobDir}/_filelist.templist.txt"; $jobOptions{step_2_matches} = "$jobOptions{jobDir}/matches.init.txt"; $jobOptions{step_3_filelist} = "$jobOptions{jobDir}/list.txt"; $jobOptions{step_3_bundlerOptions} = "$jobOptions{jobDir}/options.txt"; mkdir($jobOptions{jobDir}); foreach $fileObject (@objects) { if($fileObject->{isOk}){ $fileObject->{step_0_resizedImage} = "$jobOptions{jobDir}/$fileObject->{base}.jpg"; $fileObject->{step_1_pgmFile} = "$jobOptions{jobDir}/$fileObject->{base}.pgm"; $fileObject->{step_1_keyFile} = "$jobOptions{jobDir}/$fileObject->{base}.key"; $fileObject->{step_1_gzFile} = "$jobOptions{jobDir}/$fileObject->{base}.key.gz"; } } # exit } sub resize { print "\n"; print "\n - preparing images - "; now(); print "\n"; print "\n"; chdir($jobOptions{jobDir}); foreach $fileObject (@objects) { if($fileObject->{isOk}){ if($jobOptions{resizeTo} != "orig" && (($fileObject->{width} > $jobOptions{resizeTo}) || ($fileObject->{height} > $jobOptions{resizeTo}))){ print "\n resising $fileObject->{src} \tto $fileObject->{step_0_resizedImage}"; run("convert -resize $jobOptions{resizeTo}x$jobOptions{resizeTo} -quality 100 \"$jobOptions{srcDir}/$fileObject->{src}\" \"$fileObject->{step_0_resizedImage}\""); } else { print "\n copying $fileObject->{src} \tto $fileObject->{step_0_resizedImage}"; copy("$CURRENT_DIR/$fileObject->{src}", "$fileObject->{step_0_resizedImage}"); } chomp($file_resolution = `jhead $fileObject->{step_0_resizedImage} | grep "Resolution"`); ($fileObject->{width}, $fileObject->{height}) = $file_resolution =~ /: ([0-9]*) x ([0-9]*)/; print "\t ($fileObject->{width} x $fileObject->{height})"; } } if($args{"--end-with"} ne "resize"){ getKeypoints(); } } sub getKeypoints { print "\n"; print "\n - finding keypoints - "; now(); print "\n"; print "\n\n"; chdir($jobOptions{jobDir}); $vlsiftJobs = ""; foreach $fileObject (@objects) { if($fileObject->{isOk}){ $vlsiftJobs .= "convert -format pgm \"$fileObject->{step_0_resizedImage}\" \"$fileObject->{step_1_pgmFile}\""; $vlsiftJobs .= " && $BIN_PATH/vlsift \"$fileObject->{step_1_pgmFile}\" -o \"$fileObject->{step_1_keyFile}.sift\" > /dev/null && perl $BIN_PATH/../convert_vlsift_to_lowesift.pl \"$fileObject->{base}\""; $vlsiftJobs .= " && gzip -f \"$fileObject->{step_1_keyFile}\""; $vlsiftJobs .= " && rm -f \"$fileObject->{step_1_pgmFile}\""; $vlsiftJobs .= " && rm -f \"$fileObject->{step_1_keyFile}.sift\"\n"; } } system("echo \"$vlsiftJobs\" > $jobOptions{step_1_vlsift}"); run("\"$BIN_PATH/parallel\" --halt-on-error 1 -j+0 < \"$jobOptions{step_1_vlsift}\""); if($args{"--end-with"} ne "getKeypoints"){ match(); } } sub match { print "\n"; print "\n - matching keypoints - "; now(); print "\n"; print "\n"; chdir($jobOptions{jobDir}); $filesList = ""; foreach $fileObject (@objects) { if($fileObject->{isOk}){ if($fileObject->{isOk}){ $filesList .= "\"$fileObject->{step_1_keyFile}\"\n"; } } } system("echo \"$filesList\" > $jobOptions{step_2_filelist} "); run("\"$BIN_PATH/KeyMatchFull\" \"$jobOptions{step_2_filelist}\" \"$jobOptions{step_2_matches}\" "); if($args{"--end-with"} ne "match"){ bundler(); } } sub bundler { print "\n"; print "\n - running bundler - "; now(); print "\n"; print "\n"; chdir($jobOptions{jobDir}); mkdir($jobOptions{jobDir}."/bundle"); mkdir($jobOptions{jobDir}."/pmvs"); mkdir($jobOptions{jobDir}."/pmvs/txt"); mkdir($jobOptions{jobDir}."/pmvs/visualize"); mkdir($jobOptions{jobDir}."/pmvs/models"); $filesList = ""; foreach $fileObject (@objects) { if($fileObject->{isOk}){ if($fileObject->{isOk}){ $filesList .= sprintf("\./%s.jpg 0 %0.5f\n", $fileObject->{base}, $fileObject->{focalpx}); } } } chomp($filesList); $bundlerOptions = "--match_table matches.init.txt\n"; $bundlerOptions .= "--output bundle.out\n"; $bundlerOptions .= "--output_all bundle_\n"; $bundlerOptions .= "--output_dir bundle\n"; $bundlerOptions .= "--variable_focal_length\n"; $bundlerOptions .= "--use_focal_estimate\n"; $bundlerOptions .= "--constrain_focal\n"; $bundlerOptions .= "--constrain_focal_weight 0.0001\n"; $bundlerOptions .= "--estimate_distortion\n"; $bundlerOptions .= "--run_bundle"; system("echo \"$bundlerOptions\" > \"$jobOptions{step_3_bundlerOptions}\""); system("echo \"$filesList\" > \"$jobOptions{step_3_filelist}\""); run("\"$BIN_PATH/bundler\" \"$jobOptions{step_3_filelist}\" --options_file \"$jobOptions{step_3_bundlerOptions}\" > bundle/out"); run("\"$BIN_PATH/Bundle2PMVS\" \"$jobOptions{step_3_filelist}\" bundle/bundle.out"); run("\"$BIN_PATH/RadialUndistort\" \"$jobOptions{step_3_filelist}\" bundle/bundle.out pmvs"); $i = 0; foreach $fileObject (@objects) { if($fileObject->{isOk}){ if($fileObject->{isOk}){ if (-e "pmvs/$fileObject->{base}.rd.jpg"){ $nr = sprintf("%08d", $i++); system("mv pmvs/$fileObject->{base}.rd.jpg pmvs/visualize/$nr.jpg"); system("mv pmvs/$nr.txt pmvs/txt/$nr.txt"); } } } } system("\"$BIN_PATH/Bundle2Vis\" pmvs/bundle.rd.out pmvs/vis.dat"); if($args{"--end-with"} ne "bundler"){ cmvs(); } } sub cmvs { print "\n"; print "\n - running cmvs - "; now(); print "\n"; print "\n"; chdir($jobOptions{jobDir}); run("\"$BIN_PATH/cmvs\" pmvs/ $args{'--cmvs-maxImages'} $CORES"); run("\"$BIN_PATH/genOption\" pmvs/ $args{'--pmvs-level'} $args{'--pmvs-csize'} $args{'--pmvs-threshold'} $args{'--pmvs-wsize'} $args{'--pmvs-minImageNum'} $CORES"); if($args{"--end-with"} ne "cmvs"){ pmvs(); } } sub pmvs { print "\n"; print "\n - running pmvs - "; print "\n"; chdir($jobOptions{jobDir}); run("\"$BIN_PATH/pmvs2\" pmvs/ option-0000"); system("cp -Rf \"$jobOptions{jobDir}/pmvs/models\" \"$jobOptions{jobDir}-results\""); } parseArgs(); prepareObjects(); chdir($jobOptions{jobDir}); switch ($args{"--start-with"}) { case "resize" { resize(); } case "getKeypoints" { getKeypoints(); } case "match" { match(); } case "bundler" { bundler(); } case "cmvs" { cmvs(); } case "pmvs" { pmvs(); } } print "\n"; print "\n - done - "; now(); print "\n"; print "\n";