#!/usr/bin/perl
use strict;
use warnings;
use Panotools::Script;
use Math::Trig;
use Image::Size;
use File::Spec;
die "Usage: $0 project.paf" unless (defined $ARGV[0] and -e $ARGV[0]);
my $path_paf = File::Spec->rel2abs ($ARGV[0]);
open (PAF, '<'. $path_paf);
my $paf = {};
for my $line (<PAF>)
{
if ($line =~ /^(.+)=(.+)$/)
{
my ($key, $value) = ($1, $2);
$key =~ s/\\ / /g;
$paf->{$key} = $value;
}
}
my ($v, $d, $f) = File::Spec->splitpath ($path_paf);
my $path_equirect = File::Spec->catpath ($v, $d, $paf->{'Panorama Image'});
my ($px_width_equirect, $px_height_equirect) = imgsize ($path_equirect);
die unless ($px_width_equirect * $px_height_equirect > 0);
my $deg_hfov_equirect = $paf->{'Image Maximum Pan'} - $paf->{'Image Minimum Pan'};
$deg_hfov_equirect = 360 if $deg_hfov_equirect < 1;
my $px_radius_equirect = ($deg_hfov_equirect / 360) * $px_width_equirect / (2 * atan2(0,-1));
my $rad_vfov = $paf->{'Initial FOV'} * atan2(0,-1) / 180;
my $px_height = int (tan ($rad_vfov/2) * $px_radius_equirect * 2);
my $px_width = int ($px_height * 4/3);
my $focal_length = $px_height / (2*tan($rad_vfov/2));
my $rad_hfov = 2 * atan( $px_width / (2.0 * $focal_length));
# create a .pto project to extract the rectilinear view stored in the .paf file
my $pto_extract = new Panotools::Script;
$pto_extract->Panorama->Set (w => $px_width, h => $px_height,
n => 'TIFF',
v => ($rad_hfov * 180 / atan2(0,-1)),
f => 0);
my $equirect = new Panotools::Script::Line::Image;
$equirect->Set (w => $px_width_equirect, h => $px_height_equirect, f => 4,
v => $deg_hfov_equirect, r => 0, p => 0, y => 0,
n => '"'. $path_equirect .'"');
push @{$pto_extract->Image}, $equirect;
$pto_extract->Transform (0, 0, 0 - $paf->{'Initial Pan'});
$pto_extract->Transform (0, $paf->{'Initial Tilt'}, 0);
my $path_temp_pto = $path_paf .'.'. $$ .'.temp.pto';
$pto_extract->Write ($path_temp_pto);
# render the rectilinear view, delete the .pto project
system ('nona', '-o', $path_paf .'.extract', $path_temp_pto);
unlink $path_temp_pto;
# create a .pto that reprojects the extracted rectilinear back into the original image
my $pto_insert = new Panotools::Script;
$pto_insert->Panorama->Set (w => $px_width_equirect, h => $px_height_equirect,
v => $deg_hfov_equirect, n => 'TIFF');
my $rectilinear = new Panotools::Script::Line::Image;
$rectilinear->Set (w => $px_width, h => $px_height,
f => 0, v => ($rad_hfov * 180 / atan2(0,-1)),
n => '"'. $path_paf .'.extract.tif"');
push @{$pto_insert->Image}, $rectilinear;
$pto_insert->Transform (0, 0 - $paf->{'Initial Tilt'}, 0);
$pto_insert->Transform (0, 0, $paf->{'Initial Pan'});
$pto_insert->Write ($path_paf .'.extract.pto');
__END__
=head1 NAME
pafextract - render panoglview .paf projects
=head1 SYNOPSIS
panoglview equirectangular.tif
pafextract project.paf
gimp project.paf.extract.tif
nona -o overlay project.paf.extract.pto
composite overlay.tif equirectangular.tif merged.tif
=head1 DESCRIPTION
B<pafextract> takes a panoglview .paf file and renders the saved view as a
suitably sized .tif file. This is useful for simply extracting a 'normal' view
from an equirectangular panorama.
A hugin .pto project is also created, containing all the information necessary
to reproject the extracted .tif image back into the same equirectangular space
as the original. This is useful for merging edits back into the original with
a tool such as ImageMagick or the Gimp.
=head1 LICENSE
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.
=head1 SEE ALSO
L<http://hugin.sourceforge.net/>
=head1 AUTHOR
Bruno Postle - September 2008.
=cut