5

I'm looking for a method which finds the ridges (local maxima) in an image and returns them as an array of ridges ( where a ridge is a vector of points defining the ridge). That is, a method which behaves exactly like findContours (which finds contours and returns them as an array of vectors defining the contours), except for ridges.

Does this exist, and if not how would I acheive this effect? (I'm using the Emgu CV wrapper for OpenCV)

I have this image (it's a bit faint, sorry), obtained using the distance transform from a binary image of a system of roads:

Distance transform of binary image of a road system

I can easily use findContours on the original binary image to get the road outlines as vectors of points. However I am interested in the road centerline. The road centerline is represented by the local maxima the image above.

Obviously, using findContours on this image gives me the road outlines again. I was planning to use non-maxima suppression to take away everything but the centerline, and use findContours on that, but I don't know how to do non-maxima suppression either, hence my question here

Community
  • 1
  • 1
mchristos
  • 1,487
  • 1
  • 9
  • 24
  • How does `findContours` not give you what you want? Do you have examples of what you've tried and how they fail to give you the desired results? – beaker Apr 12 '16 at 15:20
  • Thanks for your comment - please see the new edits. – mchristos Apr 13 '16 at 07:51

1 Answers1

0

You want to do the max suppression along the direction of the gradient of each line.

  1. Calculate the gradient direction.
  2. For each point search for the max value along a line in the direction of the local gradient. 2.1 If the current point is the max mark as one otherwise mark as zero
import cv2
import numpy as np
import math
from matplotlib import pyplot as plt

# Read image
Irgb = cv2.imread('road.png')
I = Irgb[:,:,0]

# Find the gradient direction
sobelx = cv2.Sobel(I,cv2.CV_64F,1,0,ksize=1)
sobely = cv2.Sobel(I,cv2.CV_64F,0,1,ksize=1)

gradDirection = np.zeros(I.shape, np.float64)

for y in range(I.shape[0]):
    for x in range(I.shape[1]):
        gradDirection[y, x] = np.float64(math.atan2(sobely[y,x], sobelx[y,x]))

# Iterate on all points and do max suppression
points = np.nonzero(I)
points = zip(points[0], points[1])
maxSuppresion = np.zeros_like(I)
for point in points:
    y = point[0]
    x = point[1]

    # Look at local line along the point in the grad direction
    direction = gradDirection[y, x]
    pointValues = []
    for l in range(-1,2):
        yLine = int(np.round(y + l * math.sin(direction)))
        xLine = int(np.round(x + l * math.cos(direction)))

        if(yLine < 0 or yLine >= maxSuppresion.shape[0] or xLine < 0 or xLine >= maxSuppresion.shape[1]):
            continue

        pointValues.append(I[yLine,xLine])

    # Find maximum on line
    maxVal = np.max(np.asarray(pointValues))

    # Check if the current point is the max val
    if I[y,x] == maxVal:
        maxSuppresion[y, x] = 1
    else:
        maxSuppresion[y, x] = 0

# Remove small areas
im2, contours, hierarchy = cv2.findContours(maxSuppresion,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_NONE )
minArea = 5
maxSuppresionFilter = np.zeros_like(maxSuppresion)
finalShapes = []
for contour in contours:
    if contour.size > minArea:
        finalShapes.append(contour)

cv2.fillPoly(maxSuppresionFilter, finalShapes, 1)
cv2.imshow('road',maxSuppresionFilter*255)

In the end will get the following image: enter image description here

You can see that there are still problems especially around the intersections where the local maximum suppression suppressed the points next to the center of the intersection. You can try to use morphological operations to overcome those problems.

Amitay Nachmani
  • 3,259
  • 1
  • 18
  • 21