cv2.perspectiveTransform() 不接受单应矩阵
cv2.perspectiveTransform() not accepting homography matrix
下面是 bookhomography-example-1.jpg
然后 bookhomography-example-2.jpg
来自 popular OpenCV blogpost 关于单应性。
我可以进行单应性和扭曲图像,但是当我尝试使用 cv2.perspectiveTransform(pts, h)
或 cv2.perspectiveTransform(pts, h[0])
时 h
或 h[0]
不起作用。我也试过将二维数组 h[0]
转换为元组的元组,但没有改变。这可能很简单,但我想不通。
Error Message:
Traceback (most recent call last):
File "bookhomography stackexchange v00.py", line 36, in T_dst
= cv2.perspectiveTransform(pts_dst, h) TypeError: m is not a numerical tuple
注意: 将 False
设置为 True
会导致失败。两条变换线之一是错误的方向但都失败了。
import numpy as np
import matplotlib.pyplot as plt
import cv2
im_src = cv2.imread("bookhomography-example-2.jpg")
im_dst = cv2.imread("bookhomography-example-1.jpg")
im_srcrgb = cv2.cvtColor(im_src, cv2.COLOR_BGR2RGB)
im_dstrgb = cv2.cvtColor(im_dst, cv2.COLOR_BGR2RGB)
pts_src = np.float32([52, 376, 240, 528, 413, 291, 217, 266]).reshape(4, -1)
pts_dst = np.float32([56, 478, 387, 497, 376, 124, 148, 218]).reshape(4, -1)
h = cv2.findHomography(pts_src, pts_dst)
print "type(h): ", type(h)
print "len(h): ", len(h)
print "type(h[0]): ", type(h[0])
print "len(h[0]): ", len(h[0])
print "h[0].shape: ", h[0].shape
shape = im_src.shape[:2][::-1]
print h[0]
print "pts_src:"
print pts_src
print "pts_dst:"
print pts_dst
if False:
T_dst = cv2.perspectiveTransform(pts_dst, h)
T_src = cv2.perspectiveTransform(pts_src, h)
print "T_src:"
print T_src
print "T_dst:"
print T_dst
im_fin = cv2.warpPerspective(im_src, h[0], shape)
im_finrgb = cv2.cvtColor(im_fin, cv2.COLOR_BGR2RGB)
plt.figure()
plt.subplot(1, 3, 1)
plt.imshow(im_srcrgb)
x, y = pts_src.T
plt.plot(x, y, 'or', ms=8)
plt.subplot(1, 3, 2)
plt.imshow(im_dstrgb)
x, y = pts_dst.T
plt.plot(x, y, 'or', ms=8)
plt.subplot(1, 3, 3)
plt.imshow(im_finrgb)
x, y = pts_dst.T
plt.plot(x, y, 'or', ms=8)
plt.show()
查看我的回答 以获得快速修复。 TL:DR; OpenCV 函数 perspectiveTransform()
采用奇数格式指定的点,而 findHomography()
使用您拥有的格式。
首先注意findHomography()
returns 两个值;单应性矩阵,以及 mask
。来自 docs:
cv2.findHomography(srcPoints, dstPoints[, method[, ransacReprojThreshold[, mask]]]) → retval, mask
第二个return值不是单应性,因此应该使用h[0]
。或者你可以写:
h, mask = cv2.findHomography(srcPoints, dstPoints)
或
h = cv2.findHomography(srcPoints, dstPoints)[0]
所以 h
只有 保持单应性以减少混淆。请注意,使用 h
或 h[0]
会给出不同的错误消息:
使用h
:
>>> T_dst = cv2.perspectiveTransform(pts_dst, h)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: m is not a numerical tuple
使用h[0]
:
>>> T_dst = cv2.perspectiveTransform(pts_dst, h[0])
OpenCV Error: Assertion failed (scn + 1 == m.cols) in perspectiveTransform, file .../opencv/modules/core/src/matmul.cpp, line 2299
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
cv2.error: .../opencv/modules/core/src/matmul.cpp:2299: error: (-215) scn + 1 == m.cols in function perspectiveTransform
不幸的是,这里的错误消息对您并没有真正的帮助,因为实际的问题是指定点的方式。这在技术上是用户错误,但文档(和函数本身)可能应该更改。
无论如何,解决方法:向 pts
向量添加一个通道。查看区别:
>>> np.float32([52, 376, 240, 528, 413, 291, 217, 266]).reshape(4, -1)
array([[ 52., 376.],
[ 240., 528.],
[ 413., 291.],
[ 217., 266.]], dtype=float32)
>>> np.float32([52, 376, 240, 528, 413, 291, 217, 266]).reshape(4, 1, -1)
array([[[ 52., 376.]],
[[ 240., 528.]],
[[ 413., 291.]],
[[ 217., 266.]]], dtype=float32)
幸运的是,findHomography()
也适用于这种格式,因此您不必根据所使用的功能使用两种不同的格式。为了安全起见,对于 OpenCV 函数,始终以这种格式放置点。
>>> pts_src = np.float32([52, 376, 240, 528, 413, 291, 217, 266]).reshape(4, 1, -1)
>>> pts_dst = np.float32([56, 478, 387, 497, 376, 124, 148, 218]).reshape(4, 1, -1)
>>> h = cv2.findHomography(pts_src, pts_dst)[0]
>>> T_dst = cv2.perspectiveTransform(pts_dst, h)
>>> T_src = cv2.perspectiveTransform(pts_src, h)
>>> T_src
array([[[ 56., 478.]],
[[ 387., 497.]],
[[ 376., 124.]],
[[ 148., 218.]]], dtype=float32)
>>> T_dst
array([[[ 157.78089905, 588.9598999 ]],
[[ 495.96539307, 365.68994141]],
[[ 200.45231628, -69.54611206]],
[[ 15.72697926, 204.0632019 ]]], dtype=float32)
上面没有错误。
下面是 bookhomography-example-1.jpg
然后 bookhomography-example-2.jpg
来自 popular OpenCV blogpost 关于单应性。
我可以进行单应性和扭曲图像,但是当我尝试使用 cv2.perspectiveTransform(pts, h)
或 cv2.perspectiveTransform(pts, h[0])
时 h
或 h[0]
不起作用。我也试过将二维数组 h[0]
转换为元组的元组,但没有改变。这可能很简单,但我想不通。
Error Message:
Traceback (most recent call last):
File "bookhomography stackexchange v00.py", line 36, in T_dst = cv2.perspectiveTransform(pts_dst, h) TypeError: m is not a numerical tuple
注意: 将 False
设置为 True
会导致失败。两条变换线之一是错误的方向但都失败了。
import numpy as np
import matplotlib.pyplot as plt
import cv2
im_src = cv2.imread("bookhomography-example-2.jpg")
im_dst = cv2.imread("bookhomography-example-1.jpg")
im_srcrgb = cv2.cvtColor(im_src, cv2.COLOR_BGR2RGB)
im_dstrgb = cv2.cvtColor(im_dst, cv2.COLOR_BGR2RGB)
pts_src = np.float32([52, 376, 240, 528, 413, 291, 217, 266]).reshape(4, -1)
pts_dst = np.float32([56, 478, 387, 497, 376, 124, 148, 218]).reshape(4, -1)
h = cv2.findHomography(pts_src, pts_dst)
print "type(h): ", type(h)
print "len(h): ", len(h)
print "type(h[0]): ", type(h[0])
print "len(h[0]): ", len(h[0])
print "h[0].shape: ", h[0].shape
shape = im_src.shape[:2][::-1]
print h[0]
print "pts_src:"
print pts_src
print "pts_dst:"
print pts_dst
if False:
T_dst = cv2.perspectiveTransform(pts_dst, h)
T_src = cv2.perspectiveTransform(pts_src, h)
print "T_src:"
print T_src
print "T_dst:"
print T_dst
im_fin = cv2.warpPerspective(im_src, h[0], shape)
im_finrgb = cv2.cvtColor(im_fin, cv2.COLOR_BGR2RGB)
plt.figure()
plt.subplot(1, 3, 1)
plt.imshow(im_srcrgb)
x, y = pts_src.T
plt.plot(x, y, 'or', ms=8)
plt.subplot(1, 3, 2)
plt.imshow(im_dstrgb)
x, y = pts_dst.T
plt.plot(x, y, 'or', ms=8)
plt.subplot(1, 3, 3)
plt.imshow(im_finrgb)
x, y = pts_dst.T
plt.plot(x, y, 'or', ms=8)
plt.show()
查看我的回答 perspectiveTransform()
采用奇数格式指定的点,而 findHomography()
使用您拥有的格式。
首先注意findHomography()
returns 两个值;单应性矩阵,以及 mask
。来自 docs:
cv2.findHomography(srcPoints, dstPoints[, method[, ransacReprojThreshold[, mask]]]) → retval, mask
第二个return值不是单应性,因此应该使用h[0]
。或者你可以写:
h, mask = cv2.findHomography(srcPoints, dstPoints)
或
h = cv2.findHomography(srcPoints, dstPoints)[0]
所以 h
只有 保持单应性以减少混淆。请注意,使用 h
或 h[0]
会给出不同的错误消息:
使用h
:
>>> T_dst = cv2.perspectiveTransform(pts_dst, h)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: m is not a numerical tuple
使用h[0]
:
>>> T_dst = cv2.perspectiveTransform(pts_dst, h[0])
OpenCV Error: Assertion failed (scn + 1 == m.cols) in perspectiveTransform, file .../opencv/modules/core/src/matmul.cpp, line 2299
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
cv2.error: .../opencv/modules/core/src/matmul.cpp:2299: error: (-215) scn + 1 == m.cols in function perspectiveTransform
不幸的是,这里的错误消息对您并没有真正的帮助,因为实际的问题是指定点的方式。这在技术上是用户错误,但文档(和函数本身)可能应该更改。
无论如何,解决方法:向 pts
向量添加一个通道。查看区别:
>>> np.float32([52, 376, 240, 528, 413, 291, 217, 266]).reshape(4, -1)
array([[ 52., 376.],
[ 240., 528.],
[ 413., 291.],
[ 217., 266.]], dtype=float32)
>>> np.float32([52, 376, 240, 528, 413, 291, 217, 266]).reshape(4, 1, -1)
array([[[ 52., 376.]],
[[ 240., 528.]],
[[ 413., 291.]],
[[ 217., 266.]]], dtype=float32)
幸运的是,findHomography()
也适用于这种格式,因此您不必根据所使用的功能使用两种不同的格式。为了安全起见,对于 OpenCV 函数,始终以这种格式放置点。
>>> pts_src = np.float32([52, 376, 240, 528, 413, 291, 217, 266]).reshape(4, 1, -1)
>>> pts_dst = np.float32([56, 478, 387, 497, 376, 124, 148, 218]).reshape(4, 1, -1)
>>> h = cv2.findHomography(pts_src, pts_dst)[0]
>>> T_dst = cv2.perspectiveTransform(pts_dst, h)
>>> T_src = cv2.perspectiveTransform(pts_src, h)
>>> T_src
array([[[ 56., 478.]],
[[ 387., 497.]],
[[ 376., 124.]],
[[ 148., 218.]]], dtype=float32)
>>> T_dst
array([[[ 157.78089905, 588.9598999 ]],
[[ 495.96539307, 365.68994141]],
[[ 200.45231628, -69.54611206]],
[[ 15.72697926, 204.0632019 ]]], dtype=float32)
上面没有错误。