假设img0 包含您要定位的目标,而img1、img2、img3 的目标位置分别为(x1, y1)、(x2, y2)、(x3, y3)。如果您知道所有图像对之间的单应性(例如,H1、H2 和 H3 是从 img1、img2 和 img3 到 img0 的单应性),那么您可以只需将这些像素位置乘以单应性即可获得img0 中的估计坐标。您不能精确地进行三角测量,但是您可以从所有三个图像和单应性中找到估计的变形点,然后取平均值,或者根据您的喜好组合它们,这应该会给您一个很好的估计,只要您的单应性是准确的够了。
单应矩阵是 3x3 矩阵,您的点是 2 向量。为了应用您的变换(或将矩阵和向量相乘),您需要齐次坐标;您的积分格式为(x, y, 1)。然后,要从img1 中获取像素在img0 中的位置,乘法如下:
[s*x0] [x1] [h00 h01 h02] [x1]
[s*y0] = H1 * [y1] = [h10 h11 h12] * [y1]
[s ] [ 1] [h20 h21 h22] [ 1]
您的输出将是一个向量,但不是同质的。结果点将有一个比例因子s;除以s 以获得您的最终坐标(x0, y0)。只需对您拥有的三个目标位置和那些相应的单应性执行此操作,您最终将得到三个估计位置,然后您可以对它们进行平均。
完整示例。
这是使用带有地面实况数据的一些图像,可用here。
Here's my results.
通过了解其他三个中的位置以及数据集中给出的地面实况单应性,在第一张图像中估计出鸡眼中间的十字位置。我输出了每个单应性的估计值、它们的平均值和四舍五入的像素值,结果证明四舍五入的估计像素值是准确的(因为单应性非常准确)。
Estimations:
2 -> 1: [ 527.15670903 222.57196904]
3 -> 1: [ 527.21339222 221.86819147]
4 -> 1: [ 527.63122722 222.30614892]
Avg loc: [ 527.33377616 222.24876981]
Est loc: [527 222]
True loc: [527 222]
这是一个完整的编码示例,只需从该数据集中下载图像并将其弹出到该文件夹中的脚本中并运行。
import numpy as np
import cv2
# read images, taken from http://kahlan.eps.surrey.ac.uk/featurespace/web/
img1 = cv2.imread("img1.png", 1)
img2 = cv2.imread("img2.png", 1)
img3 = cv2.imread("img3.png", 1)
img4 = cv2.imread("img4.png", 1)
# true locations of the chicken's crossed eye (labeled myself)
loc1 = np.array([527, 222, 1])
loc2 = np.array([449, 241, 1])
loc3 = np.array([476, 275, 1])
loc4 = np.array([385, 236, 1])
# define ground truth homographies, also from http://kahlan.eps.surrey.ac.uk/featurespace/web/
H12 = np.array([
[8.7976964e-01, 3.1245438e-01, -3.9430589e+01],
[-1.8389418e-01, 9.3847198e-01, 1.5315784e+02],
[1.9641425e-04, -1.6015275e-05, 1.0000000e+00]])
H13 = np.array([
[7.6285898e-01, -2.9922929e-01, 2.2567123e+02],
[3.3443473e-01, 1.0143901e+00, -7.6999973e+01],
[3.4663091e-04, -1.4364524e-05, 1.0000000e+00]])
H14 = np.array([
[6.6378505e-01, 6.8003334e-01, -3.1230335e+01],
[-1.4495500e-01, 9.7128304e-01, 1.4877420e+02],
[4.2518504e-04, -1.3930359e-05, 1.0000000e+00]])
# need the homographies going the other direction
H21 = np.linalg.inv(H12)
H31 = np.linalg.inv(H13)
H41 = np.linalg.inv(H14)
# ensure they are homogeneous by dividing by the last entry
H21 = H21/H21[-1,-1]
H31 = H31/H31[-1,-1]
H41 = H41/H41[-1,-1]
# warp the locations loc2, loc3, loc4 to the coordinates of img1
est21 = np.matmul(H21, loc2)
est31 = np.matmul(H31, loc3)
est41 = np.matmul(H41, loc4)
# make homogeneous, toss the final 1
est21 = est21[:-1]/est21[-1]
est31 = est31[:-1]/est31[-1]
est41 = est41[:-1]/est41[-1]
# remove the last coordinate, take an average
avgest = (est21 + est31 + est41)/3
estloc = np.around(avgest).astype(int)
# output
print("Estimations:"
"\n2 -> 1: ", est21,
"\n3 -> 1: ", est31,
"\n4 -> 1: ", est41,
"\nAvg loc: ", avgest,
"\nEst loc: ", estloc,
"\nTrue loc: ", loc1[:-1])
# show images
cv2.circle(img1, (estloc[0], estloc[1]), 2, (0,0,255), -1) # filled
cv2.circle(img1, (estloc[0], estloc[1]), 20, (255,255,255)) # outline
cv2.imshow('img1-est', img1)
cv2.waitKey(0)
cv2.circle(img2, (loc2[0], loc2[1]), 2, (0,0,255), -1) # filled
cv2.circle(img2, (loc2[0], loc2[1]), 20, (255,255,255)) # outline
cv2.imshow('img2-loc', img2)
cv2.waitKey(0)
cv2.circle(img3, (loc3[0], loc3[1]), 2, (0,0,255), -1) # filled
cv2.circle(img3, (loc3[0], loc3[1]), 20, (255,255,255)) # outline
cv2.imshow('img3-log', img3)
cv2.waitKey(0)
cv2.circle(img4, (loc4[0], loc4[1]), 2, (0,0,255), -1) # filled
cv2.circle(img4, (loc4[0], loc4[1]), 20, (255,255,255)) # outline
cv2.imshow('img4-log', img4)
cv2.waitKey(0)
cv2.destroyAllWindows()