智能锁IMEI图片识别
 2019-03-06 09:06:39   223   0   

本文最后更新于天前,文中介绍内容及环境可能已不适用.请谨慎参考.

公司最近来了一批智能锁产品~,

使用NB-IOT移动物联平台接入,我方负责锁产品的后台统一管理,包括控制智能锁密码下发等。

 

概要

这里需要给锁安装人员提供一个快捷的录入锁IMEI 编号的功能,

鉴于之前调研过图片识别相关的东西,这里顺便做了个锁IMEi图片的识别测试。

锁如下:

 

 

识别

输入

需要识别的

就是锁上贴着的白色小纸片,需要识别出拍摄图片上的IMEI码。

如果客户端通过各种手段能直接截取到方形图片的画,识别就是草鸡简单,没什么难度了,当然这个也是后续的真正方案了~

 

这里我自己扩展了下,也算又练了一把手,

直接识别随便手机拍摄的如上图片,包含高光点、杂乱背景、歪着拍的, 可能还有90度或者180度拍摄等情况。

综合处理了下,最后结果基本还行,不过总的来说最好还是固定样式的好

 

基本正常拍摄的图片.

 

歪着拍的图片

处理时,判断分析出的边界矩形长宽,进行旋转操作。

这里只简单处理了接近90度的图片

所以,这里如果要能处理全部的图像,可能还需要对偏移角度更进一步分析。

光照不均匀图片

又有光照又有背景的图片

,这个识别好像还有点问题,不过可以综合其他方法处理,比如数字前缀等.

或者多做几次边界处理,先一步截取最外层背景。

这里可以看出来,图片识别还是要对输入的图片有一个统一标准,不然识别的难度那是无限增加~

不知道那些搞机器人,自动汽车啥的,是咋搞的,真心应该很复杂。

实现

下面说下实现思路,

其实也没啥,定位白色贴条区域,截取,识别。

那么问题来了,怎么定位白色贴条区域?

定位

针对此特定问题,我们可以看到整个图片基本上都是深色居多,白色贴条部位除外。

 

那么如果我们对图片作水平方向的灰度投影计算,即将整张图片上每一行的灰度像素值水平累计,生成出一张图像,

也就是上面结果中的各个图上右下角那个图形,人眼可以非常明显的看出贴纸的那一块的上下边界。

灰度像素值基本比较平滑,比最大值少一半左右,

这个就是关键了。

 

 

算法

算法目标已经基本很明确了,计算出上述直方图中,比较平滑的一段数据的起始y和结束y.

再抽象一点,就是给定一组数据

([0,a0],[1,a1],[2,a2].....[ x,ax])  , 数组数量>1800。 

找出其中一段连续数据,记录起始x1,x2. 其中x1-x2的所有对应a值都应该小于最大a值的一半,

并且x1-x2连续波动幅度不大的,即相连两个a值差别不应太大,假定不大于35(灰度像素)同时x2-x1的最小长度有要求,最低x2-x1>200。

即最少要有连续200个点,同时改连续段落位于给定数据中间(不会在接近头部或者尾部)

crying

自己都被自己说糊涂了。。就酱吧。

 

 

实现这个算法搞了快一天,果然现在写程序都是机械化的,真正用到算法的地方不多呢,

随便搞点这种算法,脑袋就不好使了(。・`ω´・)

 

我这里的实现步骤:

得到y投影

循环y,假设当前为段落起点.记录 起始相关值startj, startv。

  继续循环,对比前后两个值,及当前值与段落起始值 startv 差距。是否满足,

  满足: 记录连续次数times,  继续,

  否:是否满足最小连续次数times, 

      是:找到一段,记录值

      否:从新重新计算相关值startj, startv,继续循环.

 

这样用文字写一遍下来,好像思路更清晰了,果然有些东西还是要写写。

代码实现如下:

		Double max = 0D;
		// 单纯计算y投影
		Mat hist = canyStepOne(input, output, max);

		for (int j = 0; j < imgheight; j++) {
			double num = hist.get(0, j)[0];
			if (max < num)
				max = num;
		}

		// 计算纵向区域
		List<Rect> rects = new ArrayList<>();
		boolean isstart = false;

		double start_val1 = 0;// 前一个y值
		double start_val2 = 0;// 后一个y值
		int startj = 0; // 确定一行开始的y值
		double startv = 0;// 开始行的值

		int times = 0;
		int maxtimes = 5;// 像素值突然增大为区域开始
		boolean isend = false;
		for (int j = 0; j < imgheight; j++) {
			double num = hist.get(0, j)[0];

			start_val1 = start_val2;
			start_val2 = num;

			if (!isstart) {

				// 假设开始
				// 找到开始 ,剔除开头/结尾,图片位于图像当中
				if (j > 100 && j < imgheight - 100 && start_val1 / start_val2 > 1 && start_val2 < max * 2 / 3) {

					isstart = true;
					startj = j;
					startv = num;
					Rect r = new Rect(0, j, imgwidth, 0);

					rects.add(r);
				}

			} else {

				if (Math.abs(startv - start_val2) < 35)
					times++;// 前后相差不多,计数
				else {

					// 差距开始变大
					// 满足连续一段/同时 数字开始增大
					if (times > 100 && start_val2 > start_val1) {
						isend = true;

						isstart = false;
						isend = false;
						start_val1 = 0;

						// 更新当前找到的行
						Rect r = rects.get(rects.size() - 1);
						r.height = j - startj;
						rects.remove(rects.size() - 1);
						rects.add(r);

						times = 0;// 归0

					} else {

						// 重新开始计算
						isstart = false;
						times = 0;// 相差过大,重新开始

						// 移除之前的添加的不满足的区域.
						Rect r = rects.get(rects.size() - 1);
						if (r.height < 50)
							rects.remove(rects.size() - 1);

					}

				}

			}

		}

   

 

github:

https://github.com/kxjl168/opencv2/tree/master/opencvTest

 

有兴趣欢迎围观~(= ̄ω ̄=)

         

 


 2019-09-19 06:52:15 
 0

  本文基于CC BY-NC-ND 4.0 许可协议发布,作者:野生的喵喵 固定链接: 【智能锁IMEI图片识别】 转载请注明



发表新的评论
{{s_uid}}   , 欢迎回来.
您的称呼(*必填):
您的邮箱地址(*必填,您的邮箱地址不会公开,仅作为有回复后的消息通知手段):
您的站点地址(选填):
留言:

∑( ° △ °|||)︴

(๑•̀ㅂ•́)و✧
<( ̄) ̄)>
[]~( ̄▽ ̄)~*
( ̄ˇ ̄)
[]~( ̄▽ ̄)~*
( ̄ˇ ̄)
╮( ̄▽ ̄)╭
( ̄ε(# ̄)
(⊙ˍ⊙)
( ̄▽ ̄)~*
∑( ° △ °|||)︴

文章分类

可能喜欢 

KxのBook@Copyright 2017- All Rights Reserved
Designed and themed by 野生的喵喵   1344759   38295