Find vanishing point in image (1 point perspective)
%matplotlib inline
import cv2
import numpy as np
import urllib
import matplotlib.pyplot as plt
Get sample image
First download a sample image.
def get_image_from_url(url):
"""https://stackoverflow.com/a/3969809"""
with urllib.request.urlopen(url) as u:
= u.read()
s = np.asarray(bytearray(s), dtype=np.uint8)
arr = cv2.imdecode(arr, -1) # 'Load it as it is'
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
img
return img
= get_image_from_url('https://static.toiimg.com/photo/69928969/cobble.jpg')
img plt.imshow(img)
<matplotlib.image.AxesImage at 0x7fb5ef127670>
Edge detection
We are interested in using the most prominent edges in the image to compute the Hough lines. To find the edges, we use Canny edge detection.
= cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
gray = cv2.Canny(gray, 200, 700)
edges
='gray') plt.imshow(edges, cmap
<matplotlib.image.AxesImage at 0x7fb5ef468e80>
Hough lines from edges
We can use the edges obtained above to compute Hough lines.
= cv2.HoughLines(edges, 1, np.pi/180, 100)
lines = img.copy()
img_lines
# adapted from https://stackoverflow.com/a/60515853
for line in lines:
= line[0]
rho,theta = np.cos(theta)
a = np.sin(theta)
b = a*rho
x0 = b*rho
y0 = int(x0 + 10000*(-b))
x1 = int(y0 + 10000*(a))
y1 = int(x0 - 10000*(-b))
x2 = int(y0 - 10000*(a))
y2 0,255,0),2)
cv2.line(img_lines, (x1,y1),(x2,y2),(
plt.imshow(img_lines)
<matplotlib.image.AxesImage at 0x7fb5da4183a0>
= cv2.HoughLines(edges,
lines 0.85,
/180,
np.pi100,
# min_theta=np.pi/36,
# max_theta=np.pi-np.pi/36
)
= img.copy()
img_lines
= []
segments for line in lines:
= line[0]
rho, theta # skip near-vertical lines
if abs(theta-np.pi/90) < np.pi/9:
continue
= np.cos(theta)
a = np.sin(theta)
b = a*rho
x0 = b*rho
y0
= int(x0 + 10000*(-b))
x1 = int(y0 + 10000*(a))
y1
= int(x0 - 10000*(-b))
x2 = int(y0 - 10000*(a))
y2
segments.append((np.array((x1, y1)),
np.array((x2, y2))))
0,255,0),2)
cv2.line(img_lines, (x1,y1),(x2,y2),(
plt.imshow(img_lines)
<matplotlib.image.AxesImage at 0x7fb5786558b0>
def seg_intersect(s1, s2):
"""https://stackoverflow.com/a/3252222"""
= s1[0] - s1[1]
da = s2[0] - s2[1]
db = s1[0] - s2[0]
dp = perp(da)
dap = np.dot( dap, db)
denom = np.dot( dap, dp )
num return (num / denom.astype(float))*db + s2[0]
def perp(a):
= np.empty_like(a)
b 0] = -a[1]
b[1] = a[0]
b[return b
= np.empty((len(segments), len(segments), 2))
intersections = np.nan
intersections[:] for i, s1 in enumerate(segments):
for j, s2 in enumerate(segments[i:], start=i):
if i != j:
= seg_intersect(s1, s2)
intersections[i,j]
= intersections[~np.isnan(intersections)]
intersections = intersections.reshape((int(len(intersections)/2), 2)).astype(np.int16)
intersections intersections
array([[484, 332],
[522, 314],
[858, 157],
[550, 301],
[513, 318],
[523, 314],
[525, 313],
[477, 335],
[525, 307],
[776, 156],
[170, 520],
[509, 317],
[517, 312],
[524, 308],
[477, 336],
[587, 153],
[520, 318],
[519, 321],
[522, 314],
[524, 309],
[479, 422],
[800, 156],
[ 58, 144],
[103, 144],
[493, 151],
[474, 151],
[517, 320],
[526, 315],
[525, 315],
[477, 343],
[926, 477],
[527, 323],
[476, 304],
[525, 315],
[476, 295],
[472, 40]], dtype=int16)
= img.copy()
img_points
# show all intersection points
for p in intersections:
0], p[1]), 20, (255,0,0), 5)
cv2.circle(img_points, (p[
# show mean intersection point
= np.mean(intersections, axis=0).astype(np.int16)
vp_hat 0], vp_hat[1]), 20, (0,255,0), 5)
cv2.circle(img_points, (vp_hat[
plt.imshow(img_points)
print(f"Estimated vanishing point coordinates:", vp_hat)
Estimated vanishing point coordinates: [513 285]