【问题标题】:Transforming captured co-ordinates into screen co-ordinates将捕获的坐标转换为屏幕坐标
【发布时间】:2009-11-06 19:35:10
【问题描述】:

我认为这可能是一道简单的数学题,但我不知道现在发生了什么。

我正在捕获网络摄像头上“标记”的位置,并且我有一个标记列表及其坐标。其中四个标记是工作表面的外角,第五个(绿色)标记是一个小部件。像这样:

以下是一些示例数据:

  • 左上标记(a=98,b=86)
  • 右上角标记(c=119,d=416)
  • 左下标记(e=583,f=80)
  • 右下标记(g=569,h=409)
  • 小部件标记(x=452,y=318)

我想以某种方式将网络摄像头的小部件位置转换为要在屏幕上显示的坐标,其中左上角是 0,0 而不是 98,86,并以某种方式考虑网络摄像头捕获的扭曲角度。

我什至会从哪里开始?任何帮助表示赞赏

【问题讨论】:

  • 您使用什么语言?

标签: math image-processing computer-vision linear-algebra


【解决方案1】:

为了计算扭曲,您需要在输入矩形的四个角和屏幕之间计算homography

由于您的网络摄像头多边形似乎具有任意形状,因此可以使用全透视单应性将其转换为矩形。这并不复杂,您可以使用称为Singular Value Decomposition or SVD 的数学函数(应该很容易获得)来解决它。

背景信息:

对于像这样的平面变换,您可以轻松地用单应性来描述它们,这是一个 3x3 矩阵 H,这样如果您的网络摄像头多边形上或内的任何点,例如 x1 乘以 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),即

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,VT(这样 A = USVT)。与最小奇异值对应的向量为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] 定义了 affine transformation(本质上是缩放和旋转)。
  • 最后一个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.51770/-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)

所以,这是变形后的样子:

如您所见,绿色的+代表变形后的widget点。

注意事项:

  1. article 中有一些很好的图片解释了单应性。
  2. 您可以使用转换矩阵here

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

【讨论】:

  • @jpierson:我已经包含了 MATLAB 代码以及 A 矩阵。
  • @jpierson:抱歉,我好像忘了说如何从V 获取H。我已经更新了我的答案(它在 Computing H 下)。但是该网站上来自 SVD 的V^T 并不十分准确。另外,请记住,这是该网站上V 的转置,而您需要V 的最后一列(而不是转置)。
  • @Jacob:非常好,基于您对 V^T 的原始描述以及我们需要最后一列的事实,我们已经能够让我们的代码大部分工作。我们目前正在使用 C# 和 ALGLIB。
  • @Jacob:非常感谢您的回答。已经有一段时间了,我终于成功了,但不记得如何了!无论如何,结果是惊人的。我可以用一个小手电筒直接在我的屏幕上画画。 :)
  • 您的另一个惊人答案!同样,您链接用于测试广告参考的工具也很棒。 :)
【解决方案2】:

由于透视效果,线性甚至双线性变换可能不够准确。 看看correct perspective mapping 和更多来自谷歌的这句话,可能这就是你需要的......

【讨论】:

  • 虽然Jacob的回答真的很可爱,口齿伶俐,而且有很多工作要做,但他似乎错过了这一点。线性系统只计算仿射或线性变换,而且这种变换显然不是线性的。无论代码多么漂亮,计算正确数字的程序都会更好。我对你的好感,格言。
  • maxim & Die in Sente:当与齐次坐标一起使用时,线性变换给出了正确的答案。您在正确透视映射上的链接说“除以深度 z”,Jacob 说“我们通过第三个元素进行归一化”。
【解决方案3】:

由于您的输入区域不是与屏幕具有相同纵横比的矩形,因此您必须应用某种转换来进行映射。

我要做的是获取内部点相对于外侧的比例,并将其映射到屏幕的相同比例。

为此,请计算内部点上方、下方、左侧和右侧的可用空间量,并使用比率找出该点在屏幕中的位置。

alt text http://img230.imageshack.us/img230/5301/mapkg.png

完成测量后,将内点放置在:

x = left / (left + right)
y = above / (above + below)

这样,无论网络摄像头框架多么倾斜,您仍然可以映射到屏幕上的完整规则矩形。

【讨论】:

  • 这会产生一些奇怪的结果。例如,多边形左边缘的所有点都将映射到屏幕的左上角。
【解决方案4】:

尝试以下操作:用 2 条对角线分割原始矩形和该图形。它们的交叉点是 (k, l)。您有 4 个扭曲的三角形(ab-cd-kl、cd-ef-kl、ef-gh-kl、gh-ab-kl),xy 点位于其中之一。

(4 个三角形优于 2 个,因为失真不取决于所选的对角线)

你需要找出 XY 在哪个三角形点。为此,您只需要 2 次检查:

  1. 检查它是否在 ab-cd-ef 中。如果为真,请继续使用 ab-cd-ef,(在您的情况下不是,所以我们继续使用 cd-ef-gh)。
  2. 我们不检查 cd-ef-gh,但已经检查了一半:cd-gh-kl。重点就在那里。 (否则会是 ef-gh-kl)

这里是 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)

【讨论】:

    【解决方案5】:

    更多如何在 xcode 中的 Objective-c 中执行此操作,与 jacobs 帖子相关,您可以在此处找到:calculate the V from A = USVt in objective-C with SVD from LAPACK in xcode

    【讨论】:

      【解决方案6】:

      “Kabcsh 算法”正是这样做的:它在给定 N 个匹配的位置对的两个空间之间创建一个旋转矩阵。

      http://en.wikipedia.org/wiki/Kabsch_algorithm

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-11-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多