Photo Sphere XMP Metadata

The panorama namespace described here contains properties that provide information regarding the creation and rendering of photo spheres, also sometimes referred to as panoramas, such as those created by the Photo Sphere feature in the Android 4.2 camera. The metadata should be serialized and embedded inside the photo sphere as described by the Adobe XMP standard (see references at the end of this page).

The namespace URI is http://ns.google.com/photos/1.0/panorama/

Metadata properties

The diagrams and table below show the photo sphere properties encapsulated by the GPano Parameters. When editing and viewing photo spheres, please be sure to verify and update the metadata accordingly as described later in this document. When specifying the pose and initial heading fields, please be sure to follow the Euler angle conventions discussed later in this document.

Note that Google products support spherical projections only. Additional projections are currently supported only by other parties.

Spherical projections

Cylindrical projections

Note that if the top of a cylindrical image is above the horizon, CroppedAreaTopPixels must be negative. A value of 0 for CroppedAreaTopPixels will place the top of the image at the horizon. A positive value of CroppedAreaTopPixels places the top of the image below the horizon.

GPano parameter reference

Name Type Required Default value
(viewer assumed)
Property description Action required if image is modified
GPano:UsePanoramaViewer Boolean No True Whether to show this image in a photo sphere viewer rather than as a normal flat image. This may be specified based on user preferences or by the stitching software. The application displaying or ingesting the image may choose to ignore this. scale/crop:
No change. An application may decide to switch this to False if the field of view falls below a certain value.
GPano:CaptureSoftware String No n/a If capture was done using an application on a mobile device, such as an Android phone, the name of the application that was used (such as “Photo Sphere”). This should be left blank if source images were captured manually, such as by using a DSLR on a tripod. n/a
GPano:StitchingSoftware String No n/a The software that was used to create the final photo sphere. This may sometimes be the same value as that of  GPano:CaptureSoftware. n/a
GPano:ProjectionType Open Choice of Text Yes

equirectangular

Projection type used in the image file. Google products currently support the value equirectangular only. scale/crop: No change.
GPano:PoseHeadingDegrees Real No, but is required for display on Google Maps n/a Compass heading, measured in degrees clockwise from North, for the center the image. Value must be >= 0 and < 360. scale/crop: No change.
GPano:PosePitchDegrees Real No 0 Pitch, measured in degrees above the horizon, for the center in the image. Value must be >= -90 and <= 90. scale/crop: No change.
GPano:PoseRollDegrees Real No 0 Roll, measured in degrees, of the image where level with the horizon is 0. As roll increases, the horizon rotates counterclockwise in the image. Value must be > -180 and <= 180. scale/crop: No change.
GPano:InitialViewHeadingDegrees Integer No 0 The heading angle of the initial view in degrees clockwise from real world North, not relative to the pano center. scale/crop: No change.
GPano:InitialViewPitchDegrees Integer No 0 The pitch angle of the initial view in degrees above the real world horizon, not relative to the pano center. scale/crop: No change.
GPano:InitialViewRollDegrees Integer No 0 The roll angle of the initial view in degrees where level with the real world horizon is 0. As roll increases, the horizon rotates counterclockwise in the view. scale/crop: No change.
GPano:InitialHorizontalFOVDegrees Real No n/a The initial horizontal field of view that the viewer should display (in degrees). This is similar to a zoom level. n/a
GPano:InitialVerticalFOVDegrees Real No n/a The initial vertical field of view that the viewer should display (in degrees). This is similar to a zoom level. If both GPano:InitialHorizontalFOVDegrees and GPano:InitialVerticalFOVDegrees are present, GPano:InitialHorizontalFOVDegrees takes precedence. Use only InitialVerticalFOVDegrees if your content is to be displayed in multiple aspect ratios, and you would prefer the vertical field of view to remain constant while the horizontal field of view may change. Google products currently do not support this field. n/a
GPano:FirstPhotoDate Date No n/a Date and time for the first image created in the photo sphere. scale/crop: No change.
GPano:LastPhotoDate Date No n/a Date and time for the last image created in the photo sphere. scale/crop: No change.
GPano:SourcePhotosCount Integer No n/a Number of source images used to create the photo sphere. scale/crop: No change.
GPano:ExposureLockUsed Boolean No n/a When individual source photographs were captured, whether or not the camera’s exposure setting was locked. n/a
GPano:CroppedAreaImageWidthPixels Integer Yes n/a Original width in pixels of the image (equal to the actual image’s width for unedited images). See diagrams above. scale/crop: This property needs to be updated to reflect the new size of the image.
GPano:CroppedAreaImageHeightPixels Integer Yes n/a Original height in pixels of the image (equal to the actual image’s height for unedited images). See diagrams above. scale/crop: This property needs to be updated to reflect the new size of the image.
GPano:FullPanoWidthPixels Integer Yes n/a Original full width from which the image was cropped. If only a partial photo sphere was captured, this specifies the width of what the full photo sphere would have been. See diagrams above. crop: No change.
scale: This properly needs to be scaled accordingly.
GPano:FullPanoHeightPixels Integer Yes n/a Original full height from which the image was cropped. If only a partial photo sphere was captured, this specifies the height of what the full photo sphere would have been. See diagrams above. crop: No change.
scale: This properly needs to be scaled accordingly.
GPano:CroppedAreaLeftPixels Integer Yes n/a Column where the left edge of the image was cropped from the full sized photo sphere. See diagrams above. crop: If the left crop of the image is changed, this value must be updated.
scale: This properly needs to be scaled accordingly.
GPano:CroppedAreaTopPixels Integer Yes n/a Row where the top edge of the image was cropped from the full sized photo sphere. See diagrams above. crop: If the top crop of the image is changed, this value must be updated.
scale: This properly needs to be scaled accordingly.
GPano:InitialCameraDolly Real No 0 This optional parameter moves the virtual camera position along the line of sight, away from the center of the photo sphere. A rear surface position is represented by the value -1.0, while a front surface position is represented by 1.0. For normal viewing, this parameter should be set to 0. n/a

Example of a full photo sphere

Non-programmers can add the metadata example below to their existing full photo spheres (360 degrees x 180 degrees) with only small modifications. This can be done in image editing products, such as Adobe Photoshop.

  1. change any occurrences of 4000 and 2000 to match the corresponding width and height of your image in pixels
  2. update PoseHeadingDegrees if you want Google Maps to be able to show your photo sphere; otherwise, you may optionally remove this parameter
  3. update or remove optional parameters (as listed above)
<rdf:Description rdf:about="" xmlns:GPano="http://ns.google.com/photos/1.0/panorama/">
    <GPano:UsePanoramaViewer>True</GPano:UsePanoramaViewer>
    <GPano:CaptureSoftware>Photo Sphere</GPano:CaptureSoftware>
    <GPano:StitchingSoftware>Photo Sphere</GPano:StitchingSoftware>
    <GPano:ProjectionType>equirectangular</GPano:ProjectionType>
    <GPano:PoseHeadingDegrees>350.0</GPano:PoseHeadingDegrees>
    <GPano:InitialViewHeadingDegrees>90.0</GPano:InitialViewHeadingDegrees>
    <GPano:InitialViewPitchDegrees>0.0</GPano:InitialViewPitchDegrees>
    <GPano:InitialViewRollDegrees>0.0</GPano:InitialViewRollDegrees>
    <GPano:InitialHorizontalFOVDegrees>75.0</GPano:InitialHorizontalFOVDegrees>
    <GPano:CroppedAreaLeftPixels>0</GPano:CroppedAreaLeftPixels>
    <GPano:CroppedAreaTopPixels>0</GPano:CroppedAreaTopPixels>
    <GPano:CroppedAreaImageWidthPixels>4000</GPano:CroppedAreaImageWidthPixels>
    <GPano:CroppedAreaImageHeightPixels>2000</GPano:CroppedAreaImageHeightPixels>
    <GPano:FullPanoWidthPixels>4000</GPano:FullPanoWidthPixels>
    <GPano:FullPanoHeightPixels>2000</GPano:FullPanoHeightPixels>
    <GPano:FirstPhotoDate>2012-11-07T21:03:13.465Z</GPano:FirstPhotoDate>
    <GPano:LastPhotoDate>2012-11-07T21:04:10.897Z</GPano:LastPhotoDate>
    <GPano:SourcePhotosCount>50</GPano:SourcePhotosCount>
    <GPano:ExposureLockUsed>False</GPano:ExposureLockUsed>
</rdf:Description>

Example of a partial photo sphere

<rdf:Description rdf:about="" xmlns:GPano="http://ns.google.com/photos/1.0/panorama/">
    <GPano:UsePanoramaViewer>True</GPano:UsePanoramaViewer>
    <GPano:CaptureSoftware>Photo Sphere</GPano:CaptureSoftware>
    <GPano:StitchingSoftware>Photo Sphere</GPano:StitchingSoftware>
    <GPano:ProjectionType>equirectangular</GPano:ProjectionType>
    <GPano:PoseHeadingDegrees>350.0</GPano:PoseHeadingDegrees>
    <GPano:InitialViewHeadingDegrees>90.0</GPano:InitialViewHeadingDegrees>
    <GPano:InitialViewPitchDegrees>0.0</GPano:InitialViewPitchDegrees>
    <GPano:InitialViewRollDegrees>0.0</GPano:InitialViewRollDegrees>
    <GPano:InitialHorizontalFOVDegrees>75.0</GPano:InitialHorizontalFOVDegrees>
    <GPano:CroppedAreaLeftPixels>90</GPano:CroppedAreaLeftPixels>
    <GPano:CroppedAreaTopPixels>128</GPano:CroppedAreaTopPixels>
    <GPano:CroppedAreaImageWidthPixels>2300</GPano:CroppedAreaImageWidthPixels>
    <GPano:CroppedAreaImageHeightPixels>1042</GPano:CroppedAreaImageHeightPixels>
    <GPano:FullPanoWidthPixels>4000</GPano:FullPanoWidthPixels>
    <GPano:FullPanoHeightPixels>2000</GPano:FullPanoHeightPixels>
    <GPano:FirstPhotoDate>2012-11-07T21:03:13.465Z</GPano:FirstPhotoDate>
    <GPano:LastPhotoDate>2012-11-07T21:04:10.897Z</GPano:LastPhotoDate>
    <GPano:SourcePhotosCount>50</GPano:SourcePhotosCount>
    <GPano:ExposureLockUsed>False</GPano:ExposureLockUsed>
</rdf:Description>

Robustness to image editing

To be robust, programs that display photo spheres in a viewer should check if the original photo sphere has been scaled by an application without updating the metadata. This can be done in the following steps:

  1. ensure that CroppedAreaImageWidthPixels tag is equal to the actual image width
  2. ensure that CroppedAreaImageHeightPixels tag is equal to the actual image height
  3. if step 1 or 2 fails, check if the aspect ratio of the image has been preserved
  4. if step 3 fails, do not display the image as a photo sphere as it has been transformed in an incompatible manner that will introduce bad distortions
  5. if step 3 passes, the aspect ratio is equivalent and all of the following associated tag values should be scaled to fit the new image size:
    CroppedAreaImageWidthPixels, CroppedAreaImageHeightPixels, FullPanoWidthPixels, FullPanoHeightPixels, CroppedAreaLeftPixels, CroppedAreaRightPixels.

Overview of Euler Angles

The orientation of the photo sphere in the world frame is defined by Euler angles. Euler angles can be defined in many ways. To be correct, a program must strictly follow the Euler angle conventions described here.

The position above the earth’s surface defines a fixed "local frame" XYZ, where Z is up and orthogonal to the earth’s surface, X is true east, and Y is true north. The orientation is defined relative to this fixed "local frame", and the Euler angles are rotations around these fixed XYZ axes.  Pose orientation is therefore undefined at the poles. This means that a photo sphere with angles (0, 0, 0) will be oriented such that the center pixel faces due north with the equator of the photo sphere parallel with the earth’s surface.

The Euler angles provide a mapping from points in the (rotated) "photo sphere frame" to points in the (fixed) "local frame":
 
A rotation matrix is constructed from the Euler angles as follows (it is important to preserve this ordering):

R = R_Z(-heading) * R_X(pitch) * R_Y(roll)

where: R_*(t) is a right-handed rotation around the named axis:

    R_Z(angle) = [ cos(angle), -sin(angle),  0
                   sin(angle),  cos(angle),  0
                   0,       0,  1 ]
 
    R_X(angle) = [ 1,       0,      0,
                   0,  cos(angle), -sin(angle),
                   0,  sin(angle),  cos(angle) ]
 
    R_Y(angle) = [ cos(angle),  0,  sin(angle),
                   0,  1,       0,
                   -sin(angle),  0,  cos(angle) ]

and where: Z = Up, X = East, Y = North.

It is important to preserve this ordering:

R = R_Z(-heading) * R_X(pitch) * R_Y(roll)

as rotations are not commutative.

Note that the heading angle is the same as a standard compass heading.

References

Adobe XMP standard: http://www.adobe.com/devnet/xmp.html