Atv to height conversion mismatch for cylindrical panoramas

  • Hi. I'm having an issue related to converting my hotspots' cylindrical coordinates to width/height coordinates.

    Context: I have thousands of hotspots defined throughout hundreds of my cylindrical panoramas.
    Now I need to get their width/height pixel location equivalents on the original images.
    Converting ath -> x works perfectly fine, however for atv there's a varying vertical offset I'm getting.

    I'm using formulas posted by Klaus in a different thread:

    ath = ((x / width) - 0.5) * hfov
    atv = ((y / height) - 0.5) * vfov
    where for cylindrical panorama:
    hfov = 360
    vfov = 360 * arctan(height/width * PI) / PI

    1. I have an image of size: 28133 x 6608.

    2. I make a panorama out of it using makepano and following settings:

    makepano -config=base.config -panotype=cylinder -hfov=360 -vfov=auto -voffset=0 

    Note: makepano generates vlookatmin="-36.424" and vlookatmax="36.424"

    3. In the viewer using textfield plugin showing draggable cursor's ath/atv I pick an exact point eg. top of a mountain.
    It gives me following coordinates: ath="-74.99364949868569" atv="-19.815171882512473"
    What produces aforementioned ath/atv coordinates is a result of an action:

    4. When I store the ath/atv output and render a panorama with this hotspot and its atv/atv layered it points exactly in the place I picked. It's been working for years for hundreds of panoramas.

    5. Now the very same point on the source image has following XY px coordinates: 8206, 1690
    Calculating manually ath and atv gives following results:

    Image: 28133 x 6608
    ath = -74.993068638254007748906977570824
    vfov = 360 * arctan( 6608/28133 * PI ) / PI = 72.8480327
    atv = -17.7930878901

    That proves that the ath is correct but in atv -> height conversion there's a difference of -2.022083992412473 degrees (viewer yields -19.815171882512473 as mentioned above, but it should yield -17.7930878901).

    Note: looking at different points in height yields good conversion in the middle (ath = 0), but the further the point from the middle of the image horizon the offset is bigger. Given that I feel it's related to cylindrical-cubic projection?

    Any help appreciated.

    Firstly, why the viewer is yielding incorrect atv or what I've been doing wrong for years?

    Secondly, how to convert existing points (ath, atv) to width/height pixel values?


  • Hi,

    1. the hotspot ath/atv coordinates are always spherical, regardless of the image type.

    2 .for converting a point on cylinder surface to a point on spherical surface only the right math need to be used (the image size to hfov/vfov conversion is wrong here).

    Here a little helper script for doing that automatically (needs version 1.21):

    <style name="cylinder_image_xy_pos" onloaded.addevent="calc_cylinder_hs_pos();" />
    <action name="calc_cylinder_hs_pos">
      callwhen(image.hres GT 0,
        ath = (imgx/image.hres - 0.5) * image.hfov;
        atv = atan(tan(image.vfov/2 * Math.PI/180) * 2 * ((imgy / image.vres) - 0.5)) * 180/Math.PI;

    - the callwhen ensure that the image size information are available before doing the math
    - the tan(image.vfov/2 * http://Math.PI/180) * 2 calcs the vertical range of the cylinder
    - the * ((imgy / image.vres) - 0.5) maps the pixel-point linear to that vertical range
    - and then that vertical position is converted back to an angle in degrees

    To use the script, give your hotspots the "cylinder_image_xy_pos" style and define the pixel-position on the cylinder image as custom imgx/imgy settings:

    <hotspot name="s1" style="cylinder_image_xy_pos" imgx="1256" imgy="1977" />
    <hotspot name="s2" style="cylinder_image_xy_pos" imgx="732" imgy="1125" />

    Best regards,

  • Thank you Klaus!

    Formula you used was everything I needed to get it working:

    atv = atan(tan(image.vfov/2 * Math.PI/180) * 2 * ((imgy / image.vres) - 0.5)) * 180/Math.PI;

    After transforming it to have imgy on the left I got:

    y = (math.tan(atv * math.pi/180) / (2 * math.tan(image.vfov/2 * math.pi/180))) * image.vres + (0.5 * image.vres)

    Though in my case krpano yielded 180 for image.vfov in the console and it was still not working.
    But it got me into the right direction. After I substituted it with the range of vfov, which is:

    abs(vlookatmin) + abs(vlookatmax)

    it is OK now.

    So the whole working formula to calculate pixel coordinates when I have cylindrical coordinates (avh, ath) is in my case:

    x = (ath + 180.0) * pano_image_width_px / 360.0
    y = (math.tan(atv * math.pi/180) / (2 * math.tan(vlookatrange/2 * math.pi/180))) * pano_image_height_px + (0.5 * pano_image_height_px)
    where vlookatrange = abs(vlookatmin) + abs(vlookatmax)

Participate now!

Don’t have an account yet? Register yourself now and be a part of our community!