Source code for pylidar.toolbox.visualisation

"""
Functions which can be used to help with the visualisation of the point clouds
"""
# This file is part of PyLidar
# Copyright (C) 2015 John Armston, Pete Bunting, Neil Flood, Sam Gillingham
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

from __future__ import print_function, division

import os
import numpy

havepylidarviewer = True
try:
    import pylidarviewer
except ImportError as pylidarviewerErr:
    havepylidarviewer = False
    
haveMatPlotLib = True
try:
    import matplotlib.colors as clr
    import matplotlib.cm as cm
except ImportError as pltErr:
    haveMatPlotLib = False

[docs]class VisualisationError(Exception): "A Visualisation error has occured"
[docs]def rescaleRGB(r, g, b, bit8=True): """ A function which rescales the RGB arrays to a range of 0-1. Where bit8 is True the arrays will just be divided by 255 otherwise a min-max rescaling will be applied independently to each array. """ if bit8: r = r/255 g = g/255 b = b/255 else: rMin = numpy.min(r) rMax = numpy.max(r) r = (r-rMin)/(rMax-rMin) gMin = numpy.min(g) gMax = numpy.max(g) g = (g-gMin)/(gMax-gMin) bMin = numpy.min(b) bMax = numpy.max(b) b = (b-bMin)/(bMax-bMin) return r,g,b
[docs]def getClassColoursDict(): colourDict = {} colourDict[0] = [1,1,1,1] # Unknown colourDict[1] = [0,0,0,1] # Unclassified colourDict[2] = [0,0,0,1] # Created colourDict[3] = [1,0,0,2] # Ground colourDict[4] = [0,1,0,1] # Low Veg colourDict[5] = [0,0.803921569,0,1] # Med Veg colourDict[6] = [0,0.501960784,0,1] # High Veg colourDict[7] = [0.545098039,0.352941176,0,1] # Building colourDict[8] = [0,0,1,1] # Water colourDict[9] = [0.545098039,0.270588235,0.003921569,1] # Trunk colourDict[10] = [0,0.803921569,0,1] # Foliage colourDict[11] = [0.803921569,0.2,0.2,1] # Branch colourDict[12] = [0.721568627,0.721568627,0.721568627,1] # Wall return colourDict
[docs]def colourByClass(classArr, colourDict=None): """ A function which returns RGB and point size arrays given an input array of numerical classes. Where colourDict has been specified then the default colours (specified in getClassColoursDict()) can be overiden. """ if colourDict == None: colourDict = getClassColoursDict() classPres = numpy.unique(classArr) r = numpy.zeros_like(classArr, dtype=numpy.float) g = numpy.zeros_like(classArr, dtype=numpy.float) b = numpy.zeros_like(classArr, dtype=numpy.float) s = numpy.ones_like(classArr, dtype=numpy.float) for classVal in classPres: r[classArr==classVal] = colourDict[classVal][0] g[classArr==classVal] = colourDict[classVal][1] b[classArr==classVal] = colourDict[classVal][2] s[classArr==classVal] = colourDict[classVal][3] return r,g,b,s
[docs]def createRGB4Param(data, stretch='linear', colourMap='Spectral'): """ A function to take a data column (e.g., intensity) and colour into a set of rgb arrays for visualisation. colourMap is a matplotlib colour map (see http://wiki.scipy.org/Cookbook/Matplotlib/Show_colormaps) for colouring the input data. stretch options are 'linear' or 'stddev' """ # Check matplotlib is available if not haveMatPlotLib: msg = "The matplotlib module is required for this function could not be imported\n\t" + str(pltErr) raise VisualisationError(msg) if stretch == 'stddev': min = numpy.min(data) max = numpy.max(data) stddev = numpy.std(data) mean = numpy.mean(data) minData = mean - (2 * mean) if minData < min: minData = min maxData = mean + (2 * mean) if maxData > max: maxData = max nData = numpy.zeros_like(data, dtype=numpy.float) nData = (data - minData)/(maxData - minData) nData[nData < 0] = 0 nData[nData > 1] = 1 else: norm = clr.Normalize(numpy.min(data), numpy.max(data)) nData = norm(data) my_cmap = cm.get_cmap(colourMap) rgba = my_cmap(nData) r = rgba[:,0:1].flatten() g = rgba[:,1:2].flatten() b = rgba[:,2:3].flatten() return r,g,b
[docs]def displayPointCloud(x, y, z, r, g, b, s): """ Display the point cloud in 3D where arrays (all of the same length) are provided for the X, Y, Z position of the points and then the RGB (range 0-1) values to colour the points and then the point sizes (s). X and Y values are centred around 0,0 and then X, Y, Z values are rescale before display """ # Check if pylidarviewer is available if not havepylidarviewer: msg = "The pylidarviewer module is required for this function could not be imported\n\t" + str(pylidarviewerErr) raise VisualisationError(msg) x = x - numpy.min(x) y = y - numpy.min(y) z = z - numpy.min(z) medianX = numpy.median(x) medianY = numpy.median(y) maxX = numpy.max(x) maxY = numpy.max(y) maxZ = numpy.max(z) maxVal = maxX if maxY > maxVal: maxVal = maxY if maxZ > maxVal: maxVal = maxZ x = (x-medianX)/maxVal y = (y-medianY)/maxVal z = z/maxVal pylidarviewer.DisplayPointCloud(x, y, z, r, g, b, s)