Reputation: 1287
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.
Upvotes: 37
Views: 64950
Reputation: 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
Upvotes: -1
Reputation: 40969
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()
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:
Upvotes: 2
Reputation: 2404
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()
Check on colab.research.google.com
Upvotes: 40
Reputation: 186
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)
"
Upvotes: 17
Reputation: 71
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'].
Upvotes: 7