PapySpheric: a Python program to build templates for panospheres  

Everything you need to motorize your head
no avatar
GURL
Member
 
Posts: 2946
Joined: Tue Dec 06, 2005 1:57 pm
Location: Grenoble

PapySpheric: a Python program to build templates for panospheres

by GURL » Mon Jan 11, 2010 8:04 pm

Code: Select all
# Version 0.0.1 - mercredi 13 janvier 2010
##########----------##########----------##########----------##########----------
# my camera: 23 x 15.5 mm
# Olypus: 13 x 17.3 mm
# Nikon APS-C: 23.6 x 15.8 mm
# Pentax K20D 23.4 x 15.6 mm

#####################  THE  9  PARAMETERS  YOU  MUST  SET  ARE  THERE
                    #  ##################################################
f= 18               # mm, for example 50 mm
Vside= 23.4         # mm, for example 36 mm  \  portrait / landscape 
Hside= 15.6         # mm, for example 24 mm  /  orientation found there
phiMin= -90         # degrees, from -90 (nadir) toward 90
phiMax= 90          # degrees, up to 90 (zenith) toward -90
Hoverlap= 0.2       # horizontal overlap, coef from 0 to 0.5 (0% to 50 %)
Voverlap= 0.2       # vertical overlap, coef from 0 up to more than 0.5
                    #
panoheadPhiMin= -90 # degrees, from -90 (nadir)  \ avoids the camera or lens
panoheadPhiMax= 90  # degrees, up to 90 (zenith) / hitting the pano head !
                    #
#####################

from math import *

assert f > 1 and f < 1001, "f: improper focal length"
assert Vside > 1 and Vside < 100, "Vside: improper size"
assert Hside > 1 and Hside < 100, "Vside: improper size"
assert phiMin >= -90 and phiMin < 85, "phiMin not between -90 and +85"
assert phiMax <= 90 and phiMax > -85, "phiMax not between -85 and +90"
assert phiMin != phiMax, "phiMin, phiMax: min and max are equal"
assert phiMin < phiMax, "phiMin, phiMax: min and max are inverted"
assert Hoverlap >= 0, "Hoverlap: minimum possible value is 0"
assert Hoverlap < 0.96, "Hoverlap: maximum possible value is 0.95"
assert Voverlap >= 0, "Voverlap: minimum value is 0"
assert Voverlap < 0.96, "Voverlap: maximum value is 0.95"
assert panoheadPhiMin >= -90, "panoheadPhiMin: extreme value is -90"
assert panoheadPhiMax <= 90, "panoheadPhiMax: maximum value is 90"
assert panoheadPhiMin < panoheadPhiMax, "panoheadPhiMin, panoheadPhiMax:" \
       + "Pano-head extreme top & bottom positions are stupid!"
   
trueVside=  Vside
trueHside=  Hside
trueVfov=   degrees(2 * atan (trueVside / 2 / f))
trueHfov=   degrees(2 * atan (trueHside / 2 / f))

if phiMax - trueVfov / 2 > panoheadPhiMax :
    print("\nCAUTION! ...panorama phiMax incompatible",
          "with pano-head phiMax has been reduced!\n")
    phiMax= panoheadPhiMax - trueVfov / 2

if phiMin + trueVfov / 2 < panoheadPhiMin :
    phiMin= panoheadPhiMin + trueVfov / 2
    print("\nCAUTION! ...panorama phiMin incompatible",
          "with pano-head phiMin has been adjusted!\n")

truePhiMin= phiMin                             
truePhiMax= phiMax                             
                                               
##########----------##########----------##########----------##########----------

print("Camera:")
print("    Sensor size         ", repr(trueHside)[0:4] + " x " + repr(trueVside),"mm")
print("    Focal length        ", repr(f)[0:5], "mm")
print("    Lens vertical FOV   ", round(degrees(2 * atan (trueVside / 2 / f))), "deg")
print("    Lens horizontal FOV ", round(degrees(2 * atan (trueHside / 2 / f))), "deg")

print("\nPanorama:")
print("    Top at              ", repr(phiMax)[0:5], "deg")
print("    Bottom at           ", repr(phiMin)[0:5], "deg")
print("    vertical FOV        ", repr(phiMax - phiMin)[0:5], "deg")
print("    Vertical overlap    ", repr(int(100 * Voverlap))+" %")
print("    Horizontal overlap  ", repr(int(100 * Hoverlap))+" %")

if panoheadPhiMin != -90 or panoheadPhiMax != 90 :
    print("\nPano-head:")
    if panoheadPhiMin != -90  :
        print("    downward limit", int(panoheadPhiMin), " deg")
    if panoheadPhiMax != 90 :
        print("    upward limit", int(panoheadPhiMax), " deg")

print(" ")

##########----------##########----------##########----------##########----------

totalImgNb= int(0)

if trueVfov > trueHfov :
    optimalZenith= 90 - ((trueVfov - trueHfov) / 2)
    optimalNadir= -90 + ((trueVfov - trueHfov) / 2)
else :
    optimalZenith = 90
    optimalNadir = -90               # overlap between zenith disc and top row
                                     #########################################
if panoheadPhiMax >= optimalZenith \
    and truePhiMax > 90 - (trueHfov / 2 * (1 - max(Voverlap, Hoverlap))) :
    zenith= "yes"
    phiMax= phiMax - (min(trueHfov, trueVfov) / 2 * (1 - max(Voverlap, Hoverlap)))
    totalImgNb= totalImgNb + 1
else :
    zenith= "no"                        # no overlap with zenith hole is wanted
    phiMax= phiMax - (trueVfov * Voverlap / 2)                               
    print("# phiMax moved downward by", repr(trueVfov * Voverlap / 2)[0:5],
          "deg -----------------------> 0 % overlap with zenith hole")

if (panoheadPhiMin <= optimalNadir) \
    and abs(truePhiMin) > 90 - (trueVfov / 2 * (1 - max(Voverlap, Hoverlap))) :
    nadir=  "yes"
    phiMin= phiMin + (min(trueHfov, trueVfov) / 2 * (1 - max(Voverlap, Hoverlap)))
    totalImgNb= totalImgNb + 1
else :
    nadir= "no"                          # no overlap with nadir hole is wanted
    phiMin= phiMin + (trueVfov * Voverlap / 2)
    print("# phiMin moved upward by", repr(trueVfov * Voverlap / 2)[0:5],
          "deg -------------------------> 0 % overlap with nadir hole")
 
Vfov=   trueVfov  * (1 - Voverlap)
Hfov=   trueHfov  * (1 - Hoverlap)
Vside=  2 * f * tan(radians(Vfov / 2))
Hside=  2 * f * tan(radians(Hfov / 2))

linV=   1 - Vside / trueVside # Out of disc part of zenith and/or nadir
linH=   1 - Hside / trueHside # not taken into account tough it should be!
if int(linV) != int(linH) :
    print("# Linear vertical overlap   --> ", repr(100 * (linV))[0:5],
          "% of source pixels")
    print("# Linear horizontal overlap --> ", repr(100 * (linH))[0:5],
          "% of source pixels")
else :
    print("# Linear overlap --> ", repr(100 * (linV))[0:5],
          "% of source pixels")

anglV=  1 - Vfov / trueVfov # idem about out of disc part of zenith, nadir
anglH=  1 - Hfov / trueHfov
if int(100 * (anglV + anglH)) != int(100 * (linV + linH)) :
    if int(anglV) != int(anglH) :
        print("# Angular vertical overlap   --> ", repr(100 * anglV)[0:5], "%")
        print("# Angular horizontal overlap --> ", repr(100 * anglH)[0:5], "%")
    else :
        print("# Angular overlap --> ", repr(100 * anglV)[0:5], "%")

rowNb= (phiMax - phiMin) // Vfov
if rowNb * Vfov < phiMax - phiMin :
    rowNb= rowNb + 1
dPitch= (phiMax - phiMin) / rowNb               

sigmaPhi= rowNb * trueVfov
if nadir == "yes" :
    sigmaPhi= sigmaPhi + (trueVfov + trueHfov )/ 2 / 2 # sic!
if zenith == "yes" :
    sigmaPhi= sigmaPhi +  + (trueVfov + trueHfov )/ 2 / 2  # sic!
VangularExcess= (sigmaPhi - (truePhiMax - truePhiMin)) / sigmaPhi
   
##########----------##########----------##########----------##########----------

toPrint= "\n" + "Number of rows: " + repr(int(rowNb))
if zenith == "yes" :
    toPrint= toPrint + " + zenith"
if nadir == "yes" :
    toPrint= toPrint + " + nadir"
print (toPrint + "\n")

print("# Lens vertical angles :    ",
      repr(trueVfov * Voverlap / 2)[0:4], "+", repr(Vfov)[0:4], "+",
      repr(trueVfov * Voverlap / 2)[0:4], "=",repr(trueVfov)[0:4] + " deg")
print("# Lens horizontal angles :  ",
      repr(trueHfov * Hoverlap / 2)[0:4], "+", repr(Hfov)[0:4], "+",
      repr(trueHfov * Hoverlap / 2)[0:4], "=", repr(trueHfov)[0:4] + " deg")
if zenith == "yes" or nadir == "yes" :
    if Hfov < Vfov :
        print("# Zenith and Nadir angles:  ", repr(Hfov / 2)[0:4], "+",
              repr(trueHfov * Hoverlap / 2)[0:4], "=",
              repr(trueHfov / 2)[0:4] + "deg")
    else :
        print("# Zenith and Nadir angles:  ", repr(Vfov / 2)[0:4], "+",
              repr(trueVfov * Voverlap / 2)[0:4], "=",
              repr(trueVfov / 2)[0:4] + " deg")


print("# Modified phiMax = " + repr(phiMax)[0:4] + " deg")
print("# Modified phiMin = " + repr(phiMin)[0:5] + " deg")
print("# Row to row delta Pitch = " +
      repr(dPitch)[0:4] + " deg -----------------------> " +
      repr(int(100 * VangularExcess)) +
      " % vertical angular excess (total angle: " +
      repr(int(sigmaPhi)) + " deg)")
print("#############################")

##########----------##########----------##########----------##########----------

if nadir== "yes" :
    if trueVfov > trueHfov :
        print("\nNadir shoot at " + repr(optimalNadir)[0:5] + " deg\n")
    else :
        print("\nNadir shoot at -90 deg\n")
    pitchList=  [repr(optimalNadir)[0:5]]           ## 1 ##
    imgNbList=  [int(1)]                            ## 2 ##
    imgYawList= ["0.0"]                             ## 3 ##
else :
    pitchList=  []                                  ## 1 ##
    imgNbList=  []                                  ## 2 ##
    imgYawList= []                                  ## 3 ##


if rowNb != 1 :
    prevTop= phiMin
else :
    prevTop= (phiMin + phiMax) / 2 - Vfov / 2
i= 0

while i < rowNb :                              # begin rows loop <-----------------------------
    bottom= prevTop
    top= prevTop + dPitch
    pitch= (bottom + top) / 2

    if pitch < 0 :
        pitchList= pitchList + [repr(pitch)[0:5]]    ## 1 ##
    else :
        pitchList= pitchList + [repr(pitch)[0:4]]    ## 1 ##

    if abs(bottom) < abs(top) :        # the smaller the distance
        largeCirclePitch= abs(bottom)  # between a circle and the equator
        smallCirclePitch= abs(top)     # ... the larger this circle is
    else:
        largeCirclePitch= abs(top)
        smallCirclePitch= abs(bottom)

    largePitch=  largeCirclePitch                                 
    midlePitch=  (largeCirclePitch + smallCirclePitch) / 2       
    smallPitch=  smallCirclePitch                                 

# midlePitch (degrees, unsigned) points to the circle where images
# sides must be adjacent

    MoHSD= f / cos(radians(dPitch / 2)) # MoHSD: Middle of Horizontal Sides
                                        # Distance from sphere center
    circleRadius= MoHSD * cos (radians(midlePitch))
    largeRadius=  MoHSD * cos (radians(largePitch))
    smallRadius=  MoHSD * cos (radians(smallPitch))
                                                                     
    # angle under which is seen an image (decreased for overlap) in the:
    unadjdYaw= degrees(2 * (atan(Hside / 2 / circleRadius)))   # middle circle horizontal plane
    largedYaw= degrees(2 * (atan(trueHside / 2 / largeRadius)))# largest circle horizontal plane
    smalldYaw= degrees(2 * (atan(trueHside / 2 / smallRadius)))# smallest circle horizontal plane


    imgNb= 360 // unadjdYaw
    if imgNb * unadjdYaw < 360 :
        imgNb = imgNb + 1
    dYaw = 360 / imgNb
    if largedYaw < dYaw :
        imgNb= 360 // largedYaw
        if imgNb * largedYaw < 360 :
            imgNb = imgNb + 1
        dYaw = 360 / imgNb
        selected= "# based on LARGE circle, dYaw: " + repr(dYaw)[0:5] + " deg"
    else :
        selected= "# based on MIDLE circle, dYaw: " + repr(dYaw)[0:5] + " deg"

   
    imgNbList= imgNbList + [int(imgNb)]                ## 2 ##
    HexcessContiguous= (imgNb * unadjdYaw - 360) / 360

    toPrint = "\nrow " + repr(i + 1).ljust(2) + " of " + repr(int(rowNb)) \
            + ", pitch: " + repr(int(pitch)) \
            + " deg      # top overlap at " + repr(int(round(top))) \
            + " deg, bottom overlap at " + repr(int(round(bottom))) + " deg"
    print (toPrint)
    print("                                " + selected)

    if abs(round(top)) == abs(round(bottom)) :
        toPrint= "                                # large circle is any -----> "
    elif largeCirclePitch == abs(bottom) :
        toPrint= "                                # large circle at bottom --> "
    else:
        toPrint= "                                # large circle at top -----> "

    HexcessLarge= (largedYaw - dYaw) / largedYaw
    toPrint= toPrint + repr(int(100 * HexcessLarge)) + " % overlap"
    print (toPrint)

    toPrint=     "             deg                # small circle ------------> "
    HexcessSmall= (smalldYaw - dYaw) / smalldYaw
    toPrint= toPrint + repr(int(100 * HexcessSmall)) + " % overlap"
    print (toPrint)

    dYaw = 360 / imgNb
    j= 0                                  # begin images loop <-----------------
    while j < imgNb :
        imgYawList= imgYawList + [repr(j * dYaw)[0:5]]  ## 3 ##
        totalImgNb= totalImgNb + 1

        print ("    ", repr(j + 1).ljust(2), "yaw:", int(j * dYaw))
       
        j= j + 1                          # end   images loop <-----------------
    i= i + 1                             
    prevTop= top                          # end   rows loop <-------------------

##########----------##########----------##########----------##########----------

if zenith == "yes" :
    if trueVfov > trueHfov :
        print("\nZenith shoot at " + repr(optimalZenith)[0:4] + " deg")
    else :
        print("\nZenith shoot at 90 deg")
    pitchList= pitchList +  [repr(optimalZenith)[0:4]]   ## 1 ##
    imgNbList= imgNbList + [int(1)]                      ## 2 ##
    imgYawList= imgYawList + ["0.0"]                     ## 3 ##

print("\nTotal number of images: " + repr(totalImgNb) + "\n")

##########----------##########----------##########----------##########----------

print("#############################\n")

k= 0
for i in range(len(pitchList)) :
    pitchString= 'pitch="' + pitchList[i] + '" yaw="'
    if pitchString[7] == '-' and pitchString[9] == '.' :
        pitchString= pitchString[0:10]+pitchString[11:]
    for j in range(imgNbList[i]) :
        yawString= imgYawList[k] + '"'; k= k + 1;
        print(pitchString + yawString)
    print("")
     
print("#############################")
#print("the following is buggy...")
#totalArea= totalImgNb * trueVside * trueHside
#imgDiag = sqrt((trueVside)**2 + (trueHside)**2)
#r = sqrt(f**2 + (imgDiag / 2)**2)
#wrapingCylinderHeight = r * (  sin(radians(abs(truePhiMax)))
#                             + sin(radians(abs(truePhiMin))))
#wrapingCylinderArea= 2 * pi * r * wrapingCylinderHeight
######################
Last edited by GURL on Wed Jan 13, 2010 4:32 pm, edited 1 time in total.
Georges

no avatar
GURL
Member
 
Posts: 2946
Joined: Tue Dec 06, 2005 1:57 pm
Location: Grenoble

by GURL » Mon Jan 11, 2010 8:42 pm

The aim of this Python 3.1 program is to compute good pitch and yaw values to be used when shooting spherical 360 degrees panos, so that It will not work for usual "regular", "rectangular", "rows x columns", "non-360" panos...

This is the 0.0.0 pre-release, pre-candidate version.

For this reason, there is no GUI interface or, to be honest, no interface at all: one must modify the parameters values in the source program using a text editor like the Window notepad...

PARAMETERS

f ...................... lens focal lens in millimeters
Vside ................ sensor vertical sides size in millimeters
Hside ................ sensor horizontal sides size in millimeters
phiMin ............... bottom angle of the pano (like in Autopano Editor window, bottom right corner)
phiMax .............. top angle of the pano (like in Autopano Editor window, bottom right corner)
Hoverlap ............ horizontal overlap, between 0 (0 %) and 1 (100%)
Voverlap ............ vertical overlap, between 0 (0 %) and 1 (100%)
panoheadPhiMin .. maximum angle of the pano head toward nadir
panoheadPhiMax .. maximum angle of the pano head toward zenith

Code: Select all
######################### <--  T H E    9    P A R A M E T E R S   Y O U    M U S T   S E T   A R E   T H E R E
                        #     #################################################################################
f= 9                    #     mm, for example 50 mm
Vside= 17.3             #     mm, for example 36 mm  _  portrait / landscape source images orientation is found there
Hside= 13               #     mm, for example 24 mm  /
phiMin= -70             #     degrees, from -90 (nadir) toward 90
phiMax= 90              #     degrees, up to 90 (zenith) toward -90
Hoverlap= 0.15          #     horizontal overlap, coef from 0 (= none) up to more than 0.5 (= 50 %)
Voverlap= 0.15          #     vertical overlap, coef from 0 up to more than 0.5
                        #
panoheadPhiMin= -70     #     degrees, from -90 (nadir)  _ that's to avoid the camera codides with the pano head !
panoheadPhiMax= 90      #     degrees, up to 90 (zenith) /
                        #
#########################

OVERLAP

There is a vertical overlap parameter plus a horizontal overlap parameter because ...why not?
You must be warned that I hope the final overlap will be alway greater than the parameter values, but I'm not sure yet!
On a spherical surface there is no clear and well known definition of overlap: overlap varies from one row to the next and an 'angular overlap' apparently makes more sense than a 'linear overlap' (which, BTW, would be very difficult to compute.)
Georges

no avatar
GURL
Member
 
Posts: 2946
Joined: Tue Dec 06, 2005 1:57 pm
Location: Grenoble

by GURL » Mon Jan 11, 2010 8:45 pm

IMPROVEMENTS:

Though my own list includes many possible refinements, I'm completely open to any idea...
Georges

no avatar
JohnM
Member
 
Posts: 188
Joined: Tue Oct 31, 2006 9:47 pm

by JohnM » Mon Jan 11, 2010 11:48 pm

Thats cool. I dont have a head yet, but this script is a timesaver when shooting sphericals with wide lenses and might be my reason to get a PapyWizard setup for tricky places like under a bridge, on top of masts etc.

no avatar
GURL
Member
 
Posts: 2946
Joined: Tue Dec 06, 2005 1:57 pm
Location: Grenoble

by GURL » Tue Jan 12, 2010 6:55 pm

Here is an example for an APS-C camera and a 18 mm 'kit' lens:
PapySpheric wrote:Camera:
Sensor size 15.6 x 23.4 mm
Focal length 18 mm
Lens vertical FOV 66 deg
Lens horizontal FOV 47 deg

Panorama:
Top at 90 deg
Bottom at -90 deg
vertical FOV 180 deg
Vertical overlap 20 %
Horizontal overlap 20 %

Pano-head:
downward limit -75 deg

Number of rows: 3 + zenith

row 1 of 3, pitch: -57 deg

deg
1 yaw: 0
2 yaw: 45
3 yaw: 90
4 yaw: 135
5 yaw: 180
6 yaw: 225
7 yaw: 270
8 yaw: 315

row 2 of 3, pitch: -6 deg

deg
1 yaw: 0
2 yaw: 36
3 yaw: 72
4 yaw: 108
5 yaw: 144
6 yaw: 180
7 yaw: 216
8 yaw: 252
9 yaw: 288
10 yaw: 324

row 3 of 3, pitch: 45 deg

deg
1 yaw: 0
2 yaw: 45
3 yaw: 90
4 yaw: 135
5 yaw: 180
6 yaw: 225
7 yaw: 270
8 yaw: 315

Zenith shoot at 80.4 deg


Total number of images: 27
Georges

User avatar
gkaefer
Member
 
Posts: 3358
Joined: Tue Jun 09, 2009 1:01 pm
Location: Salzburg

by gkaefer » Wed Jan 13, 2010 2:05 pm

I cant start it...

what I did:
installed python 2.6.4 for windows from:
http://www.python.org/ftp/python/2.6.4/python-2.6.4.msi
I saved your sourccode as papysperic.py under C:\Python26 (default phyton dir on win)
I opened phyton gui
opened papyspheric.py
I do a "run module"

"There's an error in your program: unexpedted ident"

it than goes to line 164:
imgNb= 360 // unadjDeltaYaw

sorry... no linux available ;-(

Liebe Gruesse,
Georg
Last edited by gkaefer on Wed Jan 13, 2010 2:06 pm, edited 1 time in total.

User avatar
Paul
Member
 
Posts: 778
Joined: Sat Aug 30, 2008 4:46 pm
Location: Bonn, Germany

by Paul » Wed Jan 13, 2010 4:00 pm

YES you can too ..


I can start it...

what I did:

I deleted the linefeed before the word "cercle" and bingo ...
# angle sous lequel on voit le côté entier dans le plan du plus petit cercle

and I did it with portable python
more infos here:http://href.to/hqt
Paul

close, but no cigar ... ... ...

User avatar
gkaefer
Member
 
Posts: 3358
Joined: Tue Jun 09, 2009 1:01 pm
Location: Salzburg

by gkaefer » Wed Jan 13, 2010 4:42 pm

Paul wrote:YES you can too ..


I can start it...

what I did:

I deleted the linefeed before the word "cercle" and bingo ...
# angle sous lequel on voit le côté entier dans le plan du plus petit cercle

and I did it with portable python
more infos here:http://href.to/hqt

;-) ok bingo...

the today updated sourcecode from above works also with my python version now fluently

Liebe Gruesse,
Georg

User avatar
claudevh
Member
 
Posts: 1341
Joined: Sun Nov 25, 2007 11:12 pm
Location: Mont-Saint-André (Belgium)

by claudevh » Wed Jan 13, 2010 4:54 pm

Hello Gurl,

With the correction of Paul, it work fine ! :)
This "calculator" is only for "Wide Angle" , could we have the same for "Fish eyes" or may be a additional parameter for the choice between the 2 ?
:cool: Claude :cool:
Merlin + Papywizard on Windows 7 & Nokia 770 § N810 & Acer (Netbook) + PanoramaApp Androïd + Deltawave PapyMerlin BT + Autopano
Spherical Pano (180 x 360) with Canon 40D + Canon EF-S 10-22mm f/3.5-4.5 Zoom & Pôle Pano with Canon 5D MK2 and shaved Tokina 10-17 3.5-4.5 AF DX Fisheye
Gigapixel photography with Nikon D200 + Sigma 70-200 F 2.8 EX DG APO HSM

no avatar
GURL
Member
 
Posts: 2946
Joined: Tue Dec 06, 2005 1:57 pm
Location: Grenoble

by GURL » Wed Jan 13, 2010 4:57 pm

I replaced the previous 0.0.0 by the 0.0.1 version in the above post

- Bug: the lines are shorter, so that no more folded line errors should occur.
- Bugs: many were removed but probably some were added...
- Added: pitch="pp.p" yaw="yy.y" for each images in the results.
- Added: input parameters are now verified.
- Improved: vertical overlap computations.

The most difficult part is to compute the actual overlap. I'm not satisfied with the present approximations but the truth is that there is no obvious definition of overlap on a sphere... Angular overlap seems more useful than linear overlap but average overlap is not enough as each image must have enough overlap with the adjoining ones.
Georges

no avatar
360pano
Member
 
Posts: 35
Joined: Tue Sep 22, 2009 3:16 pm
Location: Germany

by 360pano » Wed Jan 13, 2010 5:13 pm

GURL wrote:- Added: pitch="pp.p" yaw="yy.y" for each images in the results.

You will insert <pict and /> ?

<pict pitch="pp.p" yaw="yy.y" />

*edit*

I found it, change this lines:

Code: Select all
print("#############################\n")

k= 0
for i in range(len(pitchList)) :
    pitchString= '<pict pitch="' + pitchList[i] + '" yaw="'
    if pitchString[7] == '-' and pitchString[9] == '.' :
        pitchString= pitchString[0:10]+pitchString[11:]
    for j in range(imgNbList[i]) :
        yawString= imgYawList[k] + '" />'; k= k + 1;
        print(pitchString + yawString)
    print("")
Last edited by 360pano on Wed Jan 13, 2010 5:21 pm, edited 1 time in total.

User avatar
claudevh
Member
 
Posts: 1341
Joined: Sun Nov 25, 2007 11:12 pm
Location: Mont-Saint-André (Belgium)

by claudevh » Wed Jan 13, 2010 5:52 pm

Addition of 360pano ...

Very fine ! :)

A little more step and you generate the complete PPW XML file with "preset name" and "Tooltip" ... this will be perfect really !
;)
:cool: Claude :cool:
Merlin + Papywizard on Windows 7 & Nokia 770 § N810 & Acer (Netbook) + PanoramaApp Androïd + Deltawave PapyMerlin BT + Autopano
Spherical Pano (180 x 360) with Canon 40D + Canon EF-S 10-22mm f/3.5-4.5 Zoom & Pôle Pano with Canon 5D MK2 and shaved Tokina 10-17 3.5-4.5 AF DX Fisheye
Gigapixel photography with Nikon D200 + Sigma 70-200 F 2.8 EX DG APO HSM

no avatar
GURL
Member
 
Posts: 2946
Joined: Tue Dec 06, 2005 1:57 pm
Location: Grenoble

by GURL » Wed Jan 13, 2010 6:03 pm

claudevh wrote:This "calculator" is only for "Wide Angle" , could we have the same for "Fish eyes" or may be a additional parameter for the choice between the 2 ?

Wide angle? actually the longer the lens the more useful it is because it avoids useless shoots next to zenith and nadir...

For fisheyes the easiest way is to make another version of the program. Actually, if taking into account the horizontal and vertical FOV only is OK (this is equivalent to ignore the fisheye images corners) this should be quite easy.

The resulting program (papyfish?) would be useless for circular image fisheyes. Whether it would be useful for the "rectangular image, 180 degrees diagonal fisheyes" remains to be seen. My guess is that it would be useful for the Tokina 10-17 mm zoom fisheye when used at a larger than 10 mm focal length...
Last edited by GURL on Wed Jan 13, 2010 6:05 pm, edited 1 time in total.
Georges

no avatar
mediavets
Moderator
 
Posts: 14178
Joined: Wed Nov 14, 2007 2:12 pm
Location: Isleham, Cambridgeshire, UK.

by mediavets » Wed Jan 13, 2010 8:53 pm

claudevh wrote:A little more step and you generate the complete PPW XML file with "preset name" and "Tooltip" ... this will be perfect really !
;)

Especially if it was a Web-based on-line tool.
Andrew Stephens
Many different Nodal Ninja and Agnos pano heads. Merlin/Panogear mount with Papywizard on Nokia Internet tablets.
Nikon D5100 and D40, Sigma 8mm f3.5 FE, Nikon 10.5mm FE, 35mm, 50mm, 18-55mm, 70-210mm. Promote control.

User avatar
gkaefer
Member
 
Posts: 3358
Joined: Tue Jun 09, 2009 1:01 pm
Location: Salzburg

by gkaefer » Wed Jan 13, 2010 10:41 pm

GURL wrote:I replaced the previous 0.0.0 by the 0.0.1 version in the above post

The most difficult part is to compute the actual overlap. I'm not satisfied with the present approximations but the truth is that there is no obvious definition of overlap on a sphere... Angular overlap seems more useful than linear overlap but average overlap is not enough as each image must have enough overlap with the adjoining ones.

if I let review my last 360 panos I made, I notice following point: How many percent overlap are finally good for an proper stitching depends in many cases on the object I do fotograph. Sky in general I can have 10% overlap - because in most cases I have to place the image manually (no difference to 20% and 25% overlap) or if papywizzard and merlin is involved placement is supported by xml paywizard logfile. In case of crowded sceens with a lot of moving people its easier for AP to erase ghosts if overlap is 25-30%. So some sort of mechanism to define different percentage of overlap for different parts of the pano would be worth considering.

Liebe Gruesse,
Georg

User avatar
fma38
Member
 
Posts: 5827
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Wed Jan 13, 2010 10:48 pm

gkaefer wrote:So some sort of mechanism to define different percentage of overlap for different parts of the pano would be worth considering.

I think you will spend more time to tell which overlap you want in different areas rather than shooting 2 o 3 useless pictures ;)
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

no avatar
GURL
Member
 
Posts: 2946
Joined: Tue Dec 06, 2005 1:57 pm
Location: Grenoble

by GURL » Thu Jan 14, 2010 5:56 pm

fma38 wrote:I think you will spend more time to tell which overlap you want in different areas rather than shooting 2 o 3 useless pictures ;)

Having a larger overlap next to the horizon because this is where most events happen could be an option...

:P In a very distant future adjacent views will be analyzed by Papywizard which will decide whether some more shots are needed to avoid ghosts (this is no a joke as a very fast camera could take a series of views to detect large moving objects crossing the images boundaries.)
Georges

no avatar
GURL
Member
 
Posts: 2946
Joined: Tue Dec 06, 2005 1:57 pm
Location: Grenoble

by GURL » Thu Jan 14, 2010 6:21 pm

Here is a tooltip proposal:

Future version wrote:<tooltip>
Camera:
Sensor size 15.5 x 23 mm
Focal length 80 mm
Panorama:
vertical FOV 176.7 deg
images number 384
Minimum overlap V: 20 %, H: 20 %
Pano-head:
downward limit -85 deg
upward limit 85 deg
</tooltip>


Suggested name: Rect80mmSpheric-90to90

The name corresponds to : rectilinear 80mm lens - Spherical pano - Pitch from -90 deg to +90 deg

I don't know which tags are useful in the followin list:

documentation wrote:<header>
<shooting mode="preset">
<headOrientation>up, left, right, down</headOrientation>
<cameraOrientation>portrait, landscape</cameraOrientation>
</shooting>
<camera>
<sensor coef="[float]" ratio="[ratio]"/>
</camera>
<lens type=rectilinear>
<focal>[float]</focal>
</lens>
<preset name="[str]" />
</header>

<shoot>
<pict id="[int]">
<position pitch="[float]" yaw="[float]" roll="[float]"/>
</pict>
...
</shoot>
Georges

User avatar
fma38
Member
 
Posts: 5827
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Fri Jan 15, 2010 7:49 am

USefull for APP, you mean? I don't know what tags are really used... Only Alexandre can tell...

BTW, Georges, you should use the xml.dom.minidom module to generate your xml file; this is much easier. Have a look in http://www.papywizard.org/browser/trunk/papywizard/model/data.py for a example.
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

no avatar
GURL
Member
 
Posts: 2946
Joined: Tue Dec 06, 2005 1:57 pm
Location: Grenoble

by GURL » Fri Jan 15, 2010 4:21 pm

fma38 wrote:Useful for APP, you mean? I don't know what tags are really used... Only Alexandre can tell...

No, I mean useful for Papywizard... actually, I don't even know how the preset content is fed into Papywyzard (but hope long presets are not to be entered manually!)

fma38 wrote:BTW, Georges, you should use the xml.dom.minidom module to generate your xml file; this is much easier. Have a look in http://www.papywizard.org/browser/trunk/papywizard/model/data.py for a example.

:o Ah ben si c'est simple ça m'encourage pas. :rolleyes: En fait je suis un complet débutant Python: je ne sais ni lire ni écrire un fichier et encore moins intéragir avec l'extérieur à  travers une interface (les seuls outils dans le genre que je connaisse c'est Javascript (qui ne peut pas écrire de fichier) et Visual Basic qui... (bon, qui ne fait pas l'affaire!)
Georges

User avatar
fma38
Member
 
Posts: 5827
Joined: Wed Dec 07, 2005 6:21 pm
Location: Grenoble, France

by fma38 » Fri Jan 15, 2010 4:35 pm

Pour ce qui est de lire/écrire des fichiers, c'est vraiment trivial :

Code: Select all
# lire toutes les lignes d'un fichier
f = file("titi.txt")
for line in f:
    print line

# écrire un fichier
f = file("titi.txt", "w")
f.write("ligne 1\n")
f.write("ligne 2\n")
f.close()

Pour générer du xml, tu construis ton arbre en mémoire (noeuds, sous-noeuds), puis tu le sérializes sous forme de chaine, ou directement sur disque.

Par contre, pour ce qui est d'interagir avec l'utilisateur, c'est toujours la partie chiante. Python dispose en standard d'un toolkit graphique, Tkinter, basé sur Tk. Ce n'est certes pas le mieux, mais pour débuter, c'est bien pratique. Et surtout, pour distribuer ton code, tu n'as pas à  te casser la tête à  packager un toolkit externe (si tout le monde utilisait linux, ça ne poserait pas de problème, puisque la plupart des distributions intègrent tous les principaux toolkit et permettent de les installer en 3 clicks, mais il y a Windows et MacOS, où c'est la croix et la bannière pour faire le moindre truc).

Plus d'infos sur Tkinter :

http://www.pythonware.com/library/tkinter/introduction

Et n'hésite pas à  me contacter en privé pour des renseignements plus précis, sur Tkinter ou xml...
Frédéric

Canon 20D + 17-40/f4 L USM + 70-200/f4 L USM + 50/f1.4 USM
Merlin/Orion panohead + Papywizard on Nokia N800 and HP TC-1100

no avatar
mediavets
Moderator
 
Posts: 14178
Joined: Wed Nov 14, 2007 2:12 pm
Location: Isleham, Cambridgeshire, UK.

by mediavets » Mon Feb 01, 2010 1:42 pm

GURL wrote:
fma38 wrote:I think you will spend more time to tell which overlap you want in different areas rather than shooting 2 o 3 useless pictures ;)

Having a larger overlap next to the horizon because this is where most events happen could be an option...

:P In a very distant future adjacent views will be analyzed by Papywizard which will decide whether some more shots are needed to avoid ghosts (this is no a joke as a very fast camera could take a series of views to detect large moving objects crossing the images boundaries.)

Georges,

I don't begin to understand how to use your program. I was hoping it might be an on-line tool by now that, from appropriate input data, could/would generate a Papywizard preset file, but I think not yet?

Howver it sounds to be just what I need to configure preset for use with my Nikon D40 (1.5x crop) and 50mm and 35mm rectilinear lenses so I canc experiment shooting some higher res. spherical panos on the Merlin.

Could you calculate the shooting position values for me?

...........

BTW you are not alone in creating a program with such a goal:
http://panorama-factory.ch/_English/e_Menu_PanoCalculator/PanoCalcOverview.html

Something like his version for the Rodeon Modular, but for Papywizard+Merlin, would be interesting:
http://panorama-factory.ch/_English/e_Menu_PanoCalculator/RodeonModular/RodeonModular.html
Andrew Stephens
Many different Nodal Ninja and Agnos pano heads. Merlin/Panogear mount with Papywizard on Nokia Internet tablets.
Nikon D5100 and D40, Sigma 8mm f3.5 FE, Nikon 10.5mm FE, 35mm, 50mm, 18-55mm, 70-210mm. Promote control.

no avatar
solock
Member
 
Posts: 64
Joined: Tue Apr 14, 2009 4:52 pm
Location: lehigh valley pa

by solock » Sun Feb 07, 2010 10:56 pm

This is looking very useful, just must be missing something.

Python installed, copied the code and saved as a .py file

module runs, makes the output, but...

what to do with the output to make it be loadable as a preset on papy??

Does it need some further conversion?

Sorry for being dense here...

Thanks,

Steve
Canon 50D, 20D, 1D MKII
Tok 10-17FishEye,Canon 10-22, 24-70 2.8, 50 1.4, 70-200 2.8IS, 300 2.8,1.4x,2.0x
303SPH, Panosaurus, Merlin+Parallax Bluetooth+USB to PC and Nokia N810

no avatar
mediavets
Moderator
 
Posts: 14178
Joined: Wed Nov 14, 2007 2:12 pm
Location: Isleham, Cambridgeshire, UK.

by mediavets » Sun Feb 07, 2010 11:20 pm

solock wrote:This is looking very useful, just must be missing something.

Python installed, copied the code and saved as a .py file

module runs, makes the output, but...

what to do with the output to make it be loadable as a preset on papy??

Does it need some further conversion?

Sorry for being dense here...

Thanks,

Steve

Look here to see what the format of a custom preset looks like:
http://www.papywizard.org/wiki/UserGuideSvn#Custompresets

You should be able to use the output to create one.

Ignore the stuff about having to place the preset file in a particular location - that's only if you wish your new preset to appear in the default set.

Otherwise the custom preset file(s) can be named anything-you-like.xml and placed anywhere in the file system Then use the Papywizard File/Load preset to load custom preset file(s) on a per session basis.

Does this help?
Last edited by mediavets on Sun Feb 07, 2010 11:22 pm, edited 1 time in total.
Andrew Stephens
Many different Nodal Ninja and Agnos pano heads. Merlin/Panogear mount with Papywizard on Nokia Internet tablets.
Nikon D5100 and D40, Sigma 8mm f3.5 FE, Nikon 10.5mm FE, 35mm, 50mm, 18-55mm, 70-210mm. Promote control.

no avatar
solock
Member
 
Posts: 64
Joined: Tue Apr 14, 2009 4:52 pm
Location: lehigh valley pa

by solock » Sun Feb 07, 2010 11:56 pm

got it, thanks ..

so make a master xml, as per the standard

run this python app

cut and paste the tooltip for description into new xml

cut and paste the pitch & yaw portion into new xml

save as new preset & import

than helps alot...

Now to make a master preset set for my anticipated shoots...

Again, thanks for all the help...
Canon 50D, 20D, 1D MKII
Tok 10-17FishEye,Canon 10-22, 24-70 2.8, 50 1.4, 70-200 2.8IS, 300 2.8,1.4x,2.0x
303SPH, Panosaurus, Merlin+Parallax Bluetooth+USB to PC and Nokia N810

Next

Return to Motorized panohead project: Merlin, Orion & Papywizard

Who is online

Users browsing this forum: No registered users and 1 guest