I'm failing to understand the documentation for cv2.transform. Will someone take pity and explain please (in Python)?
I have code that draws a polygon, fills it in, and rotates the image
import numpy as np
import cv2
dx,dy = 400,400
centre = dx//2,dy//2
img = np.zeros((dy,dx),np.uint8)
# construct a long thin triangle with the apex at the centre of the image
polygon = np.array([(0,0),(100,10),(100,-10)],np.int32)
polygon += np.int32(centre)
# draw the filled-in polygon and then rotate the image
cv2.fillConvexPoly(img,polygon,(255))
M = cv2.getRotationMatrix2D(centre,20,1) # M.shape = (2, 3)
rotatedimage = cv2.warpAffine(img,M,img.shape)
I want to rotate the polygon first and then draw it
# this is clumsy, I have to extend each vector,
# apply the matrix to each extended vector,
# and turn the list of transformed vectors into an numpy array
extendedpolygon = np.hstack([polygon,np.ones((3,1))])
rotatedpolygon = np.int32([M.dot(x) for x in extendedpolygon])
cv2.fillConvexPoly(img,rotatedpolygon,(127))
I'd like to do it in one function call but I can't get it right
# both of these calls produce the same error
cv2.transform(polygon,M)
cv2.transform(polygon.T,M)
# OpenCV Error: Assertion failed (scn == m.cols || scn + 1 == m.cols) in transform, file /home/david/opencv/modules/core/src/matmul.cpp, line 1947
I suspect that it's the phrase "src – input array that must have as many channels (1 to 4) as m.cols or m.cols-1" that I'm floundering on. I thought that polygon.T as three coordinates with the x and y parts as separate channels would qualify, but sadly not.
I'm aware that the same question has been asked for C++, I want an answer in Python.
My thanks to Micka who pointed me to a working example. Here is code that provides an answer to my question.
import numpy as np
import cv2
dx,dy = 400,400
centre = dx//2,dy//2
img = np.zeros((dy,dx),np.uint8)
# construct a long thin triangle with the apex at the centre of the image
polygon = np.array([(0,0),(100,10),(100,-10)],np.int32)
polygon += np.int32(centre)
# draw the filled-in polygon and then rotate the image
cv2.fillConvexPoly(img,polygon,(255))
M = cv2.getRotationMatrix2D(centre,20,1) # M.shape = (2, 3)
rotatedimage = cv2.warpAffine(img,M,img.shape)
# as an alternative, rotate the polygon first and then draw it
# these are alternative ways of coding the working example
# polygon.shape is 3,2
# magic that makes sense if one understands numpy arrays
poly1 = np.reshape(polygon,(3,1,2))
# slightly more accurate code that doesn't assumy the polygon is a triangle
poly2 = np.reshape(polygon,(polygon.shape[0],1,2))
# turn each point into an array of points
poly3 = np.array([[p] for p in polygon])
# use an array of array of points
poly4 = np.array([polygon])
# more magic
poly5 = np.reshape(polygon,(1,3,2))
for poly in (poly1,poly2,poly3,poly4,poly5):
newimg = np.zeros((dy,dx),np.uint8)
rotatedpolygon = cv2.transform(poly,M)
cv2.fillConvexPoly(newimg,rotatedpolygon,(127))
To be honest, I don't understand why cv2.fillConvexPoly() accepts the first three answers but it seems to be very forgiving and I still don't understand how these answers map to the documentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With