我认为这可能是一个简单的数学问题,但我不知道现在发生了什么。
我正在捕捉网络摄像头上“标记”的位置,我有一个标记列表及其坐标。四个标记是工作表面的外角,第五个(绿色)标记是小部件。像这样:
以下是一些示例数据:
我想以某种方式将网络摄像头的小部件位置转换为坐标以显示在屏幕上,其中左上角是0,0而不是98,86,并以某种方式考虑了网络摄像头捕获的扭曲角度。 / p>
我甚至会从哪里开始?任何帮助表示赞赏
答案 0 :(得分:19)
为了计算变形,您需要在输入矩形的四个角和屏幕之间计算homography。
由于您的网络摄像头多边形似乎具有任意形状,因此可以使用完整的透视单应性将其转换为矩形。它并不复杂,您可以使用称为Singular Value Decomposition or SVD的数学函数(应该很容易获得)来解决它。
背景资料:
对于像这样的平面变换,您可以使用单应性来轻松地描述它们,这是一个3x3矩阵H
,这样,如果您的网络摄像头多边形上或其中的任何点,比如x1
乘以{ {1}},即H
,我们会在屏幕上显示一个点(矩形),即H*x1
。
现在,请注意这些点由它们的齐次坐标表示,这只是添加第三个坐标(其原因超出了本文的范围)。因此,假设您x2
的坐标是X1
,那么齐次表示将是列向量(100,100)
(其中x1 = [100;100;1]
表示新行)。
好的,现在我们有8个同类矢量代表网络摄像头多边形和屏幕的4个角上的4个点 - 这就是我们计算单应性所需的全部内容。
计算单应性:
一点点数学: 我不打算进入数学,但简单来说就是我们如何解决它:
我们知道3x3矩阵;
,
H
可用于通过H =
h11 h12 h13
h21 h22 h23
h31 h32 h33
where hij represents the element in H at the ith row and the jth column
获取新的屏幕坐标。此外,结果将类似于x2 = H*x1
,因此要在屏幕坐标中获取它,我们会将其标准化为第三个元素或x2 = [12;23;0.1]
X2 = (120,230)
。
这意味着这意味着您的网络摄像头多边形((12/0.1,23/0.1)
)中的每个点都可以乘以WP
(然后进行标准化)以获得您的屏幕坐标(H
),即
SC
计算H: (快速无痛的解释)
伪代码:
SC1 = H*WP1
SC2 = H*WP2
SC3 = H*WP3
SC4 = H*WP4
where SCi refers to the ith point in screen coordinates and
WPi means the same for the webcam polygon
一旦你有A,只需计算for n = 1 to 4
{
// WP_n refers to the 4th point in the webcam polygon
X = WP_n;
// SC_n refers to the nth point in the screen coordinates
// corresponding to the nth point in the webcam polygon
// For example, WP_1 and SC_1 is the top-left point for the webcam
// polygon and the screen coordinates respectively.
x = SC_n(1); y = SC_n(2);
// A is the matrix which we'll solve to get H
// A(i,:) is the ith row of A
// Here we're stacking 2 rows per point correspondence on A
// X(i) is the ith element of the vector X (the webcam polygon coordinates, e.g. (120,230)
A(2*n-1,:) = [0 0 0 -X(1) -X(2) -1 y*X(1) y*X(2) y];
A(2*n,:) = [X(1) X(2) 1 0 0 0 -x*X(1) -x*X(2) -x];
}
,它会将它分解为 U,S,V T (这样 A = USV Ť 的)。对应于最小奇异值的向量是svd(A)
(一旦将其重新整形为3x3矩阵)。
使用H
,您可以通过将其与H
相乘并进行规范化来检索小部件标记位置的“扭曲”坐标。
示例:强>
在您的特定示例中,如果我们假设您的屏幕尺寸为800x600,
H
然后我们得到:
WP =
98 119 583 569
86 416 80 409
1 1 1 1
SC =
0 799 0 799
0 0 599 599
1 1 1 1
where each column corresponds to corresponding points.
同样,我不会进入数学,但如果我们将H =
-0.0155 -1.2525 109.2306
-0.6854 0.0436 63.4222
0.0000 0.0001 -0.5692
标准化为H
,即在上面的示例中将h33
中的每个元素除以H
,
-0.5692
这让我们对转型有了很多了解。
H =
0.0272 2.2004 -191.9061
1.2042 -0.0766 -111.4258
-0.0000 -0.0002 1.0000
定义点数的转换(以像素为单位)[-191.9061;-111.4258]
定义affine transformation(实质上是缩放和旋转)。 [0.0272 2.2004;1.2042 -0.0766]
是因为我们缩放1.0000
和H
表示网络摄像头多边形的投影转换。此外,您可以检查[-0.0000 -0.0002]
是否准确我的乘以H
并将每列归一化为最后一个元素:
SC = H*WP
按每个列的最后一个元素(例如,第2列,SC = H*WP
0.0000 -413.6395 0 -411.8448
-0.0000 0.0000 -332.7016 -308.7547
-0.5580 -0.5177 -0.5554 -0.5155
和-413.6395/-0.5177
)划分每列:
0/-0.5177
这是期望的结果。
小组件坐标:
现在,您的窗口小部件坐标也可以转换为SC
-0.0000 799.0000 0 799.0000
0.0000 -0.0000 599.0000 599.0000
1.0000 1.0000 1.0000 1.0000
,(规范化后为H*[452;318;1]
。
所以,这就是翘曲后的样子:
如您所见,绿色(561.4161,440.9433)
表示变形后的小部件点。
备注:强>
+
WP =[
98 119 583 569
86 416 80 409
1 1 1 1
];
SC =[
0 799 0 799
0 0 599 599
1 1 1 1
];
A = zeros(8,9);
for i = 1 : 4
X = WP(:,i);
x = SC(1,i); y = SC(2,i);
A(2*i-1,:) = [0 0 0 -X(1) -X(2) -1 y*X(1) y*X(2) y];
A(2*i,:) = [X(1) X(2) 1 0 0 0 -x*X(1) -x*X(2) -x];
end
[U S V] = svd(A);
H = transpose(reshape(V(:,end),[3 3]));
H = H/H(3,3);
答案 1 :(得分:2)
由于透视效应,线性或甚至双线性变换可能不够准确。 从谷歌看这个短语的correct perspective mapping以及更多,可能这就是你需要的......
答案 2 :(得分:0)
由于您的输入区域不是与屏幕具有相同宽高比的矩形,因此您必须应用某种转换来进行映射。
我要做的是取内部点相对于外侧的比例,并将其映射到屏幕的相同比例。
为此,计算内点上方,下方,左侧和右侧的自由空间量,并使用该比率找出屏幕中该点的位置。
alt text http://img230.imageshack.us/img230/5301/mapkg.png
完成测量后,将内点放在:
x = left / (left + right)
y = above / (above + below)
这样,无论网络摄像头框架有多么歪斜,您仍然可以在屏幕上映射到完整的常规矩形。
答案 3 :(得分:0)
请尝试以下操作:将原始矩形和此图分割成2个对角线。他们的交叉是(k,l)。你有4个扭曲的三角形(ab-cd-kl,cd-ef-kl,ef-gh-kl,gh-ab-kl),点xy就在其中一个中。
(4个三角形优于2个,因为失真不依赖于所选择的对角线)
您需要找到XY所在的三角形点。要做到这一点,你只需要2次检查:
这里是an excellent algorythm来检查点是否在多边形中,仅使用它的点。
现在您只需要将点映射到原始三角形cd-gh-kl。点xy是3个点的线性组合:
x = c * a1 + g * a2 + k * (1 - a1 - a2)
y = d * a1 + h * a2 + l * (1 - a1 - a2)
a1 + a2 <= 1
2个变量(a1,a2),包含2个方程式。我想你可以自己推导出解决方案。
然后,您只需将a1和a2与原始矩形中对应点的坐标进行线性组合。在这种情况下,W(宽度)和H(高度)是
X = width * a1 + width * a2 + width / 2 * (1 - a1 - a2)
Y = 0 * a1 + height * a2 + height / 2 * (1 - a1 - a2)
答案 4 :(得分:0)
更多如何在xcode中的objective-c中执行此操作,与jacobs post相关,您可以在此处找到:calculate the V from A = USVt in objective-C with SVD from LAPACK in xcode
答案 5 :(得分:0)
“Kabcsh算法”就是这样做的:它在给定N对匹配位置的两个空间之间创建一个旋转矩阵。