机器学习 + 浏览器插件 = 东半球最好用的二维(条形)码识别器

1,056 阅读7分钟

“ 老罗:这应该是东半球最好用的识别二维(条形)码的浏览器插件!(ALMOST 梅开二度) ”

一、它是什么!

只需要轻轻的点一下,它就会识别你当前Tab里的所有二维(条形)码,识别结束后还会贴心的自动回显到对应的位置上 !(以下gif图经过压缩,颜色不对劲,忽略它哈)

finally.png

除了以上自动识别外,也补齐了同行 ”可能“ 有的 “右键一键识别” 的功能,来覆盖识别不成功的场景:

right.png

二、怎么获取呢?

安装教程:www.cnplugins.com/zhuanti/new…

三、听听实现它的心路历程吧(有点坎坷)

下面简单记录了一周多的时间,心情上的大悲大喜,也涉及一些优化方案思路,是如何一步一步优化到最终效果的,大家可以酌情食用~

1、第一行想法

自己装过很多识别二维码的插件,发现都不如想象中的好用(有的甚至傻乎乎的)😶,工作之余想象了一下我想要的功能究竟是什么样的?怎么设计才是更好用的?

带着以上问题,在一个周三的晚上,我默默地打开了小笔记,记录下了第一行想法:

image.png

“自动”?嗯... 想象起来挺简单,好像是:先这样,再这样,就好了...

不过浏览器可不是一个聪明人,它没有意识,又怎么知道当前页面中的二维码在哪里呢?不对... 它又怎么知道什么是二维码呢?

image.png

2、知识是有价的

我们小学二年级就学过,四周有三个大方块儿、中间都是像素点的一个方形的码就是二维码,不过计算机可不知道,它所看到的就是一个一个像素点,所以,如何让它知道什么是二维码,是摆在眼前的第一个问题。

让计算机掌握这门认识二维码的能力,就需要让它不断去学习,这就是高大上且酷酷的 “ 机器学习 ”。

可是... 大学本科毕业后我就从事了前端岗位,对机器学习相关概念了解的少之又少,em... 应该是完全不了解,只听过一两个名词:神经、训练...

不懂怕什么,不懂就去学好了😀,打开梦工厂网站,惊奇的发现真的有相关课程,有点小贵不过也还好,买它!

image.png

3、不懂就问

经过一晚上的学习,有了简单的知识基础后,带着相关问题,请教了正在读研的同学,得到了一个大致准确的方向:“目标检测”。

image.png

4、成功识别,人生里程碑!

有了大致的方向,就有了不少动力!

周六日两天,放弃了睡懒觉、午休、发呆、看电视🙂,经历了无数次的调参、崩溃、转化、买会员后,终于成功识别出了人生第一张图片:

image.png

这是一个好的开始!

5、略显枯燥的准备阶段

接着我尝试去各种寻找已有的分好类的二维码的训练集,可惜没有找到比较合适的...

em... 没有合适的怎么办?只能自己造了!一张一张图进行截图保存,并进行标注、分类、归集,眼都花了...

image.png

最终成功得到标注后的资源集标签,密密麻麻...

image.png

这时我才意识到训练模型不是一件容易的事(后知后觉),有一个门槛就是... 你需要有一台有比较不错GPU的电脑,看着我的笔记本我又陷入了沉思...

image.png

6、柳暗花明第一村

运气真好,找了不久就发现了谷歌提供一个平台:Colaboratory ,该平台提供python环境,并且...提供免费的GPU,你可以在这里愉快的训练你的模型啦!

image.png

经过不断的失败...报错...修复后,终于开始训练了!

image.png

老父亲流下了一行热泪... 看着正确率的不断提升,心里还是非常高兴的,仿佛自己的好大儿开始慢慢懂事了...

image.png

训练结束后,经过转化、优化、更换模型、导出等操作后,最终得到了满意的权重文件,终于可以在浏览器里识别二维码了!

image.png

先写个demo测试一下!

demo.png

7、晴天大霹雳

兴冲冲的搞好浏览器插件,加载权重文件后,发现了一个晴天大霹雳!

tfModel.executeAsync(input)是一个异步方法,在加载权重预热的时候,会使UI页面卡死!

google了一番后,发现无解,由于webgl的问题(没有深究,看其他人的解释是这样),所以一定会阻塞当前线程。

image.png

最终的现象就是打开插件,页面会卡死5-6s,然后在1-2s内可以渲染出来结果,总耗时在8s左右,体验非常不好。

这结果让我很失望,差点放弃...

8、柳暗花明第二村

吃个午饭冷静下来后想了一下优化方案,发现可以尝试使用web worker嘛,既然一定会阻塞主线程,那么我就在其他的线程里去做这个加载权重的操作,不就不会卡死页面了嘛!

大刀阔斧重构了代码,因为web worker和主线程之间的通讯不可以传递不可序列化对象,只能传递可被序列化的数据,就导致需要在两边进行图片数据的转换,适配代码写了一大堆...

最终优化后,效果如下,可以发现,在loading过程中按钮也可以点击,证明主线程没有被卡死:

slow.png

不过聪明的你也发现了,加载权重花费的时间有些长,不,简直是太长了,而且这个插件的定位是一个一次性的工具,几乎不会存在只打开(加载)一次,识别多次的情况,所以怎么减少这个首次加载(预热)时间,是比较头疼的问题...

9、柳暗花明第三村

后来在周四的午休时间,正在梦中,忽然惊醒发现可以在background.js中做加载啊!而且有两点好处:

  • 1、天然的其他线程,不影响主线程
  • 2、background.js在安装插件的一瞬间就会执行,这个时候就去预热模型,后面都使用该预热后的模型对象去识别图片的,时间就会大大减少!粗略计算了一下,每次打开插件到识别完毕,时间大部分都在1s内,极少数会在2-3s,完全符合预期!

优化之后的效果大致如下:

finally.png

可以看到,速度是非常的快了,终于符合了心里预期(一个随用随取的插件场景)。

10、Happy Ending

至此,从构思插件到其落地实现,大致经过了一周多的时间,期间不止有以上记录的试错流程,经过其他同学的提醒,还添加了一键复制按钮、条形码支持、右键菜单一键识别,还尝试使用electron来实现了桌面端的开发,使其识别功能不局限在浏览器里,最终因为打包体积过于庞大(100MB+),不符合自己的预期(10MB以内),就忍痛放弃掉了。

😌 过程比最初开始计划做的时候预想的要痛苦得多,踩的坑实在是太多了,不堪回首,如果最初知道要踩那么多坑,可能当时就放弃了

不过好在最后的效果还是不错的,比较符合期望,也是蛮开心的!😎

四、结束才是真正的开始

因为只使用了250张图片来训练识别模型,可能部分场景识别不到,还请大家谅解,给它一个慢慢进步的空间~

OK!回到文章开头,这应该是东半球最好用的识别二维(条形)码的浏览器插件!😉 装上试试看!