Source code for raytraverse.lightfield.lightplanekd

# -*- coding: utf-8 -*-
# Copyright (c) 2020 Stephen Wasilewski, HSLU and EPFL
# =======================================================================
# 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 scipy.spatial import Voronoi
from scipy.interpolate import LinearNDInterpolator
from shapely.geometry import Polygon

from raytraverse import io, translate
from raytraverse.evaluate import MetricSet
from raytraverse.lightfield.sets import LightPointSet
from raytraverse.lightfield.lightfield import LightField


[docs]class LightPlaneKD(LightField): """collection of lightpoints with KDtree structure for positional query""" @property def data(self): """LightPointSet""" return self._data @ data.setter def data(self, idx): self._data = LightPointSet(self.scene, self.vecs, idx, self.src, self.pm.name) @property def omega(self): """representative area of each point :getter: Returns array of areas :setter: sets areas :type: np.array """ if self._omega is None: self._omega = translate.calc_omega(self.vecs, self.pm) return self._omega @omega.setter def omega(self, oga): """wait to calculate area until needed""" self._omega = None
[docs] def evaluate(self, skyvec, points=None, vm=None, metricclass=MetricSet, metrics=None, mask=True, **kwargs): # qidx are the unique query indices and midx are the mapping indices # to restore full results from the qidx results if points is None: qidx = midx = np.arange(len(self.vecs)) else: ridx, d = self.query(points) if mask: if hasattr(self.pm, "mask"): omask = self.pm.mask self.pm.mask = True ridx = ridx[self.pm.in_view(points, False)] self.pm.mask = omask else: ridx = ridx[self.pm.in_view(points, False)] qidx, midx = np.unique(ridx, return_inverse=True) results = [] for qi in qidx: lp = self.data[qi] vol = lp.evaluate(skyvec, vm=vm) if vm is None: vm = lp.vm results.append(metricclass(*vol, vm, metricset=metrics, **kwargs)()) return np.array(results)[midx]
[docs] def make_image(self, outf, vals, res=1024, interp=False, showsample=False): """make an image from precomputed values for every point in LightPlane Parameters ---------- outf: str the file to write vals: np.array shape (len(self.points),) the values computed for each point res: int, optional image resolution (the largest dimension interp: bool, optional apply linear interpolation, points outside convex hull of results fall back to nearest showsample: bool, optionaal color pixel at sample location red """ img, vecs, mask, _, header = self.pm.init_img(res) if interp: xyp = vecs[mask] interp = LinearNDInterpolator(self.vecs[:, 0:2], vals, fill_value=-1) lum = interp(xyp[:, 0], xyp[:, 1]) neg = lum < 0 i, d = self.query(xyp[neg]) lum[neg] = vals[i] img[mask] = lum else: i, d = self.query(vecs[mask]) img[mask] = vals[i] if showsample: img = np.repeat(img[None, ...], 3, 0) img = self.pm.add_vecs_to_img(img, self.vecs, channels=(1, 0, 0)) io.carray2hdr(img, outf, header) else: io.array2hdr(img, outf, header)
[docs] def direct_view(self, res=512, showsample=True, vm=None, area=False, metricclass=MetricSet, metrics=('avglum',), interp=False): """create a summary image of lightplane showing samples and areas""" if area: outf = self._datadir.replace("/", "_") + f"{self.src}_area.hdr" self.make_image(outf, self.omega, res=res, showsample=showsample, interp=False) if metrics is not None: result = self.evaluate(1, vm=vm, metricclass=metricclass, metrics=metrics, scale=1).T for r, m in zip(result, metrics): outf = self._datadir.replace("/", "_") + f"{self.src}_{m}.hdr" self.make_image(outf, r, res=res, showsample=showsample, interp=interp)