管道全景量化机器人(一)

  这是我到新公司做的第一个项目:管道量化机器人。
  之前在成都的一家公司工作,由于工作内容比较清闲,我觉得发展前途不是太大,就来到我比较向往的城市深圳,希望在这里能有良好的发展。
  5月5号是我第一天来到新公司,也是第一天接触这个项目,虽然在此之前我已经了解来到这边需要做什么项目,但那时并没有具体了解做什么,听到部门领导跟我介绍这个项目之后,我的第一感想就是我自己一个人根本不可能做的出来,基本没有任何资料,只有两张海报,上面也没任何实施方案。而且我了解之后发现只有我一个人做这个项目,在没有任何人指导的情况下,又是我自己独立做的第一个项目,因此我觉得我做出来的可能性非常低。毕竟之前在上一家公司做的工作、项目之类的会有人指导,按照同事要求的路线就能完成工作,而且不懂的东西可以问同事,而且之前做的所有工作内容基本都是畸变较小的单目相机、双目相机,测量某些物体的姿态等,并没有使用过鱼眼相机,甚至是了解它,就连它基础的成像模型都不知道,在这种情况下就这样开始了这个项目。
  由于这个项目分为两部分:管道图的展开和全景图拼接。按我现在的理解管道图的展开,主要是把管道的内部图像按照某一条线剖开,形成一张包含所有细节的平面图;好吧,我到现在也不是太清楚第二部分具体做什么。主要是说一下我做第一部分的具体过程。
  第二天从刚上班我就开始在网上找资料,找鱼眼相机全景拼接相关的资料,这一类型的资料还是有点的,在找到相关的包括程序之类的,我还挺高兴的,觉得用不了多久我就能做出来了。在我收集了几天关于这方面的资料后,以及我陆续对这个项目进行了解后,我发现并不是这么简单,最大的区别在于,网上的资料什么的全是左右平移然后拼接,而在这个项目里是鱼眼相机一直往前拍摄,每隔几厘米采集一张图片,然后把相邻两张图片消失的部分找出来进行拼接。而我当时想到的唯一办法就是把鱼眼图像用极坐标的方式展开,然后使用展开后的图像进行拼接,而我当时也是这样操作的,直到后来发现这样实施不行,具体为什么不行看完下段应该就知道了。

  在短暂的看了几天资料后,我在5月9号那天拿到了做管道全景机器人的鱼眼相机,是一个海康威视的相机,真是不管跑去哪只要做视觉的好像都离不开海康威视和大华。当天我主要是做了两件事,第一是在电脑上连接相机拍摄测试图片,了解一下鱼眼图像的特点;第二是了解鱼眼相机的成像模型,在网上一搜索一大堆,但是讲解很详细的基本上没有。由于这两件事以前做过孔型相机好多相似的内容,因此,上手还是挺快的一天就搞定了。下了班晚上回去的时候考虑了一下,无论如何我都得做鱼眼相机标定以得到它的内参和畸变。因此,在5月10号那天早上一去的时候就开始采集鱼眼相机标定的图片,在这里吐槽一下公司的标定板真垃圾是一块玻璃制作的,贼重,挺不好放置的。之后就开始写鱼眼相机标定代码,由于之前写过好多次的单目相机标定和双目相机标定的代码,因此,我能够在原先代码上进行更改,使用之前整好的函数以及OpenCV里面的相关鱼眼标定函数,来完成鱼眼相机标定,仅仅花费了大半天的时间就完成了相关的程序。我直接使用cv::fisheye::initUndistortRectifyMap函数和remap函数测试发现畸变矫正效果挺差的,我觉得我得到的内参和畸变矩阵有误,由于下班了那天也没看出来什么问题,就想着第二天来了再核查哪有问题。这里需要吐槽一下公司电脑,一个什么帷幄数据防泄密的软件,挺扯的,以前的程序在公司电脑上编辑后就不能在我笔记本电脑上打开了,不属于我自己了,还是挺郁闷的,后面由于这个软件还会出现好多的问题。由于之前数据有误,5月11号我一上班就开始看、调试之前程序,一步一步查看,知道看完我都没有发现问题,由于我还是非常肯定我标定的相机参数是有误的,就开始一个函数一个函数进行排查,最终我确定了出现问题的原因在cv::fisheye::calibrate函数,由于我为了省事把原先需要的9个参数就只填了7个剩下的使用默认参数,在这出了问题,因为迭代的方式,迭代的起点、迭代的步长、终止的条件等原因,导致鱼眼相机标定的参数错误(数据看着问题不太大,实际上求出的矫正后的图片变化贼差)。在这里要着重反思一下,以后千万不能因为省事再出现相似的问题,使用OpenCV里面的函数时一定一定把每个参数的含意都搞清楚,以防出现错误。在此,搞定了鱼眼相机标定的程序,得到相机的内参矩阵与畸变矩阵。
  5月12号我就开始着重解决图像拼接的问题,但它并不像我想的那么容易。我在github、csdn、百度等找了许多图像拼接的代码并调试后发现在正常无畸变的孔型模型图片上拼接的效果非常理想,鱼眼相机拍摄的图片却无法拼接。最大的原因是鱼眼图片畸变非常大,就算是使用opencv里的鱼眼图片畸变矫正函数cv::fisheye::undistortImage矫正后,也不能拼接,矫正后的图片人眼看上去还是和孔型相机拍摄的图片不同。看别人博客就算能拼接也是把鱼眼图像边缘部分去掉拼接的,这就和项目中违背了,项目中鱼眼相机是像前移动,和左右平移不同。因此我觉得应该先提取鱼眼图片中的圆形有效区域,先用极坐标展开,然后拼接,找到消失的图像部分,结合移动的距离来拼接图片。于是在5月13号时,我就开始按照这个思路来进行操作了,虽然现在看来这个想法有点幼稚,但那时候了解不深只能按照可行的思路来进行尝试。于是在网上找了一些关于图像极坐标变换的内容,学习了极坐标变换的实现原理和OpenCV中实现极坐标变换的函数cv::warpPolar的源码。当天又推导了一次鱼眼相机的成像模型以及畸变矫正的公式,没想到以后还要推导若干次。随后就是两天的周末,周末还是很愉快的和朋友一块玩耍,丝毫没有收到工作的影响,有点没心没肺,哈哈。在5月16号我把图像的极坐标转换代码搞出来后,并得到鱼眼图像展开图,我观察了许多展开图后,发现图的特点,越靠右边畸变越小,最右边一列像素没有任何畸变后。我终于确定了具体的实施方案(虽然没有成功),先由测试图像(鱼眼图)通过极坐标变换得到展开图,之后用展开图来进行畸变矫正,最后截取右边三分之一的部分进行拼接。但是我用程序实现时没有进行畸变矫正(是因为不知道怎么矫正),只是使用畸变最小的三分之一甚至五分之一进行拼接,结果是没有任何结果,哈哈哈,当时还觉得想法和程序都没有任何问题,但是没有结果,还挺郁闷的,现在想想漏洞百出。当天晚上下了班走路回去的时候,突然有点别的想法,于是在5月17号的时候我就试了一下前一天晚上的想法:先把鱼眼图像用极坐标转换的方式拉开得到的图像,把展开图当成针孔相机拍摄的图像,然后通过设计棋盘格在鱼眼图像中的位置(尽可能的在鱼眼图像边缘)通过拉伸后仿照针孔相机标定的方式来进行畸变矫正。当时觉得这想法真是绝了,由于有之前单目标定的代码,实施起来很简单,但是得到的结果不行,真是想法是好的现实是扯淡的,事实证明还是需要按照之前的想法接着实施,真是浪费了一天。5月18号那天,我就是按照之前的想法,把推导的公式写成代码,最后发现还是不能实现鱼眼相机极坐标转换后的畸变矫正,当时瞬间绝望了,根本不知道该怎么做了,觉得浪费了两周啥没做出来,那时候也不会想到再有几周仍然做不出来的,那天比较绝望,最后重新拍了几组实验图片就没在做什么了。在经过好多天的尝试后,发现之前的思路是错的,没办法没做出来结果只能是错的,于是5月19号开始就只能重新找方案来实施了,总不能放弃,毕竟做不出来就要离职的。开始在知网上找关于鱼眼相机和管道检测的文章,学位论文,唉,还真是小众,找了挺久的,找了几篇文章,而且只有一篇最符合条件的《基于小内径金属管道内壁的裂纹检测系统设计》这篇学位论文,看了这篇后,发现在理想条件下可能实现,根本没法用于工业应用,最大的感触是学术研究和工业应用的区别好大呀,学术研究可以在非常理想的条件下做实验甚至不用做测试,而工业应用会出现各种不能预料的事情。5月20号时,一天都是在看这些论文,《基于小内径金属管道内壁的裂纹检测系统设计-李光耀》、《基于特定角度鱼眼图像校正的设计与实现-肖昆鹏》、《基于内窥镜视频的工业管道图像展开研究-钱渠》、《管道内壁图像检测系统设计-武晓宇》、《基于鱼眼镜头的全景图像展开研究-赵琦》、《基于主动式全景视觉传感器的管道内部缺陷检测方法-吴挺》、《基于主动式全景视觉的管道形变检测及三维重构技术的研究-吴挺》、《一种基于鱼眼图像的全景展开算法-王志刚》。想从这些论文里面找一些想法,虽然他们论文中的条件都比较理想,在工业应用中基本无用,但是还是能吸取一些想法的,发现他们都没有畸变矫正,直接进行展开的,通过计算管道直径和移动距离来确定圆环的大小,随后直接展开进行拼接。看了这些论文我准备先把鱼眼图片投影到半球上,随后使用圆柱投影,进行展开,然后拼接,不确定这样干是否畸变会小很多,但是尽可能的尝试一下吧。5月23号,上午开了一会会,主题一共三点:对外的设备要保证其稳定性;多交流,多讨论,代码上任何改动都要和相关人员交流;时间节点要按时完成,定时间节点要慎重。和我没什么关系相当浪费时间。之后在推导鱼眼相机公式的时候发现,把鱼眼图像往球面上投影的时候,通过鱼眼相机的成像模型,可以把投影畸变给去掉,通过球面的3D点直接往矩形图片上投影(到这才是正确的思路,但是在这天时还不知道这个思路是正确的,主要是投影的矩形的那一步)。流程是:鱼眼图像–>球面模型转换成3D点–>投影到矩形图像中(r,2*CV_PI*r)。觉得这样搞好像可以,那天就写了相应的代码,只是使用牛顿迭代法求一元多次方程的函数那天没完成,其他的基本可以了。经过这么多天真是整的心累,也没看到那一点点的曙光。5月24号,先是把使用牛顿迭代法求一元多次方程的函数完成了,接着推导鱼眼相机成像,矫正,投影的公式,真是每次推导都能发现新的问题,理解太不透彻了,导致我写的程序没有任何结果,挺烦人的。现在想来每次都觉得这次推导的公式没有任何问题,那天看程序时还真是发现大问题了,发现在赋值的方面的主要问题是输入的cv::Size和输出的cv::Size不同,导致赋值出错。当时觉得真是好难呀,没有一点可以实操的资料查询,全靠想象,进度进展真是缓慢(就没有任何进展),但是那时候心境还是可以的,没有到最绝望的时候。5月25号时,上午写程序的时候发现结果不对,但是不知道哪里不对,因此写了一个反推回去的程序,发现结果不能形成闭环,查看公式也没发现什么问题,程序好像也都没什么问题,这就很郁闷了看了一上午还没发现任何的问题。下午的时候在把程序直接改成畸变矫正的程序发现有问题,之前明明能够畸变矫正的程序,变得不行了,最后发现图像通道不对。在重复看程序的过程中发现是先定义一张无畸变的空白图像,任何一个像素一个像素的进行畸变,找到空白图像的像素映射到畸变图像上的坐标,然后通过已知的畸变图像像素的值来赋值于无畸变的图像。那天最大的收获就是搞明白了程序中是通过无畸变的空白图像,通过畸变变换来找到畸变图像上的对应点,随后插值。因此,想得到无畸变的展开图就需要假设已知空白展开图,映射到球面上,通过球面上的3D坐标和畸变模型得到畸变图像上的坐标,然后赋值。相当的开心,觉得成功在望。5月26号就开始把昨天的想法变成代码,但是最后整了一天没整出结果,心情像过山车一样。5月27号在看csdn时忽然发现,世界地图的展开方式和我需要得到的图好像很相似,越接近底部畸变越小,而鱼眼相机的展开图也是如此,瞬间就有点开心了,在网上查了一下发现世界地图的展开方式是墨卡托投影,我觉得我也能试试墨卡托投影,因此下午的时候就开始做墨卡托投影,整了一下午发现可能是因为代码有问题没有得到想要的结果,由于那天是周五就没有专心的做。5月30号,调试了一天的代码,出来图了,但是图像在某一列一直循环的,和想象中的相差很大的,查看代码到底哪里出现问题,最后发现好像是墨卡托投影的代码好像出现了问题,代码的结果和自己计算的结果不一样。由于当时快下班了,也挺心烦的,就没继续搞了,而工作进度一如既往的没有啥进度,就不想形容当时的心情了。5月31号,今天调试程序发现一个大问题,程序中的三角函数弧度制的,之前一直以为只有OpenCV才是的,没想到C里面也是弧度制的,最终能够得到展开图了。那时候真的相当开心终于有进展了(唉,还是太年轻了),觉得第二天把图像拼出来,做能出来了,成功了。6月1号,儿童节快乐!哈哈哈。今天一天也没做什么,就是试了一下鱼眼图像到展开图,正着计算,倒着计算得出的展开图的区别,以及使用墨卡托投影与不使用墨卡托投影等等,一系列的区别。主要是根据鱼眼图像像素一个点一个点的重建得到自己想要的图像。真是把鱼眼相机的模型给搞得相当的透彻,太扯了,这要是再拼不到一起就真的无语了。6月6号,成果显著,能够把图像拼接起来了,通过使用的是墨卡托投影来实施的,虽然不知道鱼眼相机正确的压缩比例,但是墨卡托投影的拉伸比例好像和鱼眼相机的压缩比例非常类似,因此能够拼接起来,实际上和我想法好像是有区别的,原本的想法是已知矫正后的图像,通过墨卡托反向投影到球面,已知球面3D点和鱼眼相机模型来找到畸变后的鱼眼图像。但是公式推导通了,但是程序好像不知道哪里出现了问题没有搞通,但是还是非常开心的竟然能够拼接起来了。当时觉得成功了,公式和实施方法都准备要在完全完成后再写,心情都很好了。6月7号,上午的时候还很开心,积极的采集实验图片用于测试,下午的时候就乐极生悲了,在使用程序拼接时得到的效果和我想象中的不同。瞬间觉得心好累,觉得快麻木了,事事不顺心,不管是工作上还是生活上,连工作日志都觉得无趣不想写了。而且觉得最近一个多月来有点堕落了,下了班书没看过几页,什么都没搞出来,心情贼郁闷,当天还是高考的日子,八年前的今天我也在奋斗,八年前我肯定没想到今天的生活是这么的扯淡,唉,烦躁。那天真的挺烦躁的,还好我心情调整的还算可以的在6月8号时就已经觉得没有什么了,那天我重新调整了像素重建的程序,并且实施成功了,我觉得我当天的想法真是可以的。我发现我拍摄的图像是管道投影的到球面,球面经过鱼眼畸变模型投影到鱼眼图像上的,而我只需要反向操作,由鱼眼图像得到球面的3D坐标,再有球面投影到圆柱面上,就能得到展开图,而且是无畸变的图像。这样一来得到的展开图就是完美且没有任何畸变的图,这样拼接就能成功了。这样就得到了单个展开图,在拼接的时候我直接使用opencv自带的拼接函数switch,就是得到的拼接结果图是有问题的,死在了最后一步。因此,在6月9号的时候我重新考虑了拼接方案,我觉得可以用特征匹配的方式计算出第i张图和第i+1张图相差了m个像素,然后从第i张图上截取m行图像直接拼接到i+1张图像上,我个人觉得这种方法很可以,因此,那天主要的工作就是实现这个想法,虽然最后结果不理想有明显的拼接缝隙,但是我觉得我的思路应该没有什么问题。6月10号时,我通过自适应融合的方式,在得到两幅图重合的距离后,通过前后增加50个像素后,而且使用自适应阈值的方式把拼接缝减弱了,最终得到了效果图,那一刻真的是觉得太开心了,耗时36天终于成功了。
  写到这里终于把可以实施的方案搞定了,而且成功了,剩下的就只是组合程序、优化程序这些简单的问题。6月13号刚上班我就发现不知道什么原因百度网盘、福昕Pdf阅读器等软件打不开了,卸载重新安装后发现还是不行,最后升级了一下系统,发现是系统的问题,好在最后能够整好了。下午主要是把实现成功的程序组合起来,因为,之前程序是分步骤分段来写了,组合起来还真是不容易。6月14号时我把程序合并组装起来后,发现运算速度极慢,不能达到实时,因此在下午的时候计算了一下运行时间看看哪里能够加速,发现主要是两部分耗时,图像展开的时候需要for循环600w次,拼接的时候也是for循环600w,因此相当耗时,特别是图像展开耗费了将近90%的时间,release模式下要将近4s。图像展开时可以使用映射表的形式来展开,这样就不需要每一张图片都使用for循环计算了。而拼接图像时,是分成3部分来拼接的,第一部分和第三部分可以直接整块的拼接,只有拼接缝的时候使用for循环单个像素进行计算,因此可以节约大量的时间。或许还有其它地方可以优化,慢慢的试试吧。6月15号时主要做了两部分工作,1、优化程序的运行速度;2、拍摄实验图片。展开图优化时主要是通过创建映射表,只在第一张图像初始化的时候生成映射表,之后展开图可以只用映射表来计算展开图,直接把图像展开时间缩短到0.0几秒。拼接时可以把上下两部分整块复制,中部用循环,这样就极大的缩短了时间。最终的结果是:程序的运行速度已经优化到0.2s左右,现在主要是提取特征点比较耗时,大概0.17s-0.18s,应该没有什么优化的空间了。
  至此,这个项目的管道展开图完成了,其它的就只是实际的管道中测试,发现问题时再进行更改,其中最大的更改就是在于特征的更改,以及特征匹配的方式,因为,它关乎我拼接的结果,最好的是使用ORB特征和RANSAC匹配算法结合,兼顾速度和准确率。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值