Search code examples
pythonopencvimage-segmentationwatershedmathematical-morphology

Trying to improve my road segmentation program in OpenCV


I am trying to make a program that is capable of identifying a road in a scene and proceeded to using morphological filtering and the watershed algorithm. However the program produces either mediocre or bad results. It seems to do okay (not good enough through) if the road takes up most of the scene. However in other pictures, it turns out that the sky gets segmented instead (watershed with the clouds).

enter image description here

enter image description here

enter image description here

enter image description here

I tried to see if I can preform more image processing to improve the results, but this is the best I have so far and don't know how to move forward to improve my program.

How can I improve my program?

Code:

import numpy as np
import cv2
from matplotlib import pyplot as plt
import imutils

def invert_img(img):
    img = (255-img)
    return img


#img = cv2.imread('images/coins_clustered.jpg')
img = cv2.imread('images/road_4.jpg')
img = imutils.resize(img, height = 300)

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

thresh = invert_img(thresh)

# noise removal
kernel = np.ones((3,3), np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 4)

# sure background area
sure_bg = cv2.dilate(opening,kernel,iterations=3)

#sure_bg = cv2.morphologyEx(sure_bg, cv2.MORPH_TOPHAT, kernel)

# Finding sure foreground area
dist_transform = cv2.distanceTransform(opening, cv2.DIST_L2, 5)
ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)

# Finding unknown region
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg,sure_fg)

# Marker labelling
ret, markers = cv2.connectedComponents(sure_fg)

# Add one to all labels so that sure background is not 0, but 1
markers = markers+1

# Now, mark the region of unknown with zero
markers[unknown==255] = 0
'''
imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
imgray = cv2.GaussianBlur(imgray, (5, 5), 0)
img = cv2.Canny(imgray,200,500)
'''
markers = cv2.watershed(img,markers)
img[markers == -1] = [255,0,0]


cv2.imshow('background',sure_bg)
cv2.imshow('foreground',sure_fg)
cv2.imshow('threshold',thresh)
cv2.imshow('result',img)
cv2.waitKey(0)

Solution

  • For start, segmentation problems are hard. The more general you want the solution to be, the more hard it gets. Road segemntation is a well-known problem, and i'm sure you can find many papers which tackle this issue from various directions.

    Something that helps me get ideas for computer vision problems is trying to think what makes it so easy for me to detect it and so hard for computer.

    For example, let's look on the road on your images. What makes it unique from the background?

    1. Distinct gray color.
    2. Always have 2 shoulders lines in white color
    3. Always on the bottom section of the image
    4. Always have a seperation line in the middle (yellow/white)
    5. Pretty smooth
    6. Wider on the bottom and vanishing into horizon.

    Now, after we have found some unique features, we need to find ways to quantify them, so it will be obvious to the algorithm as it is obvious to us.

    1. Work on the RGB (or even better - HSV) image, don't convert it to gray on the beginning and lose all the color data. Look for gray area!
    2. Again, let's find white regions (inside gray ones). You can try do edge detection in the specific orientation of the shoulders line. You are looking for line that takes about half of the height of the image. etc...
    3. Lets delete the upper half of the image. It is hardly that you ever have there a road, and you will get rid from a lot of noise in your algorithm.
    4. see 2...
    5. Lets check the local standard deviation, or some other smoothness feature.
    6. If we found some shape, lets check if it fits what we expect.

    I know these are just ideas and I don't claim they are easy to implement, but if you want to improve your algorithm you must give it more "knowledge", just as you have.