32

I want to visualize polygonal curve(s) extracted with cv2.approxPolyDP(). Here's the image I am using:

map of UK

My code attempts to isolate the main island and define and plot the contour approximation and contour hull. I have plotted the contour found in green, the approximation in red:

import numpy as np
import cv2

# load image and shrink - it's massive
img = cv2.imread('../data/UK.png')
img = cv2.resize(img, None,fx=0.25, fy=0.25, interpolation = cv2.INTER_CUBIC)

# get a blank canvas for drawing contour on and convert img to grayscale
canvas = np.zeros(img.shape, np.uint8)
img2gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# filter out small lines between counties
kernel = np.ones((5,5),np.float32)/25
img2gray = cv2.filter2D(img2gray,-1,kernel)

# threshold the image and extract contours
ret,thresh = cv2.threshold(img2gray,250,255,cv2.THRESH_BINARY_INV)
im2,contours,hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)


# find the main island (biggest area)
cnt = contours[0]
max_area = cv2.contourArea(cnt)

for cont in contours:
    if cv2.contourArea(cont) > max_area:
        cnt = cont
        max_area = cv2.contourArea(cont)

# define main island contour approx. and hull
perimeter = cv2.arcLength(cnt,True)
epsilon = 0.01*cv2.arcLength(cnt,True)
approx = cv2.approxPolyDP(cnt,epsilon,True)

hull = cv2.convexHull(cnt)

# cv2.isContourConvex(cnt)

cv2.drawContours(canvas, cnt, -1, (0, 255, 0), 3)
cv2.drawContours(canvas, approx, -1, (0, 0, 255), 3)
## cv2.drawContours(canvas, hull, -1, (0, 0, 255), 3) # only displays a few points as well.

cv2.imshow("Contour", canvas)
k = cv2.waitKey(0)

if k == 27:         # wait for ESC key to exit
    cv2.destroyAllWindows()

Here are the resulting images:

enter image description here

The first image plots the contour in green. The second plots the approximation in red - how do I plot this approximation as a continuous closed curve?

The documentation isn't terribly clear and neither is the tutorial, but my understanding is that cv2.approxPolyDP() should define a continuous, closed curve, which I should be able to plot with cv2.drawContours(). Is that correct? If so, what am I doing wrong?

Scott
  • 4,974
  • 6
  • 35
  • 62
Aidenhjj
  • 1,249
  • 1
  • 14
  • 27
  • What is your question? What do you want to achieve? Your code does not correspond to visualization. `cv2.approxPolyDP()` returns list of points, and yes, you are able to draw them as a curve, but I am not sure how it deals with self-intersections (which exist on your initial curve). – avtomaton Jan 26 '17 at 17:32
  • @avtomaton - I have updated my question - how do I plot the returned list of points as a continuous curve if not by using `drawContours`? – Aidenhjj Jan 26 '17 at 17:37
  • I am still not sure what you are drawing. You are correct, you should use `drawContours` for drawing contours, but in your code you are drawing them on the same canvas, and them showing one picture, but your attached pictures are different! Could you please post relevant code? And I am still suppose that it can be due to self-intersections. Try to draw lines istead for figuring it out. – avtomaton Jan 26 '17 at 17:41
  • @avtomaton - to get the first image I commented out the second call to drawCanvas() and visa-versa. Make sense? – Aidenhjj Jan 26 '17 at 17:43
  • I see, sorry for inconvenience. Please try to draw lines instead - you will see points order in your approximated contour. – avtomaton Jan 26 '17 at 17:45
  • @avtomaton - what's the best way for me to draw lines? If I use `cv2.polylines(canvas, approx, True, (255, 0, 255))`, I get basically the same result. – Aidenhjj Jan 26 '17 at 17:57
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/134107/discussion-between-avtomaton-and-aidenhjj). – avtomaton Jan 26 '17 at 18:01
  • Try using [convex hull](https://en.wikipedia.org/wiki/Convex_hull). [Example Application of Convex Hull](https://i.stack.imgur.com/QGUu4.jpg) Refs: [http://opencvexamples.blogspot.com/2013/10/convex-hull.html](http://opencvexamples.blogspot.com/2013/10/convex-hull.html) – Jonel Dominic Brave Mar 24 '19 at 02:29

2 Answers2

45

The problem is in visualization only: drawContours expects array (list in case of python) of contours, not just one numpy array (which is returned from approxPolyDP).

Solution is the following: replacing

cv2.drawContours(canvas, approx, -1, (0, 0, 255), 3)

to

cv2.drawContours(canvas, [approx], -1, (0, 0, 255), 3)
avtomaton
  • 4,725
  • 1
  • 38
  • 42
-3
cv2.approxPolyDP()

approx = cv2.approxPolyDP(cnt, 0.03 * cv2.arcLength(cnt, True), True)
David Buck
  • 3,752
  • 35
  • 31
  • 35
  • 8
    Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes. – Mark Rotteveel Aug 10 '20 at 06:22