1

I am using opencv and python for programming and I am trying to draw a line between two points that I know their coordinates, and then let the line complete until it reaches the end of the contour as shown in the image bellow. The contour in my case is actually of an image face, but I have provided a circle here for explanation. So what I am trying to achieve is to get the edge of the head at that point intersecting with the line and contour. Is there a way to draw a line from two points and then let the line complete drawing until reaching the contour? enter image description here

Jeru Luke
  • 20,118
  • 13
  • 80
  • 87
Neda'a
  • 47
  • 1
  • 6
  • you could use openCV's LineIterator to follow all pixels of a line until you hit a contour pixel. But not sure if LineIterator exists in python api... – Micka Nov 12 '17 at 22:52
  • Yes I don think it exists in python – Neda'a Nov 14 '17 at 18:46
  • 2
    @Micka wicked, didn't know OpenCV had such a function! Someone on Stack actually created their own version of the function for Python: https://stackoverflow.com/questions/32328179/opencv-3-0-python-lineiterator – alkasm Nov 15 '17 at 08:59
  • Thanks, I will check this one too. – Neda'a Nov 15 '17 at 10:37
  • 1
    but be aware that you'll have to choose 4-connected line drawing/traversal (instead of 8-connected) to not miss contour pixels in special cases. – Micka Nov 15 '17 at 11:20

1 Answers1

1

I can think of one easy method off the top of my head that doesn't involve incrementally updating the image: on one blank image, draw a long line extending from point one in the direction of point two, and then AND the resulting image with the an image of the single contour drawn (filled). This will stop the line at the end of the contour. Then you can either use that mask to draw the line, or get the minimum/maximum x, y coords if you want the coordinates of the line.

To walk through an example, first we'll find the contour and draw it on a blank image:

contours = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[1]
contour_img = np.zeros_like(img)
cv2.fillPoly(contour_img, contours, 255)

Then, if we have the points p1 and p2, find the direction they're heading in and find a point far off in that distance and draw that line on a new blank image (here I used a distance of 1000 pixels from p1):

p1 = (250, 250)
p2 = (235, 210)

theta = np.arctan2(p1[1]-p2[1], p1[0]-p2[0])
endpt_x = int(p1[0] - 1000*np.cos(theta))
endpt_y = int(p1[1] - 1000*np.sin(theta))

line_img = np.zeros_like(img)
cv2.line(line_img, (p1[0], p1[1]), (endpt_x, endpt_y), 255, 2)

Then simply cv2.bitwise_and() the two images together

contour_line_img = cv2.bitwise_and(line_img, contour_img)

Here is an image showing the points, the line extending past the contour, and the line breaking off at the contour.

Line breaking at contour

Edit: Note that this will only work if your contours are convex. If there is any concavity and the line goes through that concave part, it will continue to draw on the other side of it. For e.g. in Silencer's answer, if both points were inside one of the ear and pointed towards the other ear, you'd want the contour to stop once it hit an edge, but mine will continue to draw on the other ear. I think an iterative method like Silencer's is the best for the general case, but I like the simplicity of this method if you know you have convex contours or if your points will be in a place to not have this issue.

Edit2: Someone else on Stack answered their own question about the Line Iterator class in Python by creating one: openCV 3.0 python LineIterator

alkasm
  • 22,094
  • 5
  • 78
  • 94
  • The code actually works, but why did you set the value 1000 is it an approximate value for the image width and height? – Neda'a Nov 14 '17 at 17:17
  • @Neda'a Yes it's just the length of the line in pixels, you can use any long length. The diagonal of the image is the longest possible line in an image, so perhaps that would be a good value to use in general to be sure the line extends to the ends of the image. Since I'm just drawing the line, it won't matter if the line extends past the image bounds or not---it'll just draw it to the edge of the image. – alkasm Nov 15 '17 at 05:24
  • @Neda'a make sure to mark one of the answers as the accepted solution if they worked out for you. Also see my comment on your OP about a Line Iterator method in Python. – alkasm Nov 15 '17 at 09:00