sba, a C/C++ package for generic sparse bundle adjustment is almost invariably used as the last step

源代码在线查看: reprerr.pl

软件大小: 385 K
上传用户: nanbeilisa
关键词: adjustment invariably package generic
下载地址: 免注册下载 普通下载 VIP

相关代码

				#!/usr/bin/perl								#################################################################################				## 				##  Perl script for computing the reprojection error corresponding to a				##  given reconstruction. Currently, projective and quaternion-based euclidean				##  reconstructions are supported. More reconstruction types can be added by				##  supplying appropriate camera matrix generation routines (i.e. CamMat_Generate)				##  Copyright (C) 2005  Manolis Lourakis (lourakis@ics.forth.gr)				##  Institute of Computer Science, Foundation for Research & Technology - Hellas				##  Heraklion, Crete, Greece.				##				##  This program is free software; you can redistribute it and/or modify				##  it under the terms of the GNU 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 General Public License for more details.				##				#################################################################################								#################################################################################				# Initializations								$usage="Usage is $0 -e|-i|-p [-s,-h]   []";				$help="-e specifies a quaternion-based Euclidean reconstruction with fixed intrinsics,\n-i a Euclidean reconstruction with varying intrinsics and -p a projective one.\n"				."-s computes the average *squared* reprojection error.";				use constant EUCBA => 0; # Euclidean BA, fixed intrinsics				use constant EUCIBA => 1; # Euclidean BA, varying intrinsics				use constant PROJBA => 2; # Projective BA				$cnp=$pnp=0;				$camsfile=$ptsfile=$calfile="";				$CamMat_Generate=\&dont_know;								#################################################################################				# Basic arguments parsing								use Getopt::Std;				getopts("eipsh", \%opt) or die "$usage\n";				die "$0 help: Compute the average reprojection error for some reconstruction.\n$usage\n$help\n" if($opt{h});								if($opt{e}+$opt{i}+$opt{p}!=1){				    die "$0: Only one of -e, -p can be specified!\n";				} elsif($opt{e}){				    $batype=EUCBA;				} elsif($opt{i}){				    $batype=EUCIBA;				} elsif($opt{p}){				    $batype=PROJBA;				}				$squared=$opt{s}? 1 : 0;								#################################################################################				# Initializations depending on reconstruction type				if($batype==EUCBA){				    $cnp=7; $pnp=3;				    die "$0: Cameras, points, or calibration file is missing!\n$usage" if(@ARGV				    die "$0: Too many arguments!\n$usage" if(@ARGV>3);				    $camsfile=$ARGV[0];				    $ptsfile=$ARGV[1];				    $calfile=$ARGV[2];				    $CamMat_Generate=\&PfromRtK;				}				elsif($batype==EUCIBA){				    $cnp=7+5; $pnp=3;				    die "$0: Cameras or points file is missing!\n$usage" if(@ARGV				    die "$0: Too many arguments!\n$usage" if(@ARGV>2);				    $camsfile=$ARGV[0];				    $ptsfile=$ARGV[1];				    $CamMat_Generate=\&PfromRtVarK;				}				elsif($batype==PROJBA){ 				    $cnp=12; $pnp=4;				    die "$0: Cameras or points file is missing!\n$usage" if(@ARGV				    die "$0: Too many arguments!\n$usage" if(@ARGV>2);				    $camsfile=$ARGV[0];				    $ptsfile=$ARGV[1];				    $CamMat_Generate=\&nop;				}				else{				    die "Unknown BA type \"$batype\" specified!\n";				}								die "$0: Do not know how to handle $pnp parameters per point!\n" if($pnp!=3 && $pnp!=4);												#################################################################################				# Main code for computing the reprojection error.								# NOTE: all 2D arrays are stored in row-major order as vectors				@camPoses=(); # array of arrays storing each camera's pose; each element is of size $cnp								@threeDpts=(); # array of arrays storing the reconstructed 3D points; each element is of size $pnp				@twoDtrajs=(); # array of hashes storing the 2D trajectory correponding to reconstructed 3D points.				               # The hash key is the frame number				@trajsFrames=(); # array of arrays storing the frame numbers corresponding to each trajectory.				                 # The first number is the total number of frames, then follow the individual frame				                 # numbers: [nframes, fr_i, fr_j, ..., fr_k]				@camCal=();    # 3x3 array for storing the camera intrinsic calibration												# read calibration file, if there is one				  if(length($calfile)>0){				    if(not open(CAL, $calfile)){					    print STDERR "cannot open file $calfile: $!\n";					    exit(1);				    }				    for($i=0; $i				      $line=;				      if($line=~/\r\n$/){ # CR+LF				        chop($line); chop($line);				      }				      else{				        chomp($line);				      }								      next if($line=~/^#.+/); # skip comments								      @columns=split(" ", $line);				      die "line \"$line\" in $calfile does not contain exactly 3 numbers [$#columns+1]!\n" if($#columns+1!=3);				      $camCal[$i*3]=$columns[0]; $camCal[$i*3+1]=$columns[1]; $camCal[$i*3+2]=$columns[2];				      $i++;				    }				    close(CAL);				  }								# read cameras file				  if(not open(CAMS, $camsfile)){					  print STDERR "cannot open file $camsfile: $!\n";					  exit(1);				  }				  $ncams=0;				  while($line=){				    if($line=~/\r\n$/){ # CR+LF				      chop($line); chop($line);				    }				    else{				      chomp($line);				    }								    next if($line=~/^#.+/); # skip comments								    @columns=split(" ", $line);				    #next if($#columns==-1); # skip empty lines								    die "line \"$line\" in $camsfile does not contain exactly $cnp numbers [$#columns+1]!\n" if($cnp!=$#columns+1);				    @pose=();				    for($i=0; $i				      $pose[$i]=$columns[$i];				    }				    $camPoses[$ncams]=$CamMat_Generate->($ncams, [@pose], [@camCal]);				    $ncams++;				  }				  close(CAMS);								  printf "Read %d cameras\n", scalar(@camPoses);								# read points file				  if(not open(PTS, $ptsfile)){					  print STDERR "cannot open file $ptsfile: $!\n";					  exit(1);				  }								  $npts=0;				  $trajno=0;				  while($line=){					  $npts++;				    if($line=~/\r\n$/){ # CR+LF				      chop($line); chop($line);				    }				    else{				      chomp($line);				    }								    next if($line=~/^#.+/); # skip comments				    @columns=split(" ", $line);								    die "line \"$line\" in $ptsfile contains less than $pnp numbers [$#columns+1]!\n" if($pnp>$#columns+1);				    @recpt=();				    for($i=0; $i				      $recpt[$i]=$columns[$i];				    }								    $nframes=$columns[$pnp];				    $i=$pnp+1+$nframes*3; # 3 numbers per image projection: (i.e. imgid, x, y)				    if($i!=$#columns+1){				      die "line \"$line\" in $ptsfile does not contain exactly the $i numbers required for a 3D point with $nframes 2D projections [$#columns+1]!\n";				    }								    %traj=();				    @theframes=($nframes);				    for($i=0, $j=$pnp+1; $i				      $traj{$columns[$j]}=[$columns[$j+1], $columns[$j+2]];				      push @theframes, $columns[$j];								#     printf "%d: %d %.6g %.6g\n", $j, $columns[$j], $columns[$j+1], $columns[$j+2];				    }				    $threeDpts[$trajno]=[@recpt];				    $twoDtrajs[$trajno]={%traj};				    $trajsFrames[$trajno++]=[@theframes];				  }				  close(PTS);								  printf "Read %d 3D points \& trajectories\n", scalar(@threeDpts);								# Data file has now been read. Following fragment shows how it can be printed				if(0){				  for($i=0; $i				    for($j=0; $j				      printf "%.6g ", $threeDpts[$i][$j];				    }								    printf "%d ", $trajsFrames[$i][0];				    for($j=0; $j				      $fr=$trajsFrames[$i][$j+1];				      if(defined($twoDtrajs[$i]{$fr})){				        printf "%d %.6g %.6g ", $fr, $twoDtrajs[$i]{$fr}[0], $twoDtrajs[$i]{$fr}[1];				      }				    }				    print "\n";				  }				}								# compute reprojection error				  unless ($batype==EUCBA || $batype==EUCIBA || $batype==PROJBA){				    die "current implementation of reprError() cannot handle supplied reconstruction data!\n";				  }								  $toterr=0.0;				  $totprojs=0.0;				  @error=();				  for($fr=0; $fr				    $error[$fr]=0.0;				    for($i=$j=0; $i				      if(defined($twoDtrajs[$i]{$fr})){				        $theerr=&reprError($twoDtrajs[$i]{$fr}, @camPoses[$fr], @threeDpts[$i], $pnp);				        $theerr=sqrt($theerr) if(!$squared);				        $error[$fr]+=$theerr;				#        printf "@@@ point %d, camera %d: %g\n", $i, $fr, $theerr;				        $j++;				      }				    }				    printf "Mean error for camera %d [%d projections] is %g\n", $fr, $j, $error[$fr]/$j;				    $toterr+=$error[$fr];				    $totprojs+=$j;				  }				  printf "\nMean error for the whole sequence [%d projections]  is %g\n", $totprojs, $toterr/$totprojs;																#################################################################################				# Misc routines								# compute the SQUARED reprojection error |x-xx|^2  with xx=P*X				sub reprError{								  my ($x, $P, $X, $pnp)=@_;								  # error checking				  unless (@_==4 && ref($x) eq 'ARRAY' && ref($P) eq 'ARRAY' && ref($X) eq 'ARRAY'){				    die "usage: reprError ARRAYREF1 ARRAYREF2 ARRAYREF3 pnp";				  }								  my @xx=();				  my $k;								  # compute the projection in xx				  for($k=0; $k				    $xx[$k]=$P->[$k*4]*$X->[0] + $P->[$k*4+1]*$X->[1] + $P->[$k*4+2]*$X->[2] + $P->[$k*4+3]*(($pnp==4)? $X->[3] : 1.0);				  }				  $xx[0]/=$xx[2];				  $xx[1]/=$xx[2];								# printf "[%g %g -- %g %g] ", $x->[0], $x->[1], $xx[0], $xx[1];								  return ($x->[0]-$xx[0])*($x->[0]-$xx[0]) + ($x->[1]-$xx[1])*($x->[1]-$xx[1]);				}								#################################################################################				# Camera matrix generation routines								sub dont_know {				  my ($camid, $camparms)=@_;								  die "Don't know how to generate a projection matrix for camera $camid from the supplied camera parameters!\n";				  return $camparms;				}								# Return as is				sub nop {				  my ($camid, $camparms)=@_;								  return $camparms;				}								# Compute P as K[R|t]. R is specified by the first 4 elements of $camparms, while t corresponds to the last 3 ones				sub PfromRtK {				  my ($camid, $camparms, $calparams)=@_;								  my $x, $y, $z, $w, $xx, $xy, $xz, $xw, $yy, $yz, $yw, $zz, $zw, $ww, $i, $j, $k;				  my @R=(), @P=(); # 3x3 & 3x4 resp.								# compute the rotation matrix for q=(x, y, z, w);				# see also http://www.gamedev.net/reference/articles/article1095.asp (but note that q=(w, x, y, z) there!)								  $x=$camparms->[0]; $y=$camparms->[1];				  $z=$camparms->[2]; $w=$camparms->[3];				  $xx=$x*$x; $xy=$x*$y; $xz=$x*$z; $xw=$x*$w;				  $yy=$y*$y; $yz=$y*$z; $yw=$y*$w;				  $zz=$z*$z; $zw=$z*$w; $ww=$w*$w;				  $R[0]=$xx+$yy - ($zz+$ww); $R[1]=2.0*($yz-$xw);       $R[2]=2.0*($yw+$xz);				  $R[3]=2.0*($yz+$xw);       $R[4]=$xx+$zz - ($yy+$ww); $R[5]=2.0*($zw-$xy);				  $R[6]=2.0*($yw-$xz);       $R[7]=2.0*($zw+$xy);       $R[8]=$xx+$ww - ($yy+$zz);								#print "@R\n\n";				# compute the matrix-matrix & matrix-vector products				  for($i=0; $i				    for($j=0; $j				      for($k=0, $sum=0.0; $k				        $sum+=$calparams->[$i*3+$k]*$R[$k*3+$j];				      }				      $P[$i*4+$j]=$sum;				    }				    for($j=0, $sum=0.0; $j				      $sum+=$calparams->[$i*3+$j]*$camparms->[4+$j];				    }				    $P[$i*4+3]=$sum;				  }								  return [@P];				}								# Compute P as K[R|t]. K is specified by the first 5 elements of $camparms, while R and t correspond to the next 4 & 3 elements, respectively				sub PfromRtVarK {				  my ($camid, $camparms)=@_;				  my @K=(), @poseparams=(), $size, $i;								  # setup the intrinsics matrix from the 5 first elements				  $K[0]=$camparms->[0]; $K[1]=$camparms->[4];                $K[2]=$camparms->[1];				  $K[3]=0.0;            $K[4]=$camparms->[3]*$camparms->[0]; $K[5]=$camparms->[2];				  $K[6]=0.0;            $K[7]=0.0;                           $K[8]=1.0;								  $size=scalar(@$camparms);				  for($i=5; $i				    $poseparams[$i-5]=$camparms->[$i];				  }								  &PfromRtK($camid, [@poseparams], [@K]);				}							

相关资源