Skip to content

Instantly share code, notes, and snippets.

@arccoder
Last active March 1, 2024 12:16
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save arccoder/9a73e0b2d8be1a8fd42d6026d3a7a1e1 to your computer and use it in GitHub Desktop.
Save arccoder/9a73e0b2d8be1a8fd42d6026d3a7a1e1 to your computer and use it in GitHub Desktop.
Process the output of cv2.HoughLines from OpenCV using functions that do Polar to Cartesian line conversion, Intersection of Cartesian lines, Line end points on image. https://arccoder.medium.com/process-the-output-of-cv2-houghlines-f43c7546deae
"""
Script contains functions to process the lines in polar coordinate system
returned by the HoughLines function in OpenCV
Line equation from polar to cartesian coordinates
x = rho * cos(theta)
y = rho * sin(theta)
x, y are at a distance of rho from 0,0 at an angle of theta
Therefore,
m = (y - 0) / (x - 0)
Using the values of x, y, and m
b = y - m * x
Python 3.6 was used to compile and test the code.
"""
import numpy as np
def polar2cartesian(rho: float, theta_rad: float, rotate90: bool = False):
"""
Converts line equation from polar to cartesian coordinates
Args:
rho: input line rho
theta_rad: input line theta
rotate90: output line perpendicular to the input line
Returns:
m: slope of the line
For horizontal line: m = 0
For vertical line: m = np.nan
b: intercept when x=0
"""
x = np.cos(theta_rad) * rho
y = np.sin(theta_rad) * rho
m = np.nan
if not np.isclose(x, 0.0):
m = y / x
if rotate90:
if m is np.nan:
m = 0.0
elif np.isclose(m, 0.0):
m = np.nan
else:
m = -1.0 / m
b = 0.0
if m is not np.nan:
b = y - m * x
return m, b
def solve4x(y: float, m: float, b: float):
"""
From y = m * x + b
x = (y - b) / m
"""
if np.isclose(m, 0.0):
return 0.0
if m is np.nan:
return b
return (y - b) / m
def solve4y(x: float, m: float, b: float):
"""
y = m * x + b
"""
if m is np.nan:
return b
return m * x + b
def intersection(m1: float, b1: float, m2: float, b2: float):
# Consider y to be equal and solve for x
# Solve:
# m1 * x + b1 = m2 * x + b2
x = (b2 - b1) / (m1 - m2)
# Use the value of x to calculate y
y = m1 * x + b1
return int(round(x)), int(round(y))
def line_end_points_on_image(rho: float, theta: float, image_shape: tuple):
"""
Returns end points of the line on the end of the image
Args:
rho: input line rho
theta: input line theta
image_shape: shape of the image
Returns:
list: [(x1, y1), (x2, y2)]
"""
m, b = polar2cartesian(rho, theta, True)
end_pts = []
if not np.isclose(m, 0.0):
x = int(0)
y = int(solve4y(x, m, b))
if point_on_image(x, y, image_shape):
end_pts.append((x, y))
x = int(image_shape[1] - 1)
y = int(solve4y(x, m, b))
if point_on_image(x, y, image_shape):
end_pts.append((x, y))
if m is not np.nan:
y = int(0)
x = int(solve4x(y, m, b))
if point_on_image(x, y, image_shape):
end_pts.append((x, y))
y = int(image_shape[0] - 1)
x = int(solve4x(y, m, b))
if point_on_image(x, y, image_shape):
end_pts.append((x, y))
return end_pts
def hough_lines_end_points(lines: np.array, image_shape: tuple):
"""
Returns end points of the lines on the edge of the image
"""
if len(lines.shape) == 3 and \
lines.shape[1] == 1 and lines.shape[2] == 2:
lines = np.squeeze(lines)
end_pts = []
for line in lines:
rho, theta = line
end_pts.append(
line_end_points_on_image(rho, theta, image_shape))
return end_pts
def hough_lines_intersection(lines: np.array, image_shape: tuple):
"""
Returns the intersection points that lie on the image
for all combinations of the lines
"""
if len(lines.shape) == 3 and \
lines.shape[1] == 1 and lines.shape[2] == 2:
lines = np.squeeze(lines)
lines_count = len(lines)
intersect_pts = []
for i in range(lines_count - 1):
for j in range(i + 1, lines_count):
m1, b1 = polar2cartesian(lines[i][0], lines[i][1], True)
m2, b2 = polar2cartesian(lines[j][0], lines[j][1], True)
x, y = intersection(m1, b1, m2, b2)
if point_on_image(x, y, image_shape):
intersect_pts.append([x, y])
return np.array(intersect_pts, dtype=int)
def point_on_image(x: int, y: int, image_shape: tuple):
"""
Returns true is x and y are on the image
"""
return 0 <= y < image_shape[0] and 0 <= x < image_shape[1]
@JohnnyTWA
Copy link

Hello,

I've been trying the code but I get an error thrown on line 155, in this case a divide by 0 in this case m1-m2 is equal to 0 and thus line 81 tries to divide b2-b1 by 0.

The arrays passed to polar2cartesian do contain non-zero numbers and most definitely don't cancel each other out.

I've tried a couple of different images to see if it's me but the received the same response.

@arccoder
Copy link
Author

@JohnnyTWA Did you try adding an epsilon value to the denominator?

@andrea2702
Copy link

Hola, me da este error cuando la función de cyclic_intersection_pts no regresa nada

Traceback (most recent call last):
File "puntos.py", line 83, in
for pts in intersect_pts:
TypeError: 'NoneType' object is not iterable

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment