无法正常使用cv.transform的解决方法

11
我想在一些个体的(x,y)点上使用与我在使用cv2.warpAffine处理图像时相同的仿射矩阵M。看起来cv2.transform是正确的方法。但当我尝试发送一个Nx2点矩阵时,它被否定了。
   src = np.array([
        [x1,y1],[x2,y2],[x3,y3],[x4,y4]],  dtype = "float32")
    print('source shape '+str(src.shape))
    dst=cv2.transform(src,M)

cv2.error: /home/jeremy/sw/opencv-3.1.0/modules/core/src/matmul.cpp:1947: error: (-215) scn == m.cols || scn + 1 == m.cols in function transform

我可以只使用numpy算术运算得到所需的变换:

    dst = np.dot(src,M[:,0:2]) +M[:,2]
    print('dest:{}'.format(dst))

但是我希望理解正在发生的事情。文档说cv2.transform想要的通道数等于M中列数,但我不清楚通道将是什么 - 可能是“x”通道和“y”通道,但是第三个将会是什么,不同的行代表什么?


1
通常情况下,当OpenCV需要点时,它们会以np.array([[[x1, y1]], [[x2, y2]],...])的形式出现。他们通常希望在点变换中使用这种形式——一个单列或行向量,其长度为点数,通道数等于坐标数。第三个坐标可能是第三个维度中的坐标——毕竟,变换矩阵不仅适用于2D变换。 - alkasm
谢谢,解决了问题,我在脑海中把维度顺序搞反了,应该是 hwc 而不是 chw,可能是咖啡因摄入过量了。 - jeremy_rutman
numpy中的等效代码可以正常运行,但不是您想要的正确转换。cv2.transform的numpy等效代码应为(np.dot(M[:,:2], a.T)+M[:,2].reshape(2,1)).T - thisisbhavin
2个回答

15

OpenCV在Python中通常需要以点的形式表示

np.array([ [[x1, y1]], ..., [[xn, yn]] ])

cv2.transform()的文档中,这不是很清楚,但在其他使用点的函数的文档中更为清晰,比如cv2.perspectiveTransform(),其中提到坐标位于不同的通道:

src - 输入的两通道或三通道浮点型数组

变换也可以在3D中进行(使用4x4透视变换矩阵),这解释了为什么可以在cv2.transform()中使用两通道或三通道数组。


1
对于上述使用案例(将一个Nx2矩阵中的点进行2D变换),一种简写形式是dst = cv2.transform(np.array([src]), M)[0] - Jerod
1
稍微好一点:cv2.transform(src[None, ...], M)[0]。这将创建一个对src数组的视图,而np.array([src])则会创建一个额外的数组,它会复制内存并且需要大约10倍的时间。 - aerobiomat

1
通道是源数组的最后一个维度。让我们从开始阅读cv2.transform()函数的文档。enter image description here
问题: 由于该函数会转换参数src中的每个元素,因此src的维数必须大于2。
import cv2
import numpy as np

rotation_mat = np.array([[0.8660254, 0.5, -216.41978046], [-0.5, 0.8660254, 264.31038357]]) # 2x3

rotate_box = np.array([[410, 495], [756, 295], [956, 642], [610, 842]]) # 2x2
result_box = cv2.transform(rotate_box, rotation_mat) # error: (-215:Assertion failed) scn == m.cols || scn + 1 == m.cols in function 'transform'

每个rotate_box元素的维度是(2,)。矩阵相乘的变换无法进行。
另一篇回答中提到,只要最后一个维度匹配,其他维度并不重要。继续看上面的代码片段:
rotate_box_1 = np.array([rotate_box]) # 1x4x2
result_box = cv2.transform(rotate_box_1, rotation_mat) # 1x4x2

rotate_box_2 = np.array([[[410, 495]], [[756, 295]], [[956, 642]], [[610, 842]]]) # 4x1x2
result_box = cv2.transform(rotate_box_2, rotation_mat) # 4x1x2

给读者的提示: 请注意,cv2.transform()返回的形状与src相同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接