为了计算翘曲,您需要计算输入矩形的四个角与屏幕之间的单应性。
由于您的网络摄像头多边形似乎具有任意形状,因此可以使用全透视单应性将其转换为矩形。它并不复杂,您可以使用称为奇异值分解或 SVD的数学函数(应该很容易获得)来解决它。
背景资料:
对于像这样的平面变换,您可以轻松地用单应性来描述它们,这是一个 3x3 矩阵H
,这样如果网络摄像头多边形上或网络中的任何点x1
乘以H
,即H*x1
,我们将在屏幕上得到一个点(矩形) ,即x2
。
现在,请注意,这些点由它们的齐次坐标表示,这只不过是添加了第三个坐标(其原因超出了本文的范围)。所以,假设你的坐标X1
是(100,100)
,那么齐次表示将是一个列向量x1 = [100;100;1]
(其中;
表示一个新行)。
好的,所以现在我们有 8 个齐次向量,代表网络摄像头多边形上的 4 个点和屏幕的 4 个角——这就是我们计算单应性所需的全部内容。
计算单应性:
一点数学:
我不打算进入数学,但简而言之,这是我们解决它的方法:
我们知道 3x3H
矩阵
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)
which is对其进行规范化(12/0.1,23/0.1)
。
因此,这意味着您的网络摄像头多边形(WP
)中的每个点都可以乘以H
(然后归一化)以获得您的屏幕坐标(SC
),即
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
计算 H:(快速无痛的解释)
伪代码:
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];
}
一旦你有了 A,只需计算svd(A)
哪个会将它分解为U,S,V T(使得A = USV T)。对应于最小奇异值的向量是H
(一旦你把它重塑成一个 3x3 矩阵)。
使用H
,您可以通过将其乘以H
并归一化来检索小部件标记位置的“扭曲”坐标。
例子:
在您的特定示例中,如果我们假设您的屏幕尺寸为 800x600,
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]
定义点的平移(以像素为单位)
[0.0272 2.2004;1.2042 -0.0766]
定义仿射变换(本质上是缩放和旋转)。
- 最后一个
1.0000
之所以如此,是因为我们按比例缩放H
了
[-0.0000 -0.0002]
表示网络摄像头多边形的投影变换。
此外,您可以检查我将每列与最后一个元素H
相乘和规范化是否准确:SC = H*WP
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
将每一列除以它的最后一个元素(例如,在第 2 列-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)
.
所以,这是扭曲后的样子:
![翘曲](https://imgur.com/QLNDQ.png)
如您所见,绿色+
代表变形后的小部件点。
笔记:
- 这篇文章中有一些很好的图片来解释单应性。
- 你可以在这里玩转换矩阵
MATLAB 代码:
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);
一个
0 0 0 -98 -86 -1 0 0 0
98 86 1 0 0 0 0 0 0
0 0 0 -119 -416 -1 0 0 0
119 416 1 0 0 0 -95081 -332384 -799
0 0 0 -583 -80 -1 349217 47920 599
583 80 1 0 0 0 0 0 0
0 0 0 -569 -409 -1 340831 244991 599
569 409 1 0 0 0 -454631 -326791 -799