OpenCV for object segmentation of drains from LIDAR

Peterfitchcsiro
4 min readMar 19, 2020

--

OpenCV has been used for a number of object segmentation tasks, usually for common objects, but also some geographic tasks like segmenting lakes. This article describes how it can be used to identify agricultural drains on LIDAR DEM’s.

Below is an example of one of the LIDAR tiles.

The drains can be clearly seen in the LIDAR image, so shouldn't be too hard….

The Data

The data I am using is 1m LIDAR tiles, with an image size of 1001x1001 pixels, so a tile represents rougly 1 square km, with a pixel around 1m. LIDAR is stored as a GeoTiff, with projection information, and height stored as 32bit floating point values.

The Approach

OpenCV comes with some nice functionality and lots of articles on the web, to get you going. The approach I have taken is based on knowing that drains are typically straight lines, and so is suitable for OpenCV Canny edge detection followed by Hough line transform to connect line segments.

Usually with Canny edge detection the image is smoothed with a gaussian filter, with my data and the small drains/lines to detect, I haven’t done that. If you do want to do that use the OpenCV gaussian blur with a 3x3 or 5x5 kernel.

As the drains are the lowest point in the DEM, to make it suitable for Canny detection, the image is inverted, then scaled and converted to integer data. There are 2 values passed into the Canny algorithm, minVal and maxVal. If the edge is above the maxVal, it is considered as “sure-edge”, and if below minVal, it is discarded. If the edge is between the values and connected to an edge it is retained, if not it is discarded. I ran a few experiments on selecting max and min values, and Canny wasnt too sensitive and max values. I found a maxValue between 190–220 worked well, with min Value not to sensitive all and settled on 50. For more information see here. Code for those operations is below. Note the first line to open the image. As the image is a floating point GeoTiff with projection information, I use the IMREAD__LOAD_GDAL flag which uses gdal to read the file. This requires you have gdal loaded on your system.

import cv2
import numpy as np
#read image
image = cv2.imread('lidar_tile.tif'], cv2.IMREAD_LOAD_GDAL)

#invert image
invImg = np.full(image.shape, image.max()) - image

#Scale and convert to integer
scale = 255 / (np.floor(invImg.max()) - np.floor(invImg.min()))
imgScaled = (invImg - invImg.min()) * scale

imgInt= np.uint8(imgScaled)

edges = cv2.Canny(imgInt, 50,220)

Once the edges have been defined, use the Hough Transform to connect line segments. The parameters have been selected a little by trial and error, but also by know that a typical drain segment is great than 10m.

#define constants for Hough Transform
rho = 3 # distance resolution in pixels of the Hough grid
theta = np.pi / 180 # angular resolution of the Hough grid
threshold = 30 # minimum number of votes
min_line_length = 10 # minimum number of pixels making up a line
max_line_gap = 10 # maximum gap in pixels between connectable line segments


# Run Hough on edges
# Output "lines" is an array containing endpoints of detected line segments
lines = cv2.HoughLinesP(edges, rho, theta, threshold, np.array([]),
min_line_length, max_line_gap)

Lastly, draw the lines on the image and save the file. Code for doing that is below .

colorImage = cv2.applyColorMap(imgInt,cv2.COLORMAP_BONE)for line in lines:
for x1,y1,x2,y2 in line:
cv2.line(colorImageLines,(x1,y1),(x2,y2),(255,0,255),2)
cv2.imwrite('drainagelines.png',colorImageLines)

Above you can see that the gray scale image is converted to color. This is only so the pink lines can be drawn as seen below. You can also see above how to use the imwrite method to save the image. There are a few connections made by the Hough transform where it has linked segments that shouldnt be linked, with a little more optimisation, these could be reduced.

Conclusion

In this article you have seen how OpenCV can be used to identify drains in LIDAR data. I have shown how to use OPenCV imread, imwrite, Canny detection and Hough transform methods. Its done an ok job.

The reason for this work was to identify drains so they could be included in a stream network. Whilst this approach finds the edges, it doesnt fill in the channels and the results are interesting but not really useful. Not super useful to me, but hopefully of interest and use to you.

I have moved to look at some of the deep learning aproaches for object segmentation. Next time I will share some of the work I have done using uNet to identify and segment the drains.

--

--

Peterfitchcsiro

Peter is a data scientist with interests in machine learning and environmental measurement.