I'm trying to detect lines in an irregular image using a relatively low threshold
of 5. The result I get is the following:
where red lines are the computed lines. However, I was expecting the yellow lines to satisfy the parameters as well. Does anyone know why the yellow lines aren't detected? Here's my code:
# img
rho = 1 # distance resolution in pixels of the Hough grid
theta = np.pi / 180 # angular resolution in radians of the Hough grid
threshold = 5 # minimum number of votes (intersections in Hough grid cell)
min_line_length = 200 # minimum number of pixels making up a line
max_line_gap = 500 # maximum gap in pixels between connectable line segments
low_threshold = 50
high_threshold = 150
edge_image = img.copy()
edge_image = cv2.GaussianBlur(edge_image, (3, 3), 1)
edges = cv2.Canny(edge_image, low_threshold, high_threshold)
line_image = np.copy(edges) # creating a blank to draw lines on
line_image = cv2.cvtColor(line_image, cv2.COLOR_GRAY2BGR)
lines = cv2.HoughLinesP(img, rho, theta, threshold, np.array([]),
min_line_length, max_line_gap)
for line in lines:
for x1,y1,x2,y2 in line:
cv2.line(line_image,(x1,y1),(x2,y2),(0,0,255),1)
There are few issues with the posted solution:
HoughLinesP
is applied on img
: lines = cv2.HoughLinesP(img...
, when supposed to be applied on edges
.GaussianBlur
and Canny
on an image with such "fine lines", is not recommender (the result is that each line is replicated twice).dilate
(dilate with 2x2 kernel).min_line_length = 200
is too long - the length of the short yellow line is about 120 pixels.max_line_gap = 500
for example makes no sense).Code sample:
import cv2
import numpy as np
img = cv2.imread('input_image_with_lines.png') # Read image as BGR
# Apply threshold to each color channel for converting all the non-black pixels to white (needed to the usage of automatic threshold instead of manual threshold).
b_thres = cv2.threshold(img[:, :, 0], 0, 255, cv2.THRESH_OTSU)[1] # Apply automatic threshold to the blue channel
g_thres = cv2.threshold(img[:, :, 1], 0, 255, cv2.THRESH_OTSU)[1] # Apply automatic threshold to the green channel
r_thres = cv2.threshold(img[:, :, 2], 0, 255, cv2.THRESH_OTSU)[1] # Apply automatic threshold to the red channel
thres_image = b_thres | g_thres | r_thres # thres_image is combined threshold images
#dilated_thres_image = cv2.dilate(thres_image, np.array([[0, 1, 0], [1, 1, 1], [0, 1, 0]], np.uint8))
dilated_thres_image = cv2.dilate(thres_image, np.ones((2, 2), np.uint8)) # Dilate thres_image with very small kernel - makes the lines thinker.
# img
rho = 0.5 #1 distance resolution in pixels of the Hough grid
theta = np.pi / 180 # angular resolution in radians of the Hough grid
threshold = 5 # minimum number of votes (intersections in Hough grid cell)
min_line_length = 50 #200 # minimum number of pixels making up a line
max_line_gap = 2 #500 # maximum gap in pixels between connectable line segments
#low_threshold = 50
#high_threshold = 150
#edge_image = img.copy()
#edge_image = cv2.GaussianBlur(edge_image, (3, 3), 1)
#edges = cv2.Canny(edge_image, low_threshold, high_threshold)
#lines = cv2.HoughLinesP(img, rho, theta, threshold, np.array([]),
# min_line_length, max_line_gap)
lines = cv2.HoughLinesP(dilated_thres_image, rho, theta, threshold, None, min_line_length, max_line_gap)
line_image = cv2.cvtColor(dilated_thres_image, cv2.COLOR_GRAY2BGR) # creating a blank to draw lines on
for line in lines:
for x1,y1,x2,y2 in line:
#cv2.line(line_image,(x1,y1),(x2,y2),(0,0,255),1)
cv2.line(line_image, (x1,y1), (x2,y2), (0,255,0), 1)
# Display images for testing
cv2.imshow('img', img)
cv2.imshow('thres_image', thres_image)
cv2.imshow('dilated_thres_image', dilated_thres_image)
cv2.imshow('line_image', line_image)
cv2.waitKey()
cv2.destroyAllWindows()
I realize that the result is not perfect, but we have to consider that Hough-Lines algorithm has its limitations...