去年夏天,我曾在 NASA Glenn 的 GVIS 实验室实习,在那里我将我对开源的热情带入了实验室。我的任务是改进我们实验室对 Dan Schroeder 开发的开源流体动力学模拟的贡献。最初的 simulation 展示了用户可以使用鼠标绘制的障碍物,以模拟计算流体动力学。我的团队通过添加图像处理代码做出了贡献,该代码分析实时视频流的每一帧,以显示物理对象如何与流体相互作用。但是,我们还有更多的事情要做。
我们希望使图像处理更加稳健,因此我致力于改进图像处理库。
使用新的库,模拟将能够检测轮廓、就地执行坐标变换并找到物体的质心。图像处理与流体动力学模拟的物理特性没有直接关系。它使用相机检测物体,并通过获取物体的轮廓为流体流动模拟创建障碍。然后,流体流动模拟运行,输出投影到实际物体上。
我的目标是以三种方式改进模拟
- 找到物体的精确轮廓
- 找到物体的质心
- 能够围绕物体的中心执行精确的变换
我的导师建议我安装 Node.js、OpenCV 和 Node.js bindings for OpenCV。在等待安装这些软件时,我查看了 GitHub page 页面上 OpenCV bindings 的示例代码。我发现示例代码是用 JavaScript 编写的,因为我不懂 JavaScript,所以我开始在 Codecademy 上学习一门简短的课程。两天后,我厌倦了 JavaScript,但准备开始我的项目了...... 这涉及到更多的 JavaScript。
示例轮廓查找代码运行良好。事实上,它让我在几个小时内就实现了我的第一个目标!要获取图像的轮廓,它看起来是这样的
包含所有轮廓的原始图像。
示例轮廓查找代码运行得有点太好了。不是检测到物体的轮廓,而是检测到图像中所有的轮廓。这将导致模拟与所有不需要的轮廓进行交互。这是一个问题,因为它会返回不正确的数据。为了防止模拟与不需要的轮廓进行交互,我添加了一个面积约束。如果轮廓在某个面积范围内,则会绘制该轮廓。面积约束产生了更清晰的轮廓。
带有阴影轮廓的过滤轮廓。
尽管未检测到无关的轮廓,但图像仍然存在问题。图像中只有一个轮廓,但它自身折回并且不完整。面积不能成为这里的决定性因素,所以是时候尝试其他方法了。
这一次,我没有立即查找轮廓,而是首先将图像转换为二值图像。二值图像是每个像素为黑色或白色的图像。为了获得二值图像,我首先将彩色图像转换为灰度图像。一旦图像变为灰度图像,我就对图像调用了阈值方法。阈值方法逐像素地遍历图像,如果像素的颜色值小于 30,则像素颜色将变为黑色。否则,像素值将变为白色。原始图像转换为二值图像后,结果图像如下所示
二值图像。
然后我从二值图像中获得了轮廓,这产生了更清晰的轮廓,没有阴影轮廓。
最终的清晰轮廓。
此时,我已经能够获得清晰的轮廓并检测质心。不幸的是,我没有足够的时间来完成围绕质心的变换。由于我的实习只剩下几天了,我开始考虑在有限的时间范围内我可以做的其他事情。其中一件事是外接矩形。外接矩形是包含图像整个轮廓的最小面积的四边形。外接矩形很重要,因为它是缩放页面上轮廓的关键。不幸的是,我没有时间对外接矩形做太多事情,但我仍然想了解它,因为它是一个有用的工具。
最后,经过这一切,我终于完成了图像处理!
最终图像,外接矩形和质心以红色显示。
图像处理代码完成后,我用我的代码替换了模拟中旧的图像处理代码。令我惊讶的是,它奏效了!
嗯,大部分是。
该程序存在内存泄漏,每 1/10 秒泄漏 100MB 内存。我很高兴这不是因为我的代码。糟糕的是,修复它超出了我的控制范围。好消息是,我可以找到一个解决方法。它不太理想,但它可以检查模拟正在使用的内存量,当它使用超过 1 GiB 时,模拟会重新启动。
在 NASA 实验室,我们使用大量的开源软件,没有它,我的工作是不可能完成的。
2 条评论