Source code for raytraverse.mapper.viewmapper

# -*- coding: utf-8 -*-

# Copyright (c) 2019 Stephen Wasilewski
# =======================================================================
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# =======================================================================
import numpy as np

from raytraverse.mapper.mapper import Mapper
from raytraverse.mapper.angularmixin import AngularMixin
from raytraverse import translate


[docs]class ViewMapper(AngularMixin, Mapper): """translate between world direction vectors and normalized UV space for a given view angle. pixel projection yields equiangular projection Parameters ---------- dxyz: tuple, optional central view direction viewangle: float, optional if < 180, the horizontal and vertical view angle, if greater, view becomes 360,180 """ def __init__(self, dxyz=(0.0, 1.0, 0.0), viewangle=360.0, name='view', origin=(0, 0, 0), jitterrate=0.5): self._viewangle = viewangle if viewangle == 360: aspect = 2 self._viewangle = 180 sf = (1, 1) bbox = np.stack(((0, 0), (2, 1))) else: aspect = 1 sf = np.array((self._viewangle/180, self._viewangle/180)) bbox = np.stack((.5 - sf/2, .5 + sf/2)) super().__init__(dxyz=dxyz, sf=sf, bbox=bbox, aspect=aspect, name=name, origin=origin, jitterrate=jitterrate) @property def aspect(self): return self._aspect @aspect.setter def aspect(self, a): self.area = 2*np.pi*(1 - np.cos(self.viewangle*np.pi*a/360)) self._aspect = a cl = translate.theta2chord(np.pi/2)/(np.pi/2) va = self.viewangle*np.pi/360 clp = translate.theta2chord(va)/va self._chordfactor = cl/clp @property def dxyz(self): """(float, float, float) central view direction""" return self._dxyz @dxyz.setter def dxyz(self, xyz): """set view parameters""" self._dxyz = translate.norm1(np.asarray(xyz).ravel()[0:3]) self._rmtx = translate.rmtx_yp(self.dxyz) if self.aspect == 2: self._ivm = ViewMapper(-self.dxyz, 180) else: self._ivm = None
[docs] def idx2uv(self, idx, shape, jitter=True): """ Parameters ---------- idx: flattened index shape: the shape to unravel into jitter: bool, optional randomly offset coordinates within grid Returns ------- uv: np.array uv coordinates """ si = np.stack(np.unravel_index(idx, shape)) if jitter and self.jitterrate > 0: rng = ((1 - self.jitterrate)/2, (1 + self.jitterrate)/2) offset = np.random.default_rng().uniform(*rng, si.shape).T else: offset = 0.5 uv = (si.T + offset)/shape[1] return uv