16 bit to 8 bit RGB colours with PDAL and Python

Sometimes LAS files have RGB values stored as 16 bit colours. This currently upsets the Potree viewer, and maybe some other things. The following recipe using Python and PDAL ‘eightbitifies’ colours. It also compresses incoming LAS files to LAZ.

PDAL has a neat filters.python option, which passes every incoming point into a python function. Flexible huh?

First, a Python function to scale colours:

import numpy as np

def eightbitify(colour):
    notzero = np.where(colour > 0)
    colour[notzero] = (colour[notzero]/255) - 1
    return colour

def scale_colour(ins,outs):
    outs['Red'] = eightbitify(ins['Red'])
    outs['Green'] = eightbitify(ins['Green'])
    outs['Blue'] = eightbitify(ins['Blue'])
    return True

ins is a numpy array of incoming points from PDALs reader. PDAL dimensions define what’s in there – so here I’ve asked filters.python to read Red, Green, and Blue into numpy arrays to work on. The entire set of data will be loaded up, making python array operations useful and fast (if you have the memory). PDAL’s —stream operator isn’t enabled for filters.python –  if you are memory constrained, think about filters.splitter to make manageable chunks first.  This actually makes sense – PDAL has no way of knowing what you’re going to write into your python function!

Next, construct a JSON pipeline to run the conversion:

 

{
    "pipeline": [
        {
            "type" : "readers.las",
            "filename" : "file.las"
        },
        {
            "type" : "filters.python",
            "script": "/opt/data/scalecolour.py",
            "function": "scale_colour",
            "module": "scalecolour"
        },
        {
            "type" : "writers.las",
            "filename" : "outfile.laz"
        }
    ]
}

 

…and finally invoke PDAL invocation to make it go. Here it’s wrapped in a shell script to process a bunch of data. Highlighted lines show the actual PDAL invocation. I’ll replace the shell script to loop over files with a python function once it’s written.

for f in lasfiles/*.las;
    do
    #echo $f
    fileout=$(basename $f ".las")
    #echo $fileout
    docker run -it -v /set/your/working/path:/opt/data \
                    pdal/pdal pdal \
                    pipeline /opt/data/scale_colour.json \
                    --readers.las.filename=/opt/data/${f} \
                    --writers.las.filename=/opt/data/lasfiles_8bit/${fileout}.laz

    done

 

I ran this using the pdal/pdal:latest docker image:

docker pull pdal/pdal