Opencv单应性从像素xy坐标找到全局xy坐标
Opencv homography to find global xy coordinates from pixel xy coordinates
我试图找到变换矩阵 H,以便我可以乘以 (x,y) 像素坐标并获得 (x,y) 真实世界坐标。这是我的代码:
import cv2
import numpy as np
from numpy.linalg import inv
if __name__ == '__main__' :
D=[159.1,34.2]
I=[497.3,37.5]
G=[639.3,479.7]
A=[0,478.2]
# Read source image.
im_src = cv2.imread('/home/vivek/june_14.png')
# Four corners of the book in source image
pts_src = np.array([D,I,G,A])
# Read destination image.
im_dst = cv2.imread('/home/vivek/june_14.png')
# Four corners of the book in destination image.
print "img1 shape:",im_dst.shape
scale=1
O=[0.0,0.0]
X=[134.0*scale,0]
Y=[0.0,184.0*scale]
P=[134.0*scale,184.0*scale]
# lx = 75.5 * scale
# ly = 154.0 * scale
pts_dst = np.array([O,X,P,Y])
# Calculate Homography
h, status = cv2.findHomography(pts_src, pts_dst)
print "homography:",h
print "inv of H:",inv(h)
print "position of the blob on the ground xy plane:",np.dot(np.dot(h,np.array([[323.0],[120.0],[1.0]])),scale)
# Warp source image to destination based on homography
im_out = cv2.warpPerspective(im_src, h, (im_dst.shape[1],im_dst.shape[0]))
# Display images
cv2.imshow("Source Image", im_src)
cv2.imshow("Destination Image", im_dst)
cv2.imshow("Warped Source Image", im_out)
cv2.imwrite("im_out.jpg", im_out)
cv2.waitKey(0)
我得到的全局 xy 非常不正常。我是不是哪里做错了?
长答案
单应性是 3x3
矩阵,而点只是对 2x1
,因此无法将它们映射到一起。相反,使用齐次坐标,给出 3x1
个向量相乘。但是,可以在表示相同点的同时对同质点进行缩放;也就是说,在齐次坐标系中,(kx, ky, k)与(x, y, 1)是同一个点。来自 Wikipedia page on homogeneous coordinates:
Given a point (x, y) on the Euclidean plane, for any non-zero real number Z, the triple (xZ, yZ, Z) is called a set of homogeneous coordinates for the point. By this definition, multiplying the three homogeneous coordinates by a common, non-zero factor gives a new set of homogeneous coordinates for the same point. In particular, (x, y, 1) is such a system of homogeneous coordinates for the point (x, y). For example, the Cartesian point (1, 2) can be represented in homogeneous coordinates as (1, 2, 1) or (2, 4, 2). The original Cartesian coordinates are recovered by dividing the first two positions by the third. Thus unlike Cartesian coordinates, a single point can be represented by infinitely many homogeneous coordinates.
显然,在笛卡尔坐标系中,这种缩放比例不成立; (x, y) 与 (xZ, yZ) 不同,除非 Z = 0或 Z = 1。所以我们需要一种方法来将这些可以用无数种方式表示的齐次坐标映射到只能用一种方式表示的笛卡尔坐标。幸运的是这很容易,只需缩放齐次坐标,所以三元组中的最后一个数字是 1。
单应性乘以齐次坐标和return齐次坐标。所以为了将它们映射回笛卡尔世界,你只需要除以最后一个坐标来缩放它们,然后撕掉前两个数字。
简答
将齐次坐标乘以单应性时,需要对它们进行缩放:
sx' x
sy' = H * y
s 1
所以要回到笛卡尔坐标,将新的齐次坐标除以 s:(sx', sy', s)/s = (x ', y', 1) 然后 (x', y') 就是你要的点数.
较短的答案
使用内置的 OpenCV 函数 convertPointsFromHomogeneous()
将您的点从齐次 3 向量转换为笛卡尔 2 向量。
# convert to world coordinates
def toworld(x,y):
imagepoint = [x, y, 1]
worldpoint = np.array(np.dot(inversehomographymatrix,imagepoint))
scalar = worldpoint[0,2]
xworld = int((worldpoint[0][0]/scalar)*10 +p.x_buffer_width*10)
yworld = int((worldpoint[0][1]/scalar)*10 +p.y_buffer_width*10) #in 10demm
return xworld, yworld
我试图找到变换矩阵 H,以便我可以乘以 (x,y) 像素坐标并获得 (x,y) 真实世界坐标。这是我的代码:
import cv2
import numpy as np
from numpy.linalg import inv
if __name__ == '__main__' :
D=[159.1,34.2]
I=[497.3,37.5]
G=[639.3,479.7]
A=[0,478.2]
# Read source image.
im_src = cv2.imread('/home/vivek/june_14.png')
# Four corners of the book in source image
pts_src = np.array([D,I,G,A])
# Read destination image.
im_dst = cv2.imread('/home/vivek/june_14.png')
# Four corners of the book in destination image.
print "img1 shape:",im_dst.shape
scale=1
O=[0.0,0.0]
X=[134.0*scale,0]
Y=[0.0,184.0*scale]
P=[134.0*scale,184.0*scale]
# lx = 75.5 * scale
# ly = 154.0 * scale
pts_dst = np.array([O,X,P,Y])
# Calculate Homography
h, status = cv2.findHomography(pts_src, pts_dst)
print "homography:",h
print "inv of H:",inv(h)
print "position of the blob on the ground xy plane:",np.dot(np.dot(h,np.array([[323.0],[120.0],[1.0]])),scale)
# Warp source image to destination based on homography
im_out = cv2.warpPerspective(im_src, h, (im_dst.shape[1],im_dst.shape[0]))
# Display images
cv2.imshow("Source Image", im_src)
cv2.imshow("Destination Image", im_dst)
cv2.imshow("Warped Source Image", im_out)
cv2.imwrite("im_out.jpg", im_out)
cv2.waitKey(0)
我得到的全局 xy 非常不正常。我是不是哪里做错了?
长答案
单应性是 3x3
矩阵,而点只是对 2x1
,因此无法将它们映射到一起。相反,使用齐次坐标,给出 3x1
个向量相乘。但是,可以在表示相同点的同时对同质点进行缩放;也就是说,在齐次坐标系中,(kx, ky, k)与(x, y, 1)是同一个点。来自 Wikipedia page on homogeneous coordinates:
Given a point (x, y) on the Euclidean plane, for any non-zero real number Z, the triple (xZ, yZ, Z) is called a set of homogeneous coordinates for the point. By this definition, multiplying the three homogeneous coordinates by a common, non-zero factor gives a new set of homogeneous coordinates for the same point. In particular, (x, y, 1) is such a system of homogeneous coordinates for the point (x, y). For example, the Cartesian point (1, 2) can be represented in homogeneous coordinates as (1, 2, 1) or (2, 4, 2). The original Cartesian coordinates are recovered by dividing the first two positions by the third. Thus unlike Cartesian coordinates, a single point can be represented by infinitely many homogeneous coordinates.
显然,在笛卡尔坐标系中,这种缩放比例不成立; (x, y) 与 (xZ, yZ) 不同,除非 Z = 0或 Z = 1。所以我们需要一种方法来将这些可以用无数种方式表示的齐次坐标映射到只能用一种方式表示的笛卡尔坐标。幸运的是这很容易,只需缩放齐次坐标,所以三元组中的最后一个数字是 1。
单应性乘以齐次坐标和return齐次坐标。所以为了将它们映射回笛卡尔世界,你只需要除以最后一个坐标来缩放它们,然后撕掉前两个数字。
简答
将齐次坐标乘以单应性时,需要对它们进行缩放:
sx' x
sy' = H * y
s 1
所以要回到笛卡尔坐标,将新的齐次坐标除以 s:(sx', sy', s)/s = (x ', y', 1) 然后 (x', y') 就是你要的点数.
较短的答案
使用内置的 OpenCV 函数 convertPointsFromHomogeneous()
将您的点从齐次 3 向量转换为笛卡尔 2 向量。
# convert to world coordinates
def toworld(x,y):
imagepoint = [x, y, 1]
worldpoint = np.array(np.dot(inversehomographymatrix,imagepoint))
scalar = worldpoint[0,2]
xworld = int((worldpoint[0][0]/scalar)*10 +p.x_buffer_width*10)
yworld = int((worldpoint[0][1]/scalar)*10 +p.y_buffer_width*10) #in 10demm
return xworld, yworld