如何使用HTML5画布和three.js实现四点透视变换?

8

首先,我想给出一个视觉示例来说明我的目标:

example

(图片来源:https://unsplash.com/photos/pGcqw1ARGyg

简短问题(tl;dr)

使用HTML5视频和画布,如何执行四点透视变换,以便在画布中呈现仅"电视屏幕"部分的帧?为什么我的实现没有显示正确区域?

关于我所尝试的目标的背景

我正在尝试构建一个网页,其工作方式如下:

  1. 用户将他们的网络摄像头对准电视,以便它在画面中(但可能是任意角度)
  2. 使用HTML5视频和画布,捕获网络摄像头并在网页上预览
  3. 用户能够通过单击预览图来定义电视屏幕的四个角落(4对x / y坐标)
  4. **使用某种透视变换,扭曲视频,使画布仅显示实际电视屏幕的图像部分(而不是整个网络摄像头视图)**
  5. 然后对图像进行一些处理(例如,识别最突出的颜色)。这部分超出了本问题的范围,除了指出我最终需要能够访问HTML5画布的内容/像素。

我遇到困难的部分是第4步。为了确保我每帧视频只处理相关部分的图像,重要的是我“扭曲”图像,以便它仅显示“电视屏幕”区域而不是整个网络摄像头图像。

经过一些阅读,我的理解是:

  • 这需要一种透视变换,因为网络摄像头可以在任何角度,并且我们不处理平行线,所以需要三维变换,二维变换不够。这是因为二维变换(平移/旋转/缩放/倾斜)无法处理收敛的边缘。
  • HTML5画布是二维上下文,因此只支持2D变换,而不支持3D变换。因为我需要一个适用于canvas的解决方案,我不能简单地使用3D CSS变换(例如https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix3d)。这表明WebGL可能更适合我处理3D方面。

我迄今为止尝试过的方法

考虑到这一点,我尝试了以下方法:

a) 使用video标签捕获网络摄像头

b) 使用three.js创建一个3D场景,将其渲染到canvas元素中(以便我可以对生成的画布内容进行图像处理) c) three.js场景包括: - 一个平面网格,其中包含使用VideoTexture在一侧显示视频。 - 一个透视相机,最初的位置是为了显示整个网络摄像头图像。 d) 允许用户单击四个角点来定义他们的电视机所在位置,计算出x/y坐标并保存它们。 e) 计算透视变换,将正确区域“填充框架”。换句话说,将四个点击的“电视机角”点拉伸到视口的四个角。我一直在使用这个库:https://github.com/jlouthan/perspective-transform来计算这个。 f) 我的想法是,如果将适当的变换应用于包含视频的网格,并且相机保持固定位置,则在二维查看输出画布时,该画布将包含所需的图像。

链接到我当前(已损坏)的实现

这是我尝试上述内容的链接。它显示视频并允许您单击四个角落。如果您在原点周围(中心)点击点,则似乎有效,但问题是,如果您选择图像其他位置的区域,则会显示错误的区域。

https://bitbucket.org/mattwilson1024/perspective-transform/src/master/

总结

我非常感谢任何帮助我找出为什么这不像我预期的那样工作,或任何关于是否有更好/更容易实现我所需的方法的指针。

1个回答

9
原始实现存在问题,问题在于创建transformMatrix的方式。通过改变以下内容,我成功地使其工作:
transformMatrix.set(a1, a2, a3, 0, 
                    b1, b2, b3, 0, 
                    c1, c2, c3, 0, 
                    0,  0,  0,  1);

转换为:

transformMatrix.set(a1, a2, 0, a3, 
                    b1, b2, 0, b3, 
                    0,  0,  0, 1, 
                    c1, c2, 0, c3);

这个数学StackExchange网站上的答案对解决问题很有帮助。

为了方便未来任何人寻找此问题,我已更新原始问题,使其指向包含错误代码的存档分支。可以在这里找到工作版本。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接