What does the python interface to opencv2.fillPoly want as input?
Asked Answered
O

5

36

I'm trying to draw a polygon using the python interface to opencv, cv2. I've created an empty image, just a 640x480 numpy array. I have a list of polygons (four point quadrilaterals) that I want to draw on the image, however, I can't seem to get the formate right to instruct cv2 where the quadrilaterals should be, and I keep getting this error:

OpenCV Error: Assertion failed (points.checkVector(2, CV_32S) >= 0) in fillConvexPoly, file .../OpenCV-2.4.0/modules/core/src/drawing.cpp, line 2017

My code consists of essentially the following:

binary_image = np.zeros(image.shape,dtype='int8')
for rect in expected:
    print(np.array(rect['boundary']))
    cv2.fillConvexPoly(binary_image, np.array(rect['boundary']), 255)
fig = pyplot.figure(figsize=(16, 14))
ax = fig.add_subplot(111)
ax.imshow(binary_image)
pyplot.show()

where my list of rects in expected has the 'boundary' containing the value of a list of (x,y) points. The code prints:

[[ 91 233]
 [419 227]
 [410 324]
 [ 94 349]]

I figured that this is the list of points for a polygon, but apparently that list has an invalid points.checkvector, whatever that is. A google search for that error turned up nothing useful.

Obedient answered 29/6, 2012 at 23:42 Comment(3)
I've tried both cv2.fillPoly and cv2.fillConvexPoly here, and both throw the same error...Obedient
note, openCV wants 'uint8' for images. While I appeared to be able to get away with 'int8' here, it caused me trouble later...Obedient
The openCV documentation is particularly annoying on this function: no specification about inputs types in Python, no examples. Just to note that the second argument is a list of numpy array of shape n x 2, the numpy array representing vertices of a polygon.Cybil
N
17

The AssertionError is telling you that OpenCV wants a signed, 32-bit integer. The array of polygon points should have that particular data type (e.g. points = numpy.array(A,dtype='int32') ). You could also just cast it for the function call (i.e. my_array.astype('int32') ) or as a friend put it once...

" Changing

   cv2.fillConvexPoly(binary_image, np.array(rect['boundary']), 255) to

   cv2.fillConvexPoly(binary_image, np.array(rect['boundary'], 'int32'), 255) "

Normalie answered 30/6, 2012 at 0:38 Comment(0)
T
39
import numpy as np
import cv2
import matplotlib.pyplot as plt

a3 = np.array( [[[10,10],[100,10],[100,100],[10,100]]], dtype=np.int32 )
im = np.zeros([240,320],dtype=np.uint8)
cv2.fillPoly( im, a3, 255 )

plt.imshow(im)
plt.show()

result display

Check on colab.research.google.com

Tannate answered 4/12, 2015 at 9:55 Comment(4)
Tip for those getting ValueError: setting an array element with a sequence. when creating the numpy array of vertices (a3 in this answer): this could be due to the fact that your polygons do not have the same number of points, which means the list has a shape that numpy cannot convert into a ndarray (not a "nd-cube"). My solution is to make one call to fillPoly per polygon. An alternative could be padding each polygon vertices list with their last vertex so that they all have the same length.Lotus
@themadmax, you have to go counterclockwise from topleft for the points?Narcis
this is also a tough example to follow that does not show the ordering of x and yNarcis
@mLstudent33, it actually a3, as referred in the above example, should have the coordinates in the clock-wise direction. That is to say, [Coordinates of Top-Left, Top-Right, Bottom-Right, Bottom-Left].Shutin
N
17

The AssertionError is telling you that OpenCV wants a signed, 32-bit integer. The array of polygon points should have that particular data type (e.g. points = numpy.array(A,dtype='int32') ). You could also just cast it for the function call (i.e. my_array.astype('int32') ) or as a friend put it once...

" Changing

   cv2.fillConvexPoly(binary_image, np.array(rect['boundary']), 255) to

   cv2.fillConvexPoly(binary_image, np.array(rect['boundary'], 'int32'), 255) "

Normalie answered 30/6, 2012 at 0:38 Comment(0)
E
7

I have tried in opencv 2.4.2 and python 2.7. From the c++ interface

void fillPoly(Mat& img, 
              const Point** pts, 
              const int* npts, 
              int ncontours, 
              const Scalar& color, 
              int lineType=8, 
              int shift=0, 
              Point offset=Point() 
             )

we know the pts is the array of array of points, so you should change like this

cv2.fillConvexPoly(binary_image, np.array([rect['boundary']], 'int32'), 255)

add [ ] to the rect['boundary'].

Erhard answered 2/8, 2012 at 2:3 Comment(0)
D
2

Here's an example with annotated points. You can specify the polygon vertices in either clockwise or counter-clockwise order, as long as they follow the same direction.

import numpy as np
import matplotlib.pyplot as plt
import cv2

A = np.array([125,50])
B = np.array([50,50])
C = np.array([50,175])
D = np.array([150,150])

pts = np.array( [ A, B, C, D ] ) # counter-clockwise
#pts = np.array( [ A, D, C, B ] ) # clockwise

print(pts.shape) # (4, 2)

image = np.zeros((200,200), dtype=np.uint8)
image = np.dstack((image, image, image)) # Create three channels.

cv2.fillPoly(image, pts=[pts], color =(0,255,0))

for pt in pts:
    x = pt[0]
    y = pt[1]
    _ = plt.annotate(s='%d, %d' % (x, y), xy=(x, y), color='red', fontsize=20)

print(image.shape) # (200, 200, 3)

plt.imshow(image)
plt.grid(True)
plt.show()

enter image description here

What happens if your vertices are rearranged so that they don't follow the same direction?

pts = np.array( [ A, B, D, C ] )

You get this:

enter image description here

Dirndl answered 7/7, 2021 at 17:45 Comment(0)
C
-1

Here is an example that might help.

def region_of_interest(image):
    height = image.shape[0]
    polygons = np.array([
      [(200,height),(1100,height ),(550,250)]])
    mask = np.zeros_like(image)
    cv2.fillPoly(mask, polygons, 255)
    return mask
Cornaceous answered 1/5, 2022 at 5:25 Comment(1)
please share a details explanation of your answer.Amarelle

© 2022 - 2024 — McMap. All rights reserved.