Self-driving car: Edge detection
1. Convert image to grayscale
To detect edeges we have to pass the image to black and white
gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
2. Reduce noise
blur = cv2.GaussianBlur(gray,(5,5), 0)
Alternative to GaussianBlur: bilateralFilter keeps the edges sharper.
3. Detect edges: Sobel filter (NOT USED)
The Sobel filter is very commonly used in edge detection and in finding patterns in intensity in an image. Applying a Sobel filter to an image is a way of taking (an approximation) of the derivative of the image in the x or y direction, separately. The operators look as follows.
filtered_image = cv2.filter2D(gray, -1, filters[i])
3. Detect edges: Canny
Canny Edge Detection is a popular edge detection algorithm. It was developed by John F. Canny in 1986. It is a multi-stage algorithm and we will go through each stages.
- Noise Reduction: Since edge detection is susceptible to noise in the image, first step is to remove the noise in the image with a 5x5 Gaussian filter.
- Finding Intensity Gradient of the Image: Smoothened image is then filtered with a Sobel kernel in both horizontal and vertical direction.
- Non-maximum suppression (thinning): Zero out all pixels that are not the maximum along the direction of the gradient (look at 1 pixel on each side)
- Hysteresis Thresholding: This stage decides which are all edges are really edges and which are not. For this, we need two threshold values, minVal and maxVal.
canny_wide = cv2.Canny(gray, 30, 100)
canny_tight = cv2.Canny(gray, 200, 240)
canny = cv2.Canny(blur, 50, 150)
4. Isolate region of interest
############################## Get region of interest mask
height = image.shape[0]
width = image.shape[0]
triangle = np.array([(200, height), (500,250), (1200,height)])
square = np.array([(0,height),(465,320),(475,320),(width,height)])
mask = np.zeros_like(image)
cv2.fillPoly(mask, triangle, 255)############################## Get edges in the mask
road_edges = cv2.bitwise_and(canny, mask)
5. Finding lines: Hough transform
Hough space: A 2D plane where each point represents a line, the x-axis is the slope (m) and the y-axis, the intercept (n).
lines = cv2.HoughLinesP(
image = road_edges, # Input image
rho = 2, # Distance resolution
theta = np.pi/180, # Angle resolution
threshold = 45 # 100 # Min intersections
lines = np.array([]), # Output vector of lines
minLineLength = 40, # Minimum line length
maxLineGap = 100) # 5 # Max gap between line points
Then display the lines
line_image = np.zeros_like(image)
for line in lines:
x1, x2, y1, y2 = line.reshape(4)
cv2.line(line_image, (x1, y1), (x2, y2),
color=(255,0,0), thickness=10)image_with_lines = cv2.addWeighted(line_image, 0.8, image, 1, 1)
6. Average lines
The goal is to have only 2 lines. Note if the slope is negative corresponds to the left side, and a positive slope corresponds to the right side.
Reference
Here is a video that covers all the steps explained before: