一维条形码应用广泛,本文选择最具代表性的EAN-13条形码,它采用互相平行、不同宽窄的59个黑白条纹构成,可以解码为数字0~9。条形码的识别功能实现过程如下图所示,一共分为7个过程,分别为:灰度转换、边沿检测、图像分条、角度计算、条形码定位、条形码识别和校验。

      参考代码示例: https://github.com/BluesYu/MarStech_Vision_Sensor/tree/master/bar_mode

具体的实现原理如下图所示:

一、条形码识别算法

条形码识别主要有三种方法,分别为宽度测量法,平均值法和相似边距离的测量方法,其中,用相似边距离算法进行识别。相似边距离的优点是,即使有噪音干扰,导致上一步计算的条和空宽度不准确,也不影响正确的识别。

其中C1,C2,C3,C4分别为相应的条形码条和白色空格的宽度,有如下关系:

由于条形码的起始符每个黑条和白色空白代表一个条形码模块的宽度,黑条的宽有N个模块则表示二进制数中N个数值1,白色空表示有N个数值0,对应的前置符不进行编码,一共是7个模块宽度。同时,左侧的数据字符可以分为偶编码与奇编码,右侧的数据字符仅有偶编码。

字符数据

左侧字符数据

右侧字符数据

奇编码

偶编码

偶编码

0

0001101(53)

0100111(23)

1110010(53)

1

0011001(44)

0011001(44)

1100110(44)

2

0010011(33)

0010011(33)

0010011(33)

3

0111101(55)

0100001(25)

0100001(25)

4

0100011(24)

0011101(54)

1011100(24)

5

0110001(35)

0111001(45)

1001110(35)

6

0101111(22)

0000101(52)

1010000(22)

7

0111011(44)

0010001(34)

1000100(44)

8

0110111(33)

0001001(43)

1001000(33)

9

0001011(42)

0001011(42)

0001011(42)

上述计算得到的t数值与实际字符数据不是一一对应,例如,数字1和7对应左侧奇编码数值都为44,数字2和8对应左侧奇编码数值都为33。此时,需要进一步的判断,根据表3.3中数字1和7对应的左侧奇编码分别为0011001和0111011,即数字1的C1+C3>C2+C4    ,数字7的C1+C3<C2+C4   ,同理可以区分出数字2和8.

二,条形码识别实现

代码函数主要有:

(1) 获取参数:

/******************************************************************************************************
* 函数(Function):get_bar_num(Mat &srcImg, string &result)
* 功能(Description): 获取参数
* 调用函数(Calls):cvtColor()、threshold()、bitwise_not()、expand_dis_binary_image()、get_bar_contours()、get_bar()、getDigitsEAN13()、parseEAN13()
* 输入参数(parameter):Mat &srcImg:输入图像(反转后的二值图像)string &result:输出结果
* 返回数值(return):     return="ERROR":错误return=result :条形码数据
* 其他(Others):     bar_rate可以调节,代表取值的参数,每张图一共扫描5次。
********************************************************************************************************/
string get_bar_num(Mat &srcImg, string &result);

(2)将目标图像扩大,检测区域:

/******************************************************************************************************
* 函数(Function):expand_dis_binary_image(Mat &srcImg, Mat &dstImg)
* 功能(Description): 将目标图像扩大,检测区域
* 调用函数(Calls):erode()、dilate()
* 输入参数(parameter):Mat &srcImg:输入图像(反转后的二值图像)Mat &dstImg:输出图像
* 返回数值(return):     无
* 其他(Others):      可以修改模板,形态学模板越大计算越多。
********************************************************************************************************/
void expand_dis_binary_image(Mat &srcImg, Mat &dstImg);

    (3)获取区域:

/******************************************************************************************************
* 函数(Function):get_bar_contours(Mat &mat_temp, vector<vector<Point2f>>  &vertices)
* 功能(Description): 将目标图像扩大,检测区域
* 调用函数(Calls):findContours()、contourArea()
* 输入参数(parameter):Mat &mat_temp:输入图像(反转后的二值图像)vector<Point2f>  &vertices):输出旋转矩形参数点
* 返回数值(return):     返回0:无轮廓返回4:代表4个点
* 其他(Others):
********************************************************************************************************/
int get_bar_contours(Mat &mat_temp, vector<Point2f>  &vertices) ;

    (4)获取矩形代码(0或者1)

/******************************************************************************************************
* 函数(Function):getDigitsEAN13(IplImage* source, int lineHight)
* 功能(Description): 获取矩形代码(0或者1)
* 调用函数(Calls):getBaseAndStart()、cvGet2D()、getNumOfPixel()
* 输入参数(parameter):IplImage* source:输入图像(灰度图)int lineHight:获取的Y轴图像
* 返回数值(return):     return="ERROR":失败return=code(0、1代码):成功
* 其他(Others):          调整参数lineHight
********************************************************************************************************/
string getDigitsEAN13(IplImage* source, int lineHight);

(5)统计相同类型(条/空白)的像素的个数

/******************************************************************************************************
* 函数(Function): getNumOfPixel(IplImage* source, int lineHight, int threshold, int* index)
* 功能(Description): 统计相同类型(条/空白)的像素的个数
* 调用函数(Calls):
* 输入参数(parameter):IplImage* source:输入图像(灰度图)int lineHight:获取的Y轴图像int threshold:二值化阈值int* index:起始点(x轴)
* 返回数值(return):     return="ERROR1":失败
return=code(0、1代码):成功
* 其他(Others):          调整参数lineHight
********************************************************************************************************/
int getNumOfPixel(IplImage* source, int lineHight, int threshold, int* index) ;

   (6)获取条形码起始的位置和宽度

/******************************************************************************************************
* 函数(Function): getBaseAndStart(IplImage* source, int lineHight, int threshold, int* base, int* start)
* 功能(Description):获取条形码起始的位置和宽度
* 调用函数(Calls):cvGet2D()
* 输入参数(parameter):IplImage* source:输入图像(灰度图)int lineHight:获取的Y轴图像int threshold:二值化阈值int* base:基础宽度int* start:起始的位置
* 返回数值(return):     return=-2:失败return=-1:失败return= 0:成功,返回参数
* 其他(Others):          判断宽度的算法还可以改进
********************************************************************************************************/
int getBaseAndStart(IplImage* source, int lineHight, int threshold, int* base, int* start) ;

 (7) 获取目标图像

/******************************************************************************************************
* 函数(Function):get_bar(Mat &gray, vector<Point2f>  &vertices,Mat &final_result,const int &add_pixel)
* 功能(Description): 获取目标图像
* 调用函数(Calls):temp_expand()、warpAffine()
* 输入参数(parameter):Mat &gray:输入灰度图像(二值图像也可)
vector<Point2f>  &vertices:输入矩形点
Mat &final_result:输出的目标图像
const int &add_pixel:扩张图像(用于旋转)
* 返回数值(return):     return=-1:失败,无图像return= 4:正常
* 其他(Others):          add_pixel参数可以修改,根据图像进行调整。
********************************************************************************************************/
int get_bar(Mat &gray, vector<Point2f>  &vertices, Mat &final_result, const int &add_pixel);

(8)解析EAN13的间接code

/******************************************************************************************************
* 函数(Function): parseEAN13(string code)
* 功能(Description):解析EAN13的间接code
* 调用函数(Calls):
* 输入参数(parameter):string code:根据得到的参数,进行解析
* 返回数值(return):     return=code(数字):成功return= "ERROR1":参数范围错误return= "ERROR2":参数解析错误return= "ERROR3":第一个参数解析错误return= "ERROR4":校验失败
* 其他(Others):          基本参数不需要修改
********************************************************************************************************/
string parseEAN13(string code) ;

三,使用代码

主要代码为bar_mode.cpp和bar_mode.h ,测试代码为 bar_mode_test.cpp,使用注意事项为:

1,需要使用摄像头;

2,采集图像信息,通过串口发送;

3,依赖简易的opencv库函数,需要白平衡算法;

4,需要调节摄像头焦距:10cm左右,效果较好;

5, 测试函数编译命令为:g++ bar_mode_test.cpp bar_mode.cpp uart_io/uart_io.cpp -o bar_mode_test -lopencv_core -lopencv_highgui -lopencv_imgproc -lpthread -std=c++11

使用代码

string result = "";       //参数解析
if (get_bar_num(frame, result) != "ERROR")

具体视觉传感器测试、购买可以咨询:火星人俱乐部官网(https://www.imarsclub.com/web/index),电话或邮件联系即可。传感器已经申请专利,商业使用需要授权。

火星人视觉传感器是一个开放平台,相关电路版图、代码对外开放,可以自行下载,代码地址:https://github.com/BluesYu/MarStech_Vision_Sensor,欢迎star和fork,有问题可以再github上交流。

本项目为开源项目,不以盈利为目的,开源社区需要大家一起努力,欢迎大家一起来开发!

嵌入式AI设备--火星人视觉传感器--条形码识别功能相关推荐

  1. 工业机器人工具中心点标定的意义_新品发布 | 倍加福新推VOS智能视觉传感器,为机器人添一双“慧眼”...

    作为工业传感器领域的创新先驱者,倍加福始终致力于科技创新,为用户带来更为完善的产品线及更具优势的解决方案.此次,倍加福全新推出VOS智能视觉传感器,此类高度集成化的微小型机器视觉系统,将图像的采集.处 ...

  2. 施努卡:机器人视觉传感器原理(视觉传感器公司)

    视觉传感器是整个机器视觉系统信息的直接来源,主要由一个或者两个图形传感器组成,有时还要配以光投射器及其他辅助设备.视觉传感器的主要功能是获取足够的机器视觉系统要处理的最原始图像. 视觉传感是应用在生产 ...

  3. Azure认知服务之使用墨迹识别功能识别手写汉字

    前面我们使用Azure Face实现了人脸识别.使用Azure表格识别器提取了表格里的数据.这次我们试试使用Azure墨迹识别API来对笔迹进行识别. 墨迹识别 墨迹识别器认知服务提供基于云的 RES ...

  4. 【嵌入式AI周报20210430期】Xilinx推出K26视觉AI核心板、黑芝麻智能发布196TOPS华山A1000

    导读:本期为 AI 简报 20210430期,文章架构已经调整,侧重 AI 嵌入式方向,请慢慢食用~ 祝大家节日快乐- 本文一共 3700 字,通篇阅读结束需要 10~15 分钟 RT-AK 进展 R ...

  5. 【20201231期AI简报】视觉系统的革新:嵌入式AI摄像头!还有跨年特别活动等你来哦...

    导读:本期为 AI 简报 20201231 期,将为您带来 9 条相关新闻,本年度最后一期,祝大家元旦快乐~ 2020年8月18我们第一次在公众号上连载了[AI简报],到现在将近半年时间了,也逐渐摸索 ...

  6. AI视觉传感器作用和应用介绍

    二哈识图(HuskyLens)是DFRobot新推出的一款简单易用的人工智能视觉传感器,内置6种功能:人脸识别.物体追踪.物体识别.巡线追踪.颜色识别.标签识别.仅需一个按键即可完成AI训练,摆脱繁琐 ...

  7. 一种利用NeuCube和动态视觉传感器对运动目标进行精确识别的视觉脉冲神经网络系统(译)

    原文题目为: A Retinotopic Spiking Neural Network System for Accurate of Moving Objects Using NeuCube and ...

  8. 嵌入式AI实践--基于RT-PI识别“石头剪刀布”

    嵌入式AI实践–基于RT-PI识别"石头剪刀布" 文章目录 嵌入式AI实践--基于RT-PI识别"石头剪刀布" 背景和实践目标 结果展示 软硬件介绍 RT-Pi ...

  9. AI边缘计算(嵌入式AI)硬件信息汇总

    目录 需求 方案评估 intel Mobileye 公司 EyeQ系列 Movidius 公司 Movidius Myriad 2 VPU Movidius Myriad X VPU Intel® N ...

最新文章

  1. P2801 教主的魔法(分块入门)
  2. MooseFS使用问题分析总结
  3. 新风系统风速推荐表_家用新风常用管道规格和对应风量推荐值
  4. Oracle86和92语法的连接,子查询,集合的操作
  5. 数据结构那些事(二)
  6. 前端如何提示自己的技术水平
  7. python-迭代器实现异步(在串行中)
  8. BW报表igs服务配置解决中文显示问题
  9. rds对mysql优化_RDS MySQL优化方案
  10. kuangbin专题五并查集总结
  11. 查询任意汉字的Unicode编码,UTF8编码,GB2312编码,GBK编码
  12. 简指南越狱的iOS及原因,负责其
  13. 数学建模之SPSS应用——聚类分析
  14. 文档大小超出上传限制怎么办_有道翻译和翻译狗,哪个更适合翻译文档?
  15. Android之基于百度云推送IM
  16. Linux解决txt文件乱码问题
  17. Python 中的 defaultdict 数据类型
  18. cmmi3级包含的过程域
  19. 千锋学习day09面向对象
  20. 移动硬盘插在电脑上提示需要将其格式化,我该怎么办?

热门文章

  1. 伯恩斯新情绪疗法--克服无价值感
  2. 如何在win10系统上安装使用vc6.0
  3. Windows10关机问题----只有“睡眠”、“更新并重启”、“更新并关机”,但是又不想更新,解决办法...
  4. 底包和基带是什么?刷机前有必要先刷它们吗?
  5. SSM三大框架整合原理及步骤
  6. 小程序发布体验版流程
  7. 滑模控制二阶系统实例(5mins理解入门,附带MATLAB实现)
  8. handler.ashx文件的作用详解
  9. 输出图片python
  10. 封印之门 蓝桥杯模拟赛(一)