skylibs
                                
                                
                                
                                    skylibs copied to clipboard
                            
                            
                            
                        Python library to handle 360° environment maps
skylibs
Tools used for LDR/HDR environment map (IBL) handling, conversion and I/O.
Install & Develop
Install using:
pip install --upgrade skylibs
To develop skylibs, clone the repository and execute python setup.py develop
OpenEXR & Spherical harmonics
To read and save exr files, install the following dependencies (works on win/mac/linux):
conda install -c conda-forge openexr-python openexr
Spherical Harmonics
To use the spherical harmonics functionalities, install the following dependency (works on mac/linux):
conda install -c conda-forge pyshtools
envmap
Example usage:
from envmap import EnvironmentMap
e = EnvironmentMap('envmap.exr', 'latlong')
e_angular = e.copy().convertTo('angular')
e_angular_sa = e_angular.solidAngles()
envmap.EnvironmentMap Environment map class. Converts easily between those formats:
- latlong (equirectangular)
 - angular
 - sphere
 - cube
 - skyangular
 - skylatlong
 
Coordinates system
Skylibs employs the following right-handed coordinates system: +X = right, +Y = up, +z = towards the camera. Here is its latitude-longitude map (see code below):

Available methods:
.copy(): deepcopy the instance..solidAngles(): provides the solid angle for each pixel of the current representation..convertTo(targetFormat): convert to thetargetFormat..rotate(rotation): rotate the environment map using a Direction Cosine Matrix (DCM)..resize(targetHeight): resize the environment map. Down-scaling will use energy-preserving interpolation (best results with integer downscales), which may introduce aliasing..toIntensity(mode, colorspace): convert to grayscale..getHemisphere(normal): returns a mask of the hemisphere visible from a surface withnormal..setHemisphereValue(normal, value): sets all pixels visible from a surface withnormaltovalue..getMeanLightVectors(normals): compute the mean light vector of the environment map for the given normals..project(vfov, rotation_matrix, ar, resolution, projection, mode): Extract a rectified image from the panorama, simulating a camera with field-of-viewvfov, extrinsicsrotation_matrix, aspect ratioar,resolution..embed(self, vfov, rotation_matrix, image): inverse ofproject, embeds an image in the environment map..imageCoordinates(): returns the (u, v) coordinates at each pixel center..worldCoordinates(): returns the (x, y, z, valid) world coordinates for each pixel center, with maskvalid(anything outside this mask does not project to the world)..world2image(x, y, z): returns the (u, v) coordinates of the vector (x, y, z). Pixel coordinates can be obtained withfloor(u)andfloor(v)..image2world(u, v): returns the (x, y, z) coordinates of the coordinates (u, v)..interpolate(u, v, valid): interpolates the envmap to coordinates (u, v) masked with valid.
Projection, cropping, simulating a camera
To perform a crop from pano.jpg:
import numpy as np
from imageio import imread, imsave
from envmap import EnvironmentMap, rotation_matrix
e = EnvironmentMap('pano.jpg', 'latlong')
dcm = rotation_matrix(azimuth=np.pi/6,
                      elevation=np.pi/8,
                      roll=np.pi/12)
crop = e.project(vfov=85., # degrees
                 rotation_matrix=dcm,
                 ar=4./3.,
                 resolution=(640, 480),
                 projection="perspective",
                 mode="normal")
crop = np.clip(255.*crop, 0, 255).astype('uint8')
imsave("crop.jpg", crop, quality=90)
hdrio
imread and imwrite/imsave supporting the folloring formats:
- exr (ezexr)
 - cr2, nef, raw (dcraw)
 - hdr, pic (custom, beta)
 - tiff (tifffile)
 - All the formats supported by 
imageio 
ezexr
Internal exr reader and writer, relies on python-openexr.
tools3d
- 
getMaskDerivatives(mask): creates the dx+dy from a binarymask. - 
NfromZ: derivates the normals from a depth mapsurf. - 
ZfromN: Integrates a depth map from a normal mapnormals. - 
display.plotDepth: Creates a 3-subplot figure that shows the depth mapZand two side views. - 
spharm.SphericalHarmonicSpherical Harmonic Transform (usespyshtools).Example usage of
spharm:from envmap import EnvironmentMap from tools3d import spharm e = EnvironmentMap('envmap.exr', 'latlong') sh = spharm.SphericalHarmonic(e) print(sh.coeffs) reconstruction = sh.reconstruct(height=64) - 
warping_operator.warpEnvironmentMap: The warping operator of Gardner et al., 2017. See documentation here. 
hdrtools
Tonemapping using pfstools.
Changelog
- 0.7.4: Fixed tools3d.spharm compatibility with latest pyshtools.
 - 0.7.3: Added vMF-based envmap blur functionality. 
ezexrdoes not print the number of channels on stdout. - 0.7.2: 
ezexr.imwrite()now orders correctly channels when > 10 are used. - 0.7.1: Added 
sunFromPySolar(Thank Ian!) and support for alpha values and imageio v3 in ezexr(thanks Hong-Xing!). - 0.7.0: Fixed 
.setHemisphereValue(), added mode to.toIntensity(), fixed angular and sphere projections for normals [0, 0, ±1], added.getHemisphere(normal). - 0.6.8: Fixed resizing to be energy-preserving when downscaling; fixed conversion that shifted the envmap by half a pixel
 - 0.6.7: Fixed image envmap embedding to fit the projection coordinates; fixed crash in imwrite with specific channel names
 - 0.6.6: Fixed aspect ratio when embedding
 - 0.6.5: Added envmap embed feature
 - 0.6.4: Removed 
pyshtoolsas mandatory dependency - 0.6.3: Removed custom OpenEXR bindings (can be easily installed using conda)
 - 0.6.2: Removed 
rotlibdependency - 0.6.1: Aspect ratio in 
project()now in pixels - 0.6: Updated the transport matrix Blender plugin to 2.8+
 
Roadmap
- Improved display for environment maps (change intensity with keystroke/button)
 - Standalone 
ezexron all platforms (investigatepyexr) - add 
worldCoordinates()output in spherical coordinates instead of (x, y, z) - Add assert that data is float32 in convertTo/resize (internal bugs in scipy interpolation)
 
Code for the coordinates system figure
import numpy as np
from matplotlib import pyplot as plt
from envmap import EnvironmentMap
sz = 1024
e = EnvironmentMap(sz, 'cube', channels=3)
e.data[:sz//4,:,:] = [0, 1, 0]                   # +Y
e.data[sz//4:int(0.5*sz),:,:] = [1, 0, 1]        # -Y
e.data[:,int(0.5*sz):,:] = [1, 0, 0]             # +X
e.data[:,:int(0.25*sz),:] = [0, 1, 1]            # -X
e.data[int(3/4*sz):,:,:] = [0, 0, 1]             # +Z
e.data[int(0.5*sz):int(3/4*sz):,:,:] = [1, 1, 0] # -Z
e.convertTo('latlong')
def getCoords(normal):
    u, v = e.world2image(*normal)
    return [u*e.data.shape[1], v*e.data.shape[0]]
plt.imshow(e.data)
plt.text(*(getCoords([1, 0, 0]) + ["+X"]))
plt.text(*(getCoords([-1, 0, 0]) + ["-X"]))
plt.text(*(getCoords([0, 1, 0]) + ["+Y"]))
plt.text(*(getCoords([0, -1, 0]) + ["-Y"]))
plt.text(*(getCoords([0, 0, 1]) + ["+Z"]))
plt.text(*(getCoords([0, 0, -1]) + ["-Z"]))
plt.axis('off')
plt.savefig('coordinates.png', bbox_inches="tight", dpi=200)
plt.show()