2

I'm currently trying to develop a LAStools specific routine, setting all the parameters for lasheight then using the output of that to run lasclassify. The closest thing I've found to being able to write this in Python is in Sending arguments to LAStools function from Python script not working

In the above post I'm a bit curious where the input and output .las files are. Also, not exactly sure how that Bat functionality is working. Does anyone have an example of a complete script they would be willing to post?

Here's what I have so far, I can't seem to get it to work though. I think it has something to do with the environments setting. I'm running the exact text from the bat file in the command line and it's working now that I updated the default PATH to where my LAStools bin folder is.

import os, random, sys, subprocess

input_path = "D:\Working_D\LAStools_scratch\input\\*.laz"
height_path = "D:\Working_D\LAStools_scratch\height"
arg_cores = "-cores 16"

directory = r'D:\Working_D\scripts\BatchFiles'
with open(os.path.join(directory, 'BatchTemp.bat'), 'w') as OPATH:
      OPATH.writelines(["lasheight ",
                        "-i {0} ".format('"' + input_path + '"'),
                        "{0} ".format(arg_cores),
                        "{0} ".format("-odir"),
                        "{0} ".format('"' + height_path + '"'),
                        "{0} ".format("-olaz"),
                        "\n "])

BatFile = 'D:\Working_D\scripts\BatchFiles\BatchTemp.bat'

proc=subprocess.Popen(BatFile,stdout=subprocess.PIPE,stderr=subprocess.PIPE,shell=True)
output,error=proc.communicate()

os.remove(BatFile)

print 'process complete.'

SOLVED: I was running this in IDLE and it would not work but running the Python script through the cmd window (e.g. D:\Working_D\scripts\lasheight_v2.py) and it worked!

8
  • I have one but it's quite long (644 lines). I use subprocess.Popen to call lastools with all the args in a list, if that's the bit you're interested in I can post that. Can you edit your question with some of your code so I can tell where to start from? Commented Jul 6, 2017 at 0:55
  • Hi Michael, thanks for the quick response. I'm just trying to isolate and run lasheight with the above code but it isn't panning out just yet.
    – noah ahles
    Commented Jul 6, 2017 at 19:39
  • Can you paste the contents of the batch file? You will need to comment out the os.remove line to keep the batch file. The path to the batch file needs an 'r' in front of it or use BatFile = os.path.join(directory, 'BatchTemp.bat'). Also, can you open a cmd window, drag the bat file into it and see what errors it throws up, I have a suspicion you will get 'lasheight' is not recognized as an internal or external command as an error message but just in case it's something different it's best to know for sure than to assume. Commented Jul 6, 2017 at 20:46
  • lasheight -i "D:\Working_D\LAStools_scratch\input*.laz" -cores 16 -odir "D:\Working_D\LAStools_scratch\height" -olaz When I run the bat file by double clicking on it or if I copy, paste the above into my cmd window or drag the .bat file in it works perfectly without any errors.
    – noah ahles
    Commented Jul 6, 2017 at 21:18
  • Then it's likely to be the dodgy path to the bat file from what I can see here. If you change proc.communicate() to proc.wait() you should see any error messages, along with other progress text, if you're executing this python script from a cmd window. If you write to your batch file SET (nothing else!) there will be a list of system variables, this could help diagnose if there's a path issue. Commented Jul 6, 2017 at 21:24

1 Answer 1

2

Now that your question is open again I can provide some code. In your linked answer I wrote a batch file then called the batch file, that works, but to call directly from python:

lasheight     = r"c:\lastools\bin\lasheight.exe" # earlier in the script
for ThisXStep in XStep:
    for ThisYStep in YStep:
        # for each sub block identify the matching list
        InList = os.path.join(RasterTempDir,"LHInputList-{}-{}.txt".format(ThisXStep,ThisYStep))

        SInfo = os.stat(InList) # check the file size for the list. It is possible that some blocks are empty
        if SInfo.st_size > 0:
            print("Processing {}".format(InList))
            LASHeight = [lasheight,
                        '-replace_z',
                        '-drop_below',dropMin,
                        '-lof',InList,
                        '-drop_above',dropMax,
                        '-odir',ClampedFolder]            # the command I'm using for LASheight in a Popen list

            pcs =subprocess.Popen(LASHeight)              # start this process
            pcs.wait()                                    # and wait for it to finish

This is a part of a much bigger script; it contains just the information pertinent to your question. Previously in this script I wrote some text files (InList) which contain a list of the LAS files for a given block.

4
  • Awesome, thanks for putting this up. Seeing all of the various ways that this can be accomplished has been really helpful. I'm excited to expand this script into running lasheight into lasclassify, then blast2dem both on separate drives to maximize efficiency.
    – noah ahles
    Commented Jul 6, 2017 at 22:27
  • blast2dem comes later in the script, in exactly the same way, the reason for separating into blocks is that blast2dem has a maximum number of input points groups.google.com/forum/#!topic/lastools/jeo-vtYK58k and that's what makes the script 644 lines instead of < 100. Commented Jul 6, 2017 at 22:48
  • Interesting, our workflow utilizes lastile before running blast2dem to make the tile inputs a bit smaller. we use the buffer function (roughly half the size of the tile) within lastile so that there are no edge effects upon mosaicking the output.
    – noah ahles
    Commented Jul 7, 2017 at 14:20
  • That is a solid workflow for small areas. The areas I was converting were many square kilometres, as 1k x 1k tiles @ 8ppsm. The first part was to calculate the extent, divide (dice) the extent and then find all files with partial or complete overlap. The second part was to count the class 2 and 8 records for a given tile and if more than 2e31 records quarter the extent until all 'boxes' had less than 2e31 ground records. I didn't need to merge and retile the existing tiles which saved some temp space and processing time. Commented Jul 9, 2017 at 21:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.