首先,我想给出一个视觉示例来说明我的目标:
(图片来源:https://unsplash.com/photos/pGcqw1ARGyg)
简短问题(tl;dr)
使用HTML5视频和画布,如何执行四点透视变换,以便在画布中呈现仅"电视屏幕"部分的帧?为什么我的实现没有显示正确区域?
关于我所尝试的目标的背景
我正在尝试构建一个网页,其工作方式如下:
- 用户将他们的网络摄像头对准电视,以便它在画面中(但可能是任意角度)
- 使用HTML5视频和画布,捕获网络摄像头并在网页上预览
- 用户能够通过单击预览图来定义电视屏幕的四个角落(4对x / y坐标)
- **使用某种透视变换,扭曲视频,使画布仅显示实际电视屏幕的图像部分(而不是整个网络摄像头视图)**
- 然后对图像进行一些处理(例如,识别最突出的颜色)。这部分超出了本问题的范围,除了指出我最终需要能够访问HTML5画布的内容/像素。
我遇到困难的部分是第4步。为了确保我每帧视频只处理相关部分的图像,重要的是我“扭曲”图像,以便它仅显示“电视屏幕”区域而不是整个网络摄像头图像。
经过一些阅读,我的理解是:
- 这需要一种透视变换,因为网络摄像头可以在任何角度,并且我们不处理平行线,所以需要三维变换,二维变换不够。这是因为二维变换(平移/旋转/缩放/倾斜)无法处理收敛的边缘。
- HTML5画布是二维上下文,因此只支持2D变换,而不支持3D变换。因为我需要一个适用于
canvas
的解决方案,我不能简单地使用3D CSS变换(例如https://developer.mozilla.org/en-US/docs/Web/CSS/transform-function/matrix3d)。这表明WebGL可能更适合我处理3D方面。
我迄今为止尝试过的方法
考虑到这一点,我尝试了以下方法:
a) 使用video
标签捕获网络摄像头
canvas
元素中(以便我可以对生成的画布内容进行图像处理)
c) three.js场景包括:
- 一个平面网格,其中包含使用VideoTexture
在一侧显示视频。
- 一个透视相机,最初的位置是为了显示整个网络摄像头图像。
d) 允许用户单击四个角点来定义他们的电视机所在位置,计算出x/y坐标并保存它们。
e) 计算透视变换,将正确区域“填充框架”。换句话说,将四个点击的“电视机角”点拉伸到视口的四个角。我一直在使用这个库:https://github.com/jlouthan/perspective-transform来计算这个。
f) 我的想法是,如果将适当的变换应用于包含视频的网格,并且相机保持固定位置,则在二维查看输出画布时,该画布将包含所需的图像。
链接到我当前(已损坏)的实现
这是我尝试上述内容的链接。它显示视频并允许您单击四个角落。如果您在原点周围(中心)点击点,则似乎有效,但问题是,如果您选择图像其他位置的区域,则会显示错误的区域。
https://bitbucket.org/mattwilson1024/perspective-transform/src/master/
总结
我非常感谢任何帮助我找出为什么这不像我预期的那样工作,或任何关于是否有更好/更容易实现我所需的方法的指针。