How to Use the Hough Transform for Line Detection in Images: A Step-by-Step Guide with Code Examples using OpenCV [C++]

Briefly, the Hough transform is a technique that is exploited to extract simple shapes out of images. By simple shapes, we mean forms that can be represented with few parameters. For instance, to mathematically describe a circle, we only need access to the radius r and the center’s coordinates (x, y). Regarding lines, which are relevant in our case, these two required parameters become the intercept b and the slope a. Moreover, it is possible to generalize this technique to mathematically describe other geometric forms, such as ellipses. To initiate the search for lines by the Hough transform, we better understand the principle of this technique beforehand.

How to Use the Hough Transform for Line Detection in Images: A Step-by-Step Guide with Code Examples using OpenCV [C++]

As the name suggests, it is a mere mathematical transformation between different coordinate systems. To summarize, our input is the edge image that has already been calculated using the Canny edge detector, which leads to our input being a 2D array containing coordinates of lines. We know that a line is represented in the image coordinate system by the following equation:

y = ax + b 

In the Hough space, which is a 2D space, we can represent a line as a point with (a_0 , b_0 ) being the coordinates, the slope equaling the x-axis, and the intercept b equaling the y-axis. On the other hand, a point with (x_i , y_i ) being the coordinates has an infinite number of possible lines, as shown in the previous figure, that can go through it in the image coordinate system. This signifies that a point in the image coordinate system is a line
in the Hough 2D system, which can be described with the following equation:

b = ax_i + y_i

It is worth noting that the already mentioned equation has a limit of use, which has to do with vertical lines, as they have an infinite slope . That is why searching for another mathematical alternative to bypass such a limitation is convenient. In our particular case, we will represent the line by another one where both of them are
perpendicular and pass through the origin of the coordinate system. We will utilize the same alternative to remap edge points, yet we will also shift from having a straight line in the Hough space to a non-straight one in the form of a cos or sin curve. This new polar representation, as shown  in the figure below, can be described by the equation below:

ρ = x.cos(θ) + y.sin(θ),

where θ represents the perpendicular line’s argument, whereas ρ represents its length.

After transforming all edge points into Hough parameters (ρ,θ) that are stored inside an array, also labeled an accumulator, its corresponding cells get incremented every time sin or cos curves intersect with one another. Soon after, we look for local maximums based on a given threshold value. For instance, peaks are highly probable candidates to be lines on the edge image. We can easily implement the whole Hough line transform and obtain the output line coordinates using the OpenCV function HoughLinesP() Similar to edge-based feature extraction, the Hough line transform is a technique with extreme sensitivity to threshold values. 3 key values must be meticulously estimated:
• The minimum number of points that can form a line. Lines with less than this exact value are thereby discarded.
• The maximum gap between two points that are considered in the same line.
• The minimum number of intersections, to considerate it as evidence of a straight
line presence.

Example [C++]

// Load an Input Image
Mat image = imread('picture.jpg', IMREAD_COLOR);

// Converting the Input Image to  to grayscale
Mat grayscale = cvtColor(image, COLOR_BGR2GRAY);

// Implementing Canny Edge Detector to find Edges
Mat edges;
Canny(grayscale, edges, 40, 100);

// Implementing Hough Line Transform
vector<Vec4i> lines;
HoughLinesP(edges, lines, 1, CV_PI/180, 50, 10, 20);

// Drawing the detected lines
for (size_t i=0; i<lines.size(); i++) {
    Vec4i l = lines[i];
    line(src, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(255, 0, 0), 3, LINE_AA);

// Show the image with final results
imshow("Result Image", image);