Why is the returned value of cv2.HoughLines of OpenCV for Python need to be accessed with index?
Asked Answered
H

7

12

I hope I wrote the question title right because I don't know how to exactly explain it. Consider below's 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)

Why it has to be wrote for rho,theta in lines[0]:? By this kind of code, I can only obtain one line. I have tried to remove the indexing in lines but I got ValueError: need more than 1 value to unpack. I have tried to print the returned value and it look something like this:

[[[ 287.            1.97222209]]

[[ 885.            1.20427716]]

[[ 881.            1.22173047]]]

I have kinda solved this problem my making the code look like this:

lines = cv2.HoughLines(edges,1,np.pi/180,200)
for i in range(10):
    for rho,theta in lines[i]:

I wonder, what is really happening? Or did I do something wrong here?

Hawse answered 22/1, 2016 at 11:57 Comment(1)
If tthe docs are saying to use lines[0], then that's likely correct. The python libraries are a bridge to the C++ core, so the indexing probably has to do with that.Selfconfidence
G
7

I believe it should be this:

for line in lines:
    rho, theta = line[0]
    ...

this way you loop through all of the values in the lines array, each of which is a line consisting of rho and theta.

It would of course be much bettwe if they structure this as

[ [r0,t0], [r1,t1], ... ,[rn,tn] ]

but instead they made it confusing by using the extra nested

[ [[r0,t0]], [[r1,t1]], ... ,[[rn,tn]] ]

form.

The line in lines: loops through giving [[ri,ti]] terms, which you can then make into [ri,ti] via line[0], which you then pass into rho and theta.

Gladiator answered 27/5, 2016 at 21:45 Comment(1)
This is the correct answer. Perhaps OpenCV changed this function. Either way, the docs are outdated or simply wrong. Very weird.Casi
C
2

The question and this answer refer to this tutorial which was based on opencv 3.0.0. In openCV 3.2.0 the nested list that is returned by houghlines is a nX1X2 array (where n is the number of lines), and the right way to access rho and theta can be found in this tutorial.

So.. according to the first tutorial: "Lines" is a multi-dimensional 1XnX2 array (ndarray), where n is the number of lines detected.

The first array contains only one element, lines[0] (nX2 array), which is your list of lines (you only need to iterate through this).

On second level you have lines[0][0],lines[0][1],...,lines[0][n]. (which are your lines)

Finally, in 3rd level you have lines[0][n][0] and lines[0][n][1] which are the rho and theta values for each line. Your solution will not work as there is not a lines[1] array!

You can add this to your code and see what it prints.

print lines.shape
print lines[0].shape
print lines[0][0].shape
Costanzia answered 22/1, 2016 at 13:36 Comment(3)
It's an nX1X2 array. Your code prints (14, 1, 2), (1, 2) and (2,) respectively for me (where 14 is variable, i.e. n).Casi
Well, actually you are partly right. Both the initial question and my answer refer to this tutorial which was based on opencv 3.0.0. As you can see from the documentation the array was indeed 1XnX2, which also explains why lines[0] is used to access the lines in the example. The nested list presenting the output of houghlines has been changed since then, and the right way to access them can be found in this tutorial.Costanzia
Agreed. I downvoted your answer because it didn't answer the question in light of the fact that the OP had a different version. Now changed to an upvote, thanks for your edit!Casi
A
2
lines=cv2.HoughLines(canny,1,numpy.pi/180,120)
for i in lines:
    # print(i)
    rho=i[0][0]
    theta=i[0][1]
    a=numpy.cos(theta)
    b=numpy.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,255,0),1)
cv2.imshow('ss',img)
Adamina answered 12/1, 2021 at 12:42 Comment(0)
F
1
for line in lines:
    rho, theta = line[0]
    a = np.cos(theta)
    b = np.sin(theta)

This works for me on Python2.7 (Anaconda) and OpenCV3.1.0. There seems to be a mismatch between the example in the online documentation provided by OpenCV (1XnX2) and what it actually returns in the HoughLines function (nX1X2).

Fit answered 6/2, 2017 at 3:17 Comment(0)
B
0

By writing line[0] you acces the first element of the array. In this case the first element is another array containing the line parameter rho and theta. That's just how the cv2.HoughLines function returns its results.

So if you want to iterate over each combination of rho and theta (i.e. each line found in the image) you can write

for [rho, theta] in lines[0]:
    print rho
    print theta
Barr answered 22/1, 2016 at 13:9 Comment(0)
M
0

This worked for me

for l in lines:
    rho = l[0][0]
    theta = l[0][1]
    a = np.cos(theta)
Microwatt answered 9/9, 2018 at 17:51 Comment(1)
While this code may answer the question, providing additional context regarding why and/or how this code answers the question improves its long-term value.Spartan
T
-1
img = cv2.Canny(img,50,150)
lines = cv2.HoughLines(img,1,np.pi/180,50)
for k in range(lines.shape[0]):
    for rho,theta in lines[k]:
            a = np.cos(theta)
            b = np.sin(theta)
            x0 = a*rho
            y0 = b*rho
            P=2*max(img.shape)
            x1 = int(x0 + P*(-b))
            y1 = int(y0 + P*(a))
            x2 = int(x0 - P*(-b))
            y2 = int(y0 - P*(a))
            cv2.line(img,(x1,y1),(x2,y2),(0,255,0),5)
Trochanter answered 3/4, 2021 at 16:49 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.