我有一组非网格对齐的输入值与网格对齐的输出值相关联。给定一个新的输入值,我想找到输出:
(这些是X,Y坐标,将不精确的非方形眼动追踪输入设备校准到屏幕上的确切位置。)
这看起来像Bilinear Interpolation,但我的输入值不是网格对齐的。给定输入,我如何计算出合理的输出值?
答案:在这种情况下,我有输入和输出点集,实际需要的是执行inverse bilinear interpolation来查找输入点内的U,V坐标。四,然后使用那些U,V坐标在输出四边形上执行正常的双线性插值(如下面Nico的答案所述)。
答案 0 :(得分:10)
你可以在任何凸四边形中进行双线性插值。笛卡尔网格稍微简单一些,因为插值参数的计算是微不足道的。在一般情况下,您插入如下:
parameters alpha, beta
interpolated value = (1 - alpha) * ((1 - beta) * p1 + beta * p2) + alpha * ((1 - beta) * p3 + beta * p4)
为了计算参数,您必须求解方程组。将您的输入值放在p1
到p4
的位置,然后求解alpha
和beta
。
然后将输出值放在p1
到p4
的位置,并使用计算出的参数计算最终插值输出值。
对于常规网格,参数计算归结为:
alpha = x / cell width
beta = y / cell height
自动解决方程式。
以下是alpha=0.3
和beta=0.6
实际上,方程式可以通过分析求解。然而,公式非常难看。因此,迭代方法可能更好。方程组有两种解决方案。您需要选择两个参数都在[0,1]中的解决方案。
第一个解决方案:
alpha = -(b e - a f + d g - c h + sqrt(-4 (c e - a g) (d f - b h) +
(b e - a f + d g - c h)^2))/(2 c e - 2 a g)
beta = (b e - a f - d g + c h + sqrt(-4 (c e - a g) (d f - b h) +
(b e - a f + d g - c h)^2))/(2 c f - 2 b g)
其中
a = -p1.x + p3.x
b = -p1.x + p2.x
c = p1.x - p2.x - p3.x + p4.x
d = center.x - p1.x
e = -p1.y + p3.y
f = -p1.y + p2.y
g = p1.y - p2.y - p3.y + p4.y
h = center.y - p1.y
第二个解决方案:
alpha = (-b e + a f - d g + c h + sqrt(-4 (c e - a g) (d f - b h) +
(b e - a f + d g - c h)^2))/(2 c e - 2 a g)
beta = -((-b e + a f + d g - c h + sqrt(-4 (c e - a g) (d f - b h) +
(b e - a f + d g - c h)^2))/( 2 c f - 2 b g))
答案 1 :(得分:2)
这是我自己的技术,以及用于派生结果值的代码。它需要三个lerps输出值(以及三个百分比计算来确定lerp百分比):
请注意,这不是双线性插值。它不会将输入点的四边形重新映射到输出值的四边形,因为某些输入点可能会导致输出四边形之外的输出值强>
这里我展示了笛卡尔平面上的非对齐输入值(使用上面问题的样本输入值,为简单起见,乘以10)。
要计算“北”点(顶部绿点),我们计算X轴上的百分比为
(inputX - northwestX) / (northeastX - northwestX)
= (-4.2 - -19) / (10 - -19)
= 0.51034
我们使用这个百分比通过在前Y值之间进行计算来计算Y轴的截距:
(targetValue - startValue) * percent + startValue
= (northeastY - northwestY) * percent + northwestY
= (-8 - -7) * 0.51034 + -7
= -7.51034
我们在'南'边做同样的事情:
(inputX - southwestX) / (southeastX - southwestX)
= (-4.2 - -11) / (9 - -11)
= 0.34
(southeastY - southwestY) * percent + southwestY
= (7 - 4) * 0.34 + 4
= 5.02
最后,我们使用这两个值来计算北边和南边之间的最终百分比:
(inputY - southY) / (northY - southY)
= (1 - 5.02) / (-7.51034 - 5.02)
= 0.3208
有了这三个百分比,我们可以通过点之间的计算来计算我们的最终输出值:
nw = Vector(-150,-100)
ne = Vector( 150,-100)
sw = Vector(-150, 100)
se = Vector( 150, 100)
north = lerp( nw, ne, 0.51034) --> ( 3.10, -100.00)
south = lerp( sw, se, 0.34) --> (-48.00, 100.00)
result = lerp( south, north, 0.3208) --> (-31.61, 35.84)
最后,这是执行上述操作的一些(Lua)代码。它使用一个可变的Vector对象,该对象支持从另一个向量复制值并将其值转向另一个向量的能力。
-- Creates a bilinear interpolator
-- Corners should be an object with nw/ne/sw/se keys,
-- each of which holds a pair of mutable Vectors
-- { nw={inp=vector1, out=vector2}, … }
function tetragonalBilinearInterpolator(corners)
local sides = {
n={ pt=Vector(), pts={corners.nw, corners.ne} },
s={ pt=Vector(), pts={corners.sw, corners.se} }
}
for _,side in pairs(sides) do
side.minX = side.pts[1].inp.x
side.diff = side.pts[2].inp.x - side.minX
end
-- Mutates the input vector to hold the result
return function(inpVector)
for _,side in pairs(sides) do
local pctX = (inpVector.x - side.minX) / side.diff
side.pt:copyFrom(side.pts[1].inp):lerp(side.pts[2].inp,pctX)
side.inpY = side.pt.y
side.pt:copyFrom(side.pts[1].out):lerp(side.pts[2].out,pctX)
end
local pctY = (inpVector.y-sides.s.inpY)/(sides.n.y-sides.s.inpY)
return inpVector:copyFrom(sides.s.pt):lerp(sides.n.pt,pctY)
end
end
local interp = tetragonalBilinearInterpolator{
nw={ inp=Vector(-19,-7), out=Vector(-150,-100) },
ne={ inp=Vector( 10,-8), out=Vector( 150,-100) },
sw={ inp=Vector(-11, 4), out=Vector(-150, 100) },
se={ inp=Vector( 9, 7), out=Vector( 150, 100) }
}
print(interp(Vector(-4.2, 1))) --> <-31.60 35.84>