2
$\begingroup$

I am trying to extract building footprints from satellite images. Using a series of morphological operations i.e erosion and opening by reconstruction, I'm able to obtain the footprints, albeit with a lot of noise. Please refer the image below:

Footprints extracted

As you can see, there are some 'bridges' left between the buildings, and I'm not being able to remove them with opening operations. There are also many holes inside the footprints. I'd love any inputs on how I can improve my result.

P.S I am working on this using openCV and scikit-image on python.

Here's the original image if anyone needs it:

Original Image

$\endgroup$

1 Answer 1

2
$\begingroup$

There are two things that make this image particularly difficult to segment using thresholding or a sequence of morphological operations:

  • Illumination - some parts of the streets are hit by more sun light than others, hence confused as a foreground (the things you call "bridges").
  • Inhomogeneous foreground - the rooftop of a building is not necessarily one color (take for example the most top-left building), hence the "holes" you observe in the footprint.

I managed to get somewhat better results using region-based segmentation and based my solution on this example. Note that I am using SK-image but you should not have problem converting the code to OpenCV as they support the same functions. First, I load and grayscale the image:

img = imread("gfy4e.jpg")
img = rgb2gray(img) * 255

The reason I multiply the grayscaled image by 255 is because it makes the image histogram more readable. enter image description here Since I used the Watershed algorithm, which requires an elevation map and markers, these are the next things I obtained:

elevation_map = sobel(img)
t = threshold_otsu(img)

markers = np.zeros_like(img)
markers[img < t] = 1
markers[img > t] = 2

Then I apply the Watershed algorithm and fill holes in the resulting image like so:

segmented = watershed(elevation_map, markers)
segmented = binary_fill_holes(segmented - 1)

enter image description here

The noise which remained across the streets I removed by applying an closing operation:

segmented = area_opening(segmented, area_threshold=256, connectivity=1)

enter image description here

You can play around with the hyper-parameters of the functions if the final result does not fully satisfy you. You can also look up Machine/Deep learning approaches towards segmentation as they might be able to give you a better result across wider range of images. Here is the complete code (without the plotting bits):

# Imports:
import numpy as np
from skimage.io import imread
from skimage.color import rgb2gray
from skimage.filters import threshold_otsu, sobel
from skimage.segmentation import watershed
from scipy.ndimage import binary_fill_holes
from skimage.morphology import area_opening

# Solution:
img = imread("gfy4e.jpg")
img = rgb2gray(img) * 255

elevation_map = sobel(img)
t = threshold_otsu(img)

markers = np.zeros_like(img)
markers[img < t] = 1
markers[img > t] = 2

segmented = watershed(elevation_map, markers)
segmented = binary_fill_holes(segmented - 1)

segmented = area_opening(segmented, area_threshold=256, connectivity=1)    
$\endgroup$

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.