I want to detect lines and curves with OpenCV 3.1, Python 3.4 and Hough transformer. I found a lot of websites but I dont understand how can I programing the formulae. I have this code:
lines = cv2.HoughLines(edges,1,np.pi/180,200)
for rho, theta in lines[0]:
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)
for circle detection if found this:
x = a + r * cos0
y = b + r * sin0
its enough if i change only x0 and y0 to
x0 = a+rho*cos0
y0 = b+rho*sin0
?
Thank you in advance.
Related
There are some implementations of the Hough transform on the internet, only I don't understand a part:
When we find our couple (rho, theta), we have to go back to Cartesian.
To draw the lines here is what is used:
for i in range (len(Liste_p)):
a = cos(Liste_theta[i])
b = sin(Liste_theta[i])
x0 = a*Liste_p[i]
y0 = b*Liste_p[i]
x1 = int(x0 + 1000*(-b)) # x1 stores the rounded off value of (rcos(theta)-1000sin(theta))
y1 = int(y0 + 1000*(a)) # y1 stores the rounded off value of (rsin(theta)+1000cos(theta))
x2 = int(x0 - 1000*(-b)) # x2 stores the rounded off value of (rcos(theta)+1000sin(theta))
y2 = int(y0 - 1000*(a)) # y2 stores the rounded off value of (rsin(theta)-1000cos(theta))
plot([x1,x2],[y1,y2],color="r")
But what is multiplication by 1000?
In fact I do not understand the link with the line that we are supposed to draw
I am trying to implement Hough line transform by myself, but I just couldn't do the last step which is drawing high voted thetas/rhos values. I tried to do its math on my own but It remained to get wrong outputs. When I checked some implementations of others, they were always using this approach to transform from Polar to cartesian coordinates in order to find two points.
for r,theta in lines[0]:
# Stores the value of cos(theta) in a
a = np.cos(theta)
# Stores the value of sin(theta) in b
b = np.sin(theta)
# x0 stores the value rcos(theta)
x0 = a*r
# y0 stores the value rsin(theta)
y0 = b*r
# x1 stores the rounded off value of (rcos(theta)-1000sin(theta))
x1 = int(x0 + 1000*(-b))
# y1 stores the rounded off value of (rsin(theta)+1000cos(theta))
y1 = int(y0 + 1000*(a))
# x2 stores the rounded off value of (rcos(theta)+1000sin(theta))
x2 = int(x0 - 1000*(-b))
# y2 stores the rounded off value of (rsin(theta)-1000cos(theta))
y2 = int(y0 - 1000*(a))
# cv2.line draws a line in img from the point(x1,y1) to (x2,y2).
# (0,0,255) denotes the colour of the line to be
#drawn. In this case, it is red.
cv2.line(img,(x1,y1), (x2,y2), (0,0,255),2)
The previous code from GeeksForGeeks.
What I didn't get are those equations x1 = int(x0 + 1000*(-b)) & y2 = int(y0 - 1000*(a)). By translating these equations as a mathematic form : x1 = r cos(theta) + r (-sin(theta))||
y1 = r sin(theta) + r (cos(theta))
These two equations are just strange to me. 'r cos(theta)' is normal as we transfer from polar to cartesian. However, the next part isn't clear. Could anyone explain the original math behind it?
(r cos, r sin) is the point closest to the origin on the line. It is not a line equation. To draw a line, u need 2 points. Here, he just moved along line 1000 and -1000 to get two points that are guaranteed to be outside a medium sized image
There are many ways to get line equation. Easiest is:
r = x cos + y sin
If x1 = x - t sin
y1 = (1 / sin) (r - x cos + t sin cos)
= y + t cos
He used t=+/-1000 for image size
I have two arrays as follows:
X1 = np.array([[x11, x12, x13 ... x1n],[y11, y12, y13, ... , y1n]])
X2 = np.array([[x21, x22, x23 ... x2n],[y21, y22, y23, ... , y2n]])
I would like to basically conceptualize these as piecewise linear functions and come up with an intersection point intercept:
intercept = (x_int, y_int)
Every search I do regarding array intersection gives entirely unrelated results, since the intersection of two arrays also has the meaning of finding elements common to both arrays (rather than an intersection point).
I also found this interesting post, but it seems too complex for my application. If I had to implement this, I think I could since it would involve repeated calculations of line equations and intersections of points between line equations. However I'm first trying to check if some robust implementation already exists in a well-tested library, since my poor attempt might take hours/days to achieve and then not necessarily be applicable for any dataset.
Has this already been implemented in python?
Step 1: work with the union of x1 and x2.
Step 2: linearly interpolate to find y1 and y2 for each point in the union.
Step 3: find where y1 - y2 changes sign.
Step 4: solve the linear equations for the intersection.
import numpy as np
def intersect_piecewise(X1, X2):
x = np.union1d(X1[0], X2[0])
y1 = np.interp(x, X1[0], X1[1])
y2 = np.interp(x, X2[0], X2[1])
dy = y1 - y2
ind = (dy[:-1] * dy[1:] < 0).nonzero()[0]
x1, x2 = x[ind], x[ind+1]
dy1, dy2 = dy[ind], dy[ind+1]
y11, y12 = y1[ind], y1[ind+1]
y21, y22 = y2[ind], y2[ind+1]
x_int = x1 - (x2 - x1) * dy1 / (dy2 - dy1)
y_int = y11 + (y12 - y11) * (x_int - x1) / (x2 - x1)
return x_int, y_int
the equations you need to solve are
(x_int - x1) / (x2 - x1) = (0 - dy1) / (dy2 - dy1)
= (y_int - y11) / (y12 - y11) = (y_int - y21) / (y22 - y21)
Edit: Let's try it out
import matplotlib.pyplot as plt
x = np.linspace(-2, 2, 17)
X1 = np.stack((x[::2], x[::2]**2))
X2 = np.stack((x[1::2], 4 - x[1::2]**2))
x_int, y_int = intersect_piecewise(X1, X2)
plt.plot(X1[0], X1[1], 'bo-', X2[0], X2[1], 'bo-', x_int, y_int, 'rs')
So I'm trying to obtain hough lines on a chessboard, but the algorithm results in only one line being detected. I'm using python 2.7 and opencv 3.0. Here's the code:
def applyHoughLineTransform():
image1 = cv2.imread('pictures/board1.png',0)
image2 = cv2.imread('pictures/board2.png',0)
image3 = cv2.imread('pictures/board3.png')
image4 = cv2.imread('pictures/board4.png')
lines1 = cv2.HoughLines(image1,1,math.pi/180.0,5)
lines2 = cv2.HoughLines(image2,1,math.pi/180.0,5)
lines1 = lines1[0]
lines2 = lines2[0]
for rho,theta in lines1:
print ('Rho and theta:',rho,theta)
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
print (x1,y1)
print (x2,y2)
cv2.line(image3,(x1,y1),(x2,y2),(0,0,255),2)
for rho,theta in lines2:
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(image4,(x1,y1),(x2,y2),(0,0,255),2)
cv2.imwrite('pictures/board1.png',image1)
cv2.imwrite('pictures/board2.png',image2)
cv2.imshow('hough line 1',image3)
cv2.imshow('hough line 2',image4)
Here's the canny edge image on which i perform the hough line algorithm:
And here are the results:
As you can see, pretty lame. The canny algorithm seems to be providing really nice edges to operate on. I'm not entirely sure what I'm doing wrong. I imagine it has something to do with the arguments inputted into the houghLines function. If someone could point me in the right direction (or fix my problem entirely :) ) I would greatly appreciate it. Here's a link to the tutorial site I'm using:
http://opencv-python-tutroals.readthedocs.org/en/latest/py_tutorials/py_imgproc/py_houghlines/py_houghlines.html
OPENCV 3.1.0
After checking the example from the package This is what you should use to get it right in Opencv 3.0.0 +
import cv2
import numpy as np
import math
image1 = cv2.imread('img.png')
gray=cv2.cvtColor(image1,cv2.COLOR_BGR2GRAY)
dst = cv2.Canny(gray, 50, 200)
lines= cv2.HoughLines(dst, 1, math.pi/180.0, 100, np.array([]), 0, 0)
#lines1 = cv2.HoughLines(image1,1,math.pi/180.0,5)
#lines2 = cv2.HoughLines(image2,1,math.pi/180.0,5)
#lines1 = lines1[0]
#lines2 = lines2[0]
a,b,c = lines.shape
for i in range(a):
rho = lines[i][0][0]
theta = lines[i][0][1]
a = math.cos(theta)
b = math.sin(theta)
x0, y0 = a*rho, b*rho
pt1 = ( int(x0+1000*(-b)), int(y0+1000*(a)) )
pt2 = ( int(x0-1000*(-b)), int(y0-1000*(a)) )
cv2.line(image1, pt1, pt2, (0, 0, 255), 2, cv2.LINE_AA)
cv2.imshow('image1',image1)
cv2.waitKey(0)
cv2.destoryAllWindows(0)
OUTPUT
The fix to this issue, was to switch from opencv 3.0 to 2.4. Now I get all the lines I want. Lesson learned... it's in beta for a reason! Here are the results:
I had the same issue with OpenCV 3.4. The culprit is in the numpy array lines:
[[[ 7.99000000e+02 1.57079637e+00]]
[[ 9.39000000e+02 1.57079637e+00]]
[[ 1.57100000e+03 1.57079637e+00]]
[[ 6.68000000e+02 1.57079637e+00]]
[[ 5.46000000e+02 1.57079637e+00]]
[[ 1.42700000e+03 1.57079637e+00]]
...
[[ 1.49100000e+03 1.57079637e+00]]]
Notice this is a 3D array, while the example code treats it as a 2D array. The fix is simply to extract rho and theta from the 3D array (only the first 2 lines are changed):
for line in lines:
rho, theta = line[0]
a = np.cos(theta)
b = np.sin(theta)
x0 = a*rho
y0 = b*rho
x1 = int(x0 + 1000*(-b))
y1 = int(y0 + 1000*(a))
x2 = int(x0 - 1000*(-b))
y2 = int(y0 - 1000*(a))
cv2.line(img,(x1,y1),(x2,y2),(0,0,255),2)
If I have x,y coordinates for a point on line in 3D and I need to get this z-coordinate using python, how can I do it ?? I have the start point (x1,y1,z1) and end point (x2,y2,z2) of the line in 3D, so any suggestions please ???
You can easily setup a parametric equation for the line:
x = x1 + (x2 - x1)*t
y = y1 + (y2 - y1)*t
z = z1 + (z2 - z1)*t
So given a (x,y), solve this equation for t:
x = x1 + (x2 - x1)*t
so
t = (x - x1) / (x2 - x1)
or
t = (y - y1) / (y2 - y1)
Now that you know t, you can find z:
z = z1 + (z2 - z1)*t
So in Python it would be:
def computeZ(p1,p2,x,y):
x1,y1,z1 = p1
x2,y2,z2 = p2
if x2 - x1 != 0:
t = (x - x1) / (x2 - x1)
elif y2 - y1 != 0:
t = (y - y1) / (y2 - y1)
else:
print "no unique z value exists"
return 0
return z1 + (z2 - z1)*t
You only need to know either the X or the Y value, not both. The equation, if you have an X value, A, would be:
((A - x1)*(z2 - z1)/(x2 - x1)) + z1
Using this, you can plug in your two initial points and an x and get the new point like so:
def get_points(p1, p2, x):
x1, y1, z1 = p1
x2, y2, z2 = p2
new_z = ((x - x1)*(z2 - z1)/(x2 - x1)) + z1
new_y = ((x - x1)*(y2 - y1)/(x2 - x1)) + y1
new_p = (x, new_y, new_z)
return new_p