作者:Chad Hart(原文链接)
翻译:刘通
原标题:Computer Vision on the Web with WebRTC and TensorFlow
前文连接:利用WebRTC和TensorFlow通过网络实现计算机视觉1
代码走查
第1部分——确保Tensorflow正常工作
为确保TensorFlow对象检测API正常工作,我们首先从用于演示对象检测的官方版Jupyter Notebook经调整后的版本着手。我将此文件保存为object_detection_tutorial.py。
如果您剪切并粘贴该notebook的每个部分,得到的结果应如下所示:
在这里我就不再赘述实际TensorFlow代码的作用了,这方面的信息可在Jupyter演示及其他教程中找到。我将重点介绍我们对代码所做的修改。
我们不需要的内容
我注释掉了几个小节:
- 更改了一些位置引用
- 删除了对Python matplot的所有引用。Python matplot用于在GUI环境中以可视化方式呈现输出结果。在我的Docker环境中没有设置它——根据您采用的具体运行方式,可以酌情决定是否保留这些引用。
对象检测API的输出结果
正如第111行所示,对象检测API输出4种对象:
- 类——一个由对象名组成的数组
- 分值——一个由置信度分值组成的数组
- 方框——检测到的每个对象所在的位置
- 数量——检测到的对象总数
类、分值和方框都是相互并列、大小相等的数组,因此classes[n]与scores[n]和boxes[n]都是一一对应的。
由于我删去了可视化功能,我们需要通过某种方式来查看结果,所以我们要把下面的命令添加到文件末尾:
第一个np.squeeze部分只是将多维数组输出缩减成一维,这与原来的可视化代码一样。我认为这是TensorFlow的一个副产品,因为它通常会输出多维数组。
接着我们要为它输出的分值设置一个阈值。好像TensorFlow默认会返回100个对象。其中很多对象嵌套在置信度更高的对象内或与这些对象重叠。在选择阈值方面我还没有发现任何最佳做法,不过对于这些示例图像来说,50%似乎是合适的。
最后,我们需要循环遍历这些数组,直接输出那些超过阈值的分值。
如果您运行下面的命令:
应该会获得下面的输出:
第2部分——打造一项对象API网络服务
在这一部分,我们将对教程代码作一些改动,以将其作为一项网络服务加以运行。我在Python方面的经验颇为有限(主要在Raspberry Pi项目中使用过),所以如有不对的地方,请添加备注或提交拉取请求,以便我可以修正。
2.1 将演示代码转变成一项服务
至此我们已经让TensorFlow Object API能够正常工作了,接下来我们就将它封装成一个可以调用的函数。我将演示代码复制到了一个名为object_detection_api.py的新python文件中。您可以看到,我删除了很多没有用到或注释掉的行,以及用于将详细信息输出到控制台的部分(暂时删除)。
由于我们要将这些信息输出到网络上,因此最好将我们的输出结果封装成一个JSON对象。为此,请务必向您导入的内容中添加一个import jso语句,然后再添加下面的命令:
接下来,我们要重复利用之前的代码创建一个get_objects函数:
在此函数中我们添加了一个图像输入参数和一个默认为0.5的threshold值。其余内容都是在演示代码的基础上重构的。
现在我们再向此函数添加一些代码,以查询具体的值并将它们输出到一个JSON对象中:
这一次我们是使用Object类来创建一些初始元数据并将这些元数据添加到output列表中。然后我们使用循环向此列表中添加Object数据。最后,将此列表转换成JSON并予以返回。
之后,我们来创建一个测试文件(这里要提醒自己:先做测试),以检查它是否调用了object_detection_test.py:
至此万事俱备,接下来就是运行了。
除了前面的控制台输出之外,您应该还会看到一个JSON字符串:
2.2 添加一个网络服务器
我们已经有了函数——接下来我们就用它来打造一项网络服务。
先使用测试用的路由(Route)运行
我们有了一个可以轻松添加到网络服务的良好API。我发现使用Flask是最简单的测试方法。我们来创建一个server.py,然后执行一次快速测试:
现在,运行该服务器:
确保该服务正常工作
然后调用该网络服务。就我自己的情况而言,我只是从主机运行了下面的命令(因为我的Docker实例现在正在前台运行该服务器):
json.tool将帮助您为输出结果设置格式。您应该会看到下面的结果:
好了,接下来我们就要接受一个包含一个图片文件及其他一些参数的POST,使用真实路由运行了。为此,需要在/test路由函数下添加一个新的/image路由:
这样就会从一个采用表单编码方式的POST中获取图片,并且可以选择指定一个阈值,然后将该图片传递给我们的object_detection_api。
我们来测试一下:
这时看到的结果应该与上面使用/test路径时相同。继续测试,可以指定您任选的其他本地图像的路径。
让该服务在localhost以外的位置也能正常工作
如果您打算在localhost上运行浏览器,可能就不需要再做些什么。但如果是真实的服务,甚至是在需要运行很多测试的情况下,这就不太现实了。如果要跨网络运行网络服务,或者使用其他资源运行网络服务,都需要用到CORS。幸好,在路由前添加以下代码就可以轻松解决这一问题:
让该服务支持安全源
最佳做法是搭配HTTPS使用WebRTC,因为Chrome和Safari等浏览器若不作专门配置,则仅支持安全源(不过Chrome可以很好地支持localhost,您也可以将Safari设为允许在非安全网站上捕获信息——跳转到此处的调试工具部分了解详情)。为此,您需要获取一些SSL证书或生成一些自托管证书。我将我自己的证书放在了ssl/目录中,然后将最后一行app.run更改为:
如果您使用的是自签名证书,您在使用CURL进行测试时可能需要添加–insecure选项:
严格来讲并非一定要生成您自己的证书,而且这会增加一定的工作量,所以在server.py最底部,我依然让SSL版本保持被注释掉的状态。
如果是要投入生产环境中使用的应用程序,您可能需要使用nginx之类的代理向外发送HTTPS,同时在内部依然使用HTTP(此外还要做很多其他方面的改进)。
添加一些路由以便提供我们的网页
在开始介绍浏览器端的工作之前,我们先为后面需要用到的一些路由生成存根。为此,请将下面的代码放在index()路由后面:
Python方面的工作到此就结束了。接下来我们将用到JavaScript,并且需要编写一些HTML。