I need help to get the real "start" and "end" points where a line is drawn in the image matrix. In the example below, a detected line is shown using y0 and y1.
import numpy as np
from skimage.transform import hough_line, hough_line_peaks
from skimage.feature import canny
from skimage import data
import matplotlib.pyplot as plt
from matplotlib import cm
# Constructing test image
image = np.zeros((200, 200))
idx = np.arange(0, 200)
image[idx, idx//2] = 255
imgOriginal = image.copy()
# Classic straight-line Hough transform
# Set a precision of 0.5 degree.
tested_angles = np.linspace(-np.pi / 2, np.pi / 2, 360)
h, theta, d = hough_line(image, theta=tested_angles)
# Generating figure 1
fig, axes = plt.subplots(1, 3, figsize=(15, 6))
ax = axes.ravel()
ax[0].imshow(image, cmap=cm.gray)
ax[0].set_title('Input image')
ax[0].set_axis_off()
ax[1].imshow(np.log(1 + h),
extent=[np.rad2deg(theta[-1]), np.rad2deg(theta[0]), d[-1], d[0]],
cmap=cm.gray, aspect=1/1.5)
ax[1].set_title('Hough transform')
ax[1].set_xlabel('Angles (degrees)')
ax[1].set_ylabel('Distance (pixels)')
ax[1].axis('image')
ax[2].imshow(image, cmap=cm.gray)
origin = np.array((0, image.shape[1]))
for _, angle, dist in zip(*hough_line_peaks(h, theta, d)):
y0, y1 = (dist - origin * np.cos(angle)) / np.sin(angle)
print('y0 = {} y1 = {}'.format(y0, y1))
ax[2].plot(origin, (y0, y1), '-r')
ax[2].set_xlim(origin)
ax[2].set_ylim((image.shape[0], 0))
ax[2].set_axis_off()
ax[2].set_title('Detected lines')
plt.tight_layout()
plt.show()
This code results in:
What I want is to get the following points in the real image matrix:
Which is likely to be (0,0) and (199, 100)
In summary, I want to transform y0 and y1 into real points in my numpy matrix.
Your problem is to find the point of intersection between two lines essentially. One is your given line and the other is the line defined by the edge of the image.
That can be done as explained here. I am borrowing the code in the first answer. Define these functions -
def line_intersection(line1, line2):
xdiff = (line1[0][0] - line1[1][0], line2[0][0] - line2[1][0])
ydiff = (line1[0][1] - line1[1][1], line2[0][1] - line2[1][1])
def det(a, b):
return a[0] * b[1] - a[1] * b[0]
div = det(xdiff, ydiff)
if div == 0:
raise Exception('lines do not intersect')
d = (det(*line1), det(*line2))
x = det(d, xdiff) / div
y = det(d, ydiff) / div
return x, y
Change your loop as follows -
for _, angle, dist in zip(*hough_line_peaks(h, theta, d)):
y0, y1 = (dist - origin * np.cos(angle)) / np.sin(angle)
print('y0 = {} y1 = {}'.format(y0, y1))
ax[2].plot(origin, (y0, y1), '-r')
l1 = ((origin[0], y0), (origin[1], y1))
l2 = ((0, 200), (200, 200))
print(line_intersection(l1, l2))
This is obviously assuming that the line of interest always intersects with the lower edge of the image. If the line intersects with the right edge, l2
will have to be modified accordingly. In practice, I would suggest finding the intersect with the two edges and picking the "closest" intersect.
This also assumes that the the line of interest always starts from the top left corner of the image (as you have defined your problem) . If that's not the case, you would need to do this for all four edges of the image and pick the first two intersects.