0%

记一次当乙方的经历

给阳光电源提供噪声过滤的接口及实现的经历

我导接到了一个来自阳光电源的企业横向项目。我正好负责其中的关于传统图像处理的部分,涉及到图像分割分类和对掩模噪声过滤这两部分。几次会议交流下来,掩模噪声过滤这部分已经基本实现,达到了企业的要求,于是企业方要我提供对应的接口与实现以便后续部署在他们的服务器上。然后,这段奇妙的经历正式开始...

0x0 前言----一念之差埋下的祸根

整个任务的流程大致是SIFT+聚类+匹配(实际上复杂得多得多,这里只列出每个子流程中最重要的一个环节)。

在某一阶段的任务完成后,我发现代码如果全用python实现的话,里面有不少for循环,而python的for循环又是出了名的慢。所以想着闲着也是闲着,不如把这些完全基于OpenCV的python代码拿C++重构了(看来是真的闲)。殊不知,一个大坑就在这次重构中被埋下了...

重构后的代码果然快了很多(提升3倍左右,opencv-python本身也是调的C++库代码,主要优化的部分是函数调用开销和庞大的for循环)。但是,代价是:项目使用了python和C++两种语言,且两者之间是强耦合

0x1 伊始----逐步离谱的开发过程

当我真正领到要把之前的所有代码整理成可用的库并提供简单的接口这项任务的时候,其实我还是比较懵逼的。

因为他们的意思感觉就是打算直接把我写的库改叭改叭就直接部署在服务器上了(起码我当时是这么认为的)。这着实让我有点惊慌:

  • 一是我担心我的代码出问题,而且一般公司应该都有一些代码规范啥的,我写的肯定不符合他们的规范(废话,我甚至连他们公司的代码规范都没读过),他们肯定也不太会做code review之类的
  • 二是,我之前开发的代码都是一些原型代码,不涉及日志记录、强大的异常处理还有错误恢复等等鲁棒性措施(如果他们打算加进去又得code review,而code review又会遇到我的代码不合规范的问题)。

还有一点,他们给的deadline还是相对比较紧的。我写的代码在本地环境能跑,但是想要打包成一个对于不同架构下开箱即用的库,难度还是比较大的。(更何况是代码涉及到python和C++两种语言)。

但无论如何,都得继续进行下去。为了增强代码的可读性,我还得对python那部分代码进行重构(主要是任务是随着每次会议进行逐步增加,就慢慢变成衣驼使了...)

0x2 挣扎----在坑里陷得越来越深

当我从重构深渊中爬出来的时候,我需要真正开始思考如何提供一个能够在不同系统上开箱即用的库了

其实关于python代码那部分不太考虑太多,python跨平台性能还是很强的。按照道理来说确实是这样,但是,他们公司有的图片实在是太大了,超过了OpnCV的像素限制大小,所以需要在OpenCV的源码中把限制像素大小的那几个断言注释掉,不然是没法用的。所以,如果想要不出问题地运行python代码,就必须需要从源码编译OpenCV的python库...

然后是C++那部分代码,其实C++的跨平台也不错,只需要有对应平台的动态链接库,然后我们到时候一链接就OK啦。但是,还是一样的问题,直接下载下来的OpenCV链接库会出现超出像素限制的错误,所以还是得从头编译OpenCV库

另外,因为服务器是linux系统,所以如果想要编译出该系统下的库,只需要找一台对应系统的服务器,或者...交叉编译

幸好实验室里有一台linux服务器,只需要...等等,前两天这台服务器跑深度学习给烧了。没事,维修师傅应该很快就能修...等等,现在因为疫情封校,外来人员根本进不来

寄!看来只能老老实实去交叉编译了

0x3 转机----要从坑里出去啦?

这时候我突然想到,之前从Github Student Package里领过DigitalOcean的200美元金额,正好可以开一个服务器,然后当作编译服务器来用。

然后理所当然的就开了一个2C2G的服务器,而且由于服务器本身在墙外,拉github代码、下载依赖啥的都很快。当我配置好CMAKE选项,敲下令人很有安全感的make -j2后,一阵心情愉悦。

但是没过多久,我发现如果服务器的内存不够,opencv没法编译出python的库。但是又懒得换一台再走一套这个流程了,所以就干脆先不编译python的库, 只编译出c++的库。

就这样,总算是勉强弄出了C++的依赖库。然后就是要把这些库链接进我写的C++代码编译成的库中。

至于python,我是这样想的,因为他们既然能生成那种超大张的图像,所以他们的opencv-python肯定是魔改过的,我只要保证我的c++代码这里链接的库不出问题就可以了。

0x4 折磨----重复编译的地狱与初见曙光

由于涉及到在python中调用C++的库函数,关于这个问题,其实我之前没有搞过。我之前只是接触过Cython和一些C扩展的写法,但是C扩展也太难写了,所以后面没有深入。

后面经过一番搜索才知道可以使用ctypes这个包,但是具体怎么用还是不很清楚。考虑到那部分C++代码是以类的方式呈现的,所以我又为它搞了个包装函数(因为我只搜到了ctypes调用函数的方式,不清楚能不能调用类)。

但是调用的时候老是出错,我一度怀疑是搜出来的资料有问题还是我本身代码写的有问题,反复编译了好几次。

最终好不容易才摸清楚正确的调用方式。为了能调用c++库函数,我为这部分又写了一个适配器;为了让接口更加优雅,我又为适配器写了一个包装函数...

但不管怎么说,这一堆代码总算是能正确的跑起来了。

0x5 结束----但是似乎并不令人满意

总算是能够给出一套能用的库了,在服务器上测试了一下,运行的还不错。于是写了个文档和example程序,加上一点注释,把所有默认配置项全部引出组织成文件。接下来,就可以给公司人员测试了。

但是,我忘了我所有编译的都是动态链接库(这确实是我的失误,应该把OpenCV编译成静态库,把我的代码编译成动态库),所以公司他们还需要重头编译...相当于我之前的一些工作都白干了...

而且他们之前还要我测试一下部分结构的改进效果,我还给忘了...

0x6 后记

这次经历还是很有意思的(虽然写出来之后可能没有读出来,这种事还是要经历才能有感知),所以打算记录下来。

顺带一提,阳光电源和我交接工作的还是我们学校的学长,人非常好,之前还打电话问我要不要去他们公司实习,但是考虑到目前刚刚大三,而且这里疫情很重,所以就没去。