1

I am detecting straight lines in an image using OpenCv. Below is the code:

import cv2
import numpy as np

img = cv2.imread('Image.jpg')
img = img[:, 10:img.shape[1]-10]
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
minLineLength = img.shape[1] - 300
lines = cv2.HoughLinesP(image=edges, rho=0.02, theta=np.pi / 500, threshold=10, lines=np.array([]), minLineLength=minLineLength, maxLineGap=2)
a, b, c = lines.shape
for i in range(a):
    cv2.line(img, (lines[i][0][0], lines[i][0][1]), (lines[i][0][2], lines[i][0][3]), (0, 0, 255), 2, cv2.LINE_AA)
cv2.imwrite('result.png', img)

For the image(Screenshot of a PDF) Image.jpg(Below) I am getting result.png(Below) as a result which is exactly the output I desire.

Image.jpg enter image description here

result.png enter image description here

But when I give the below Image Test.jpg as an input, my algorithm is not working correctly. It is giving the following error:

a, b, c = lines.shape # 10th Line
AttributeError: 'NoneType' object has no attribute 'shape'

I think because in Test.jpg the horizontal lines are not that straight(because I clicked this by a phone's camera) and also If I change the minLineLength value to let's say 100 it is not showing the above error but showing incomplete faded lines on each row. So can anyone please tell me what params should I change in my algorithm to make it work correctly?

Test.jpgenter image description here

Aadit
  • 199
  • 1
  • 6
  • 17
  • First of all, what does your "10th line" comment mean? You've taken the dimensions of the returned vector of lines. According to the error message, `lines` is `None` at that point. I find that very strange: increasing the threshold should *reduce* the quantity of lines, not enable finding them where the lower value got none. Check that value of `lines`, and double-check the arguments you give to that call. – Prune Apr 17 '18 at 16:18
  • that error is in the 10th line of the code posted. By changing the ***minLineLength*** I meant sorry. Look at the question again. @Prune – Aadit Apr 17 '18 at 18:38

2 Answers2

2

You need to loosen up on your definition of "straight". The documentation is clear if you are already familiar with the terminology of the geometry. "rho" and "theta" are the variables for polar coordinates: length and direction, in this case. Since you're worried about a variation in direction, you need to loosen up on the theta value

theta=np.pi / 500

Is too restrictive (PI/500 radians, just over 1/3 of a degree). Decrease that 500 figure until you have a result you like. For instance, try starting with 90 (1 degree).

Prune
  • 76,765
  • 14
  • 60
  • 81
  • I went through [this](https://docs.opencv.org/master/d6/d10/tutorial_py_houghlines.html) I tried various values of theta but it is throwing the following error every time: a, b, c = lines.shape, AttributeError: 'NoneType' object has no attribute 'shape' @Prune – Aadit Apr 16 '18 at 18:41
  • You're going through a reasonable tutorial; thanks for the link. However, there's not much we can do for the error until you post the supporting code to your question. You really got that simply by chaning the denominator of the `theta` expression? – Prune Apr 16 '18 at 18:59
  • Happy to help. Actually I should have mentioned this error was thrown previously also when I tried "Test.jpg" as an input and also If i change the minLength parameter to some arbitrary value let's say 100 it is showing incomplete faded lines on each row. PS : I am using the mentioned code in my question to test this Image. @Prune – Aadit Apr 16 '18 at 19:08
  • Please update your posting to clarify when you get the error, and when you don't. Obviously, you got good output (for truly straight lines) at least once. – Prune Apr 16 '18 at 21:17
  • Normally, I would think that increasing `theta` and reducing `threshold` would improve your results. If you have trouble with line length, also experiment with `rho` -- I *think* you want to increase it, but not sure about algorithm internals. – Prune Apr 17 '18 at 16:20
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/169182/discussion-between-aadit-and-prune). – Aadit Apr 17 '18 at 17:01
0

possibly add a condition to test if there is a line. remember you are looking for lines of a particular length. the second image has none. i tried your code and commented

minLineLength = img.shape[1] - 300

your code works with only particluar images. if you need to use any image comment out the lines

#img = img[:, 10:img.shape[1]-10]
minLineLength = 10 #img.shape[1] - 300

it works if this is the case the final code i executed is

import cv2
import numpy as np
img = cv2.imread('test.jpg')
#img = img[:, 10:img.shape[1]-10]
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 50, 150, apertureSize=3)
minLineLength = 20 #img.shape[1] - 300
lines = cv2.HoughLinesP(image=edges, rho=0.02, theta=np.pi / 500,     threshold=10, lines=np.array([]), minLineLength=minLineLength, maxLineGap=2)
a, b, c = lines.shape

for i in range(a):
    cv2.line(img, (lines[i][0][0], lines[i][0][1]), (lines[i][0][2],  lines[i][0][3]), (0, 0, 255), 2, cv2.LINE_AA)
cv2.imwrite('result.png', img)
kishea
  • 637
  • 1
  • 6
  • 17
  • that is what I mentioned in my question itself. As I said take **minLineLength** to be **100**. It is giving better results than your code but lines are still incomplete and faded. – Aadit Apr 17 '18 at 18:35