Last active
April 5, 2025 20:41
-
-
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
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
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] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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